1 # SPDX-License-Identifier: GPL-2.0-or-later
2 # Copyright 2009-2010 Michel J. Anders (varkenvarken)
5 from bpy
.types
import Operator
11 from bpy
.props
import (
18 from mathutils
import (
22 from bpy_extras
import object_utils
24 # A very simple "bridge" tool.
25 # Connects two equally long vertex rows with faces.
26 # Returns a list of the new faces (list of lists)
28 # vertIdx1 ... First vertex list (list of vertex indices)
29 # vertIdx2 ... Second vertex list (list of vertex indices)
30 # closed ... Creates a loop (first & last are closed)
31 # flipped ... Invert the normal of the face(s)
33 # Note: You can set vertIdx1 to a single vertex index to create
35 # Note: If both vertex idx list are the same length they have
36 # to have at least 2 vertices
38 def createFaces(vertIdx1
, vertIdx2
, closed
=False, flipped
=False):
41 if not vertIdx1
or not vertIdx2
:
44 if len(vertIdx1
) < 2 and len(vertIdx2
) < 2:
48 if (len(vertIdx1
) != len(vertIdx2
)):
49 if (len(vertIdx1
) == 1 and len(vertIdx2
) > 1):
57 # Bridge the start with the end.
64 face
.append(vertIdx1
[total
- 1])
68 face
= [vertIdx2
[0], vertIdx1
[0]]
70 face
.append(vertIdx1
[total
- 1])
71 face
.append(vertIdx2
[total
- 1])
74 # Bridge the rest of the faces.
75 for num
in range(total
- 1):
78 face
= [vertIdx2
[num
], vertIdx1
[0], vertIdx2
[num
+ 1]]
80 face
= [vertIdx2
[num
], vertIdx1
[num
],
81 vertIdx1
[num
+ 1], vertIdx2
[num
+ 1]]
85 face
= [vertIdx1
[0], vertIdx2
[num
], vertIdx2
[num
+ 1]]
87 face
= [vertIdx1
[num
], vertIdx2
[num
],
88 vertIdx2
[num
+ 1], vertIdx1
[num
+ 1]]
94 # Calculate the vertex coordinates for a single
95 # section of a gear tooth.
96 # Returns 4 lists of vertex coords (list of tuples):
97 # *-*---*---* (1.) verts_inner_base
99 # *-*---*---* (2.) verts_outer_base
101 # *---*---* (3.) verts_middle_tooth
103 # *-*-* (4.) verts_tip_tooth
116 def add_tooth(a
, t
, d
, radius
, Ad
, De
, base
, p_angle
, rack
=0, crown
=0.0):
117 A
= [a
, a
+ t
/ 4, a
+ t
/ 2, a
+ 3 * t
/ 4]
118 C
= [cos(i
) for i
in A
]
119 S
= [sin(i
) for i
in A
]
125 # Pressure angle calc
126 O
= Ad
* tan(p_angle
)
128 p_angle
= atan(O
/ Ra
)
136 S
= [sin(t
/ 4) * I
for I
in range(-2, 3)]
137 Sp
= [0, sin(-t
/ 4 + p_angle
), 0, sin(t
/ 4 - p_angle
)]
139 verts_inner_base
= [(Rb
, radius
* S
[I
], d
) for I
in range(4)]
140 verts_outer_base
= [(Rd
, radius
* S
[I
], d
) for I
in range(4)]
141 verts_middle_tooth
= [(radius
, radius
* S
[I
], d
) for I
in range(1, 4)]
142 verts_tip_tooth
= [(Ra
, radius
* Sp
[I
], d
) for I
in range(1, 4)]
147 cos(a
+ t
/ 4 + p_angle
),
149 cos(a
+ 3 * t
/ 4 - p_angle
)]
151 sin(a
+ t
/ 4 + p_angle
),
153 sin(a
+ 3 * t
/ 4 - p_angle
)]
155 verts_inner_base
= [(Rb
* C
[I
], Rb
* S
[I
], d
)
157 verts_outer_base
= [(Rd
* C
[I
], Rd
* S
[I
], d
)
159 verts_middle_tooth
= [(radius
* C
[I
], radius
* S
[I
], d
+ crown
/ 3)
160 for I
in range(1, 4)]
161 verts_tip_tooth
= [(Ra
* Cp
[I
], Ra
* Sp
[I
], d
+ crown
)
162 for I
in range(1, 4)]
164 return (verts_inner_base
, verts_outer_base
,
165 verts_middle_tooth
, verts_tip_tooth
)
168 # EXPERIMENTAL Calculate the vertex coordinates for a single
169 # section of a gearspoke.
170 # Returns them as a list of tuples
186 def add_spoke(a
, t
, d
, radius
, De
, base
, s
, w
, l
, gap
=0, width
=19):
196 for N
in range(width
, 1, -2):
197 edgefaces
.append(len(verts
))
202 t4
= ts
+ td
* (width
- N
) / (width
- 3.0)
203 A
= [tm
+ (i
- int(N
/ 2)) * t4
for i
in range(N
)]
204 C
= [cos(i
) for i
in A
]
205 S
= [sin(i
) for i
in A
]
207 verts
.extend((Rb
* I
, Rb
* J
, d
) for (I
, J
) in zip(C
, S
))
208 edgefaces2
.append(len(verts
) - 1)
213 for N
in range(width
, 3, -2):
214 sf
.extend([(i
+ n
, i
+ 1 + n
, i
+ 2 + n
, i
+ N
+ n
)
215 for i
in range(0, N
- 1, 2)])
216 sf
.extend([(i
+ 2 + n
, i
+ N
+ n
, i
+ N
+ 1 + n
, i
+ N
+ 2 + n
)
217 for i
in range(0, N
- 3, 2)])
221 return verts
, edgefaces
, edgefaces2
, sf
224 # Create gear geometry.
226 # * A list of vertices (list of tuples)
227 # * A list of faces (list of lists)
228 # * A list (group) of vertices of the tip (list of vertex indices)
229 # * A list (group) of vertices of the valley (list of vertex indices)
231 # teethNum ... Number of teeth on the gear
232 # radius ... Radius of the gear, negative for crown gear
233 # Ad ... Addendum, extent of tooth above radius
234 # De ... Dedendum, extent of tooth below radius
235 # base ... Base, extent of gear below radius
236 # p_angle ... Pressure angle. Skewness of tooth tip. (radiant)
237 # width ... Width, thickness of gear
238 # skew ... Skew of teeth. (radiant)
239 # conangle ... Conical angle of gear. (radiant)
241 # crown ... Inward pointing extend of crown teeth
243 # inner radius = radius - (De + base)
245 def add_gear(teethNum
, radius
, Ad
, De
, base
, p_angle
,
246 width
=1, skew
=0, conangle
=0, rack
=0, crown
=0.0):
249 return None, None, None, None
251 t
= 2 * pi
/ teethNum
256 #print(radius, width, conangle)
258 scale
= (radius
- 2 * width
* tan(conangle
)) / radius
260 scale
= radius
- 2 * width
* tan(conangle
)
264 vgroup_top
= [] # Vertex group of top/tip? vertices.
265 vgroup_valley
= [] # Vertex group of valley vertices
267 verts_bridge_prev
= []
268 for toothCnt
in range(teethNum
):
271 verts_bridge_start
= []
272 verts_bridge_end
= []
274 verts_outside_top
= []
275 verts_outside_bottom
= []
277 in [(0, -width
, 1, True), (skew
, width
, scale
, False)]:
279 verts1
, verts2
, verts3
, verts4
= add_tooth(a
+ s
, t
, d
,
280 radius
* c
, Ad
* c
, De
* c
, base
* c
, p_angle
,
283 vertsIdx1
= list(range(len(verts
), len(verts
) + len(verts1
)))
285 vertsIdx2
= list(range(len(verts
), len(verts
) + len(verts2
)))
287 vertsIdx3
= list(range(len(verts
), len(verts
) + len(verts3
)))
289 vertsIdx4
= list(range(len(verts
), len(verts
) + len(verts4
)))
293 verts_outside
.extend(vertsIdx2
[:2])
294 verts_outside
.append(vertsIdx3
[0])
295 verts_outside
.extend(vertsIdx4
)
296 verts_outside
.append(vertsIdx3
[-1])
297 verts_outside
.append(vertsIdx2
[-1])
300 # verts_inside_top = vertsIdx1
301 verts_outside_top
= verts_outside
303 verts_bridge_start
.append(vertsIdx1
[0])
304 verts_bridge_start
.append(vertsIdx2
[0])
305 verts_bridge_end
.append(vertsIdx1
[-1])
306 verts_bridge_end
.append(vertsIdx2
[-1])
309 # verts_inside_bottom = vertsIdx1
310 verts_outside_bottom
= verts_outside
312 verts_bridge_start
.append(vertsIdx2
[0])
313 verts_bridge_start
.append(vertsIdx1
[0])
314 verts_bridge_end
.append(vertsIdx2
[-1])
315 verts_bridge_end
.append(vertsIdx1
[-1])
317 # Valley = first 2 vertices of outer base:
318 vgroup_valley
.extend(vertsIdx2
[:1])
320 vgroup_top
.extend(vertsIdx4
)
322 faces_tooth_middle_top
= createFaces(vertsIdx2
[1:], vertsIdx3
,
324 faces_tooth_outer_top
= createFaces(vertsIdx3
, vertsIdx4
,
327 faces_base_top
= createFaces(vertsIdx1
, vertsIdx2
, flipped
=top
)
328 faces
.extend(faces_base_top
)
330 faces
.extend(faces_tooth_middle_top
)
331 faces
.extend(faces_tooth_outer_top
)
333 # faces_inside = createFaces(verts_inside_top, verts_inside_bottom)
334 # faces.extend(faces_inside)
336 faces_outside
= createFaces(verts_outside_top
, verts_outside_bottom
,
338 faces
.extend(faces_outside
)
341 verts_bridge_first
= verts_bridge_start
343 # Bridge one tooth to the next
344 if verts_bridge_prev
:
345 faces_bridge
= createFaces(verts_bridge_prev
, verts_bridge_start
)
346 faces
.extend(faces_bridge
)
348 # Remember "end" vertices for next tooth.
349 verts_bridge_prev
= verts_bridge_end
351 # Bridge the first to the last tooth.
352 faces_bridge_f_l
= createFaces(verts_bridge_prev
, verts_bridge_first
)
353 faces
.extend(faces_bridge_f_l
)
355 return verts
, faces
, vgroup_top
, vgroup_valley
358 # Create spokes geometry
360 # * A list of vertices (list of tuples)
361 # * A list of faces (list of lists)
363 # teethNum ... Number of teeth on the gear.
364 # radius ... Radius of the gear, negative for crown gear
365 # De ... Dedendum, extent of tooth below radius
366 # base ... Base, extent of gear below radius
367 # width ... Width, thickness of gear
368 # conangle ... Conical angle of gear. (radiant)
377 # @todo Create a function that takes a "Gear" and creates a
378 # matching "Gear Spokes" object
380 def add_spokes(teethNum
, radius
, De
, base
, width
=1, conangle
=0, rack
=0,
381 spoke
=3, spbevel
=0.1, spwidth
=0.2, splength
=1.0, spresol
=9):
384 return None, None, None, None
387 return None, None, None, None
389 t
= 2 * pi
/ teethNum
394 scale
= (radius
- 2 * width
* tan(conangle
)) / radius
402 for toothCnt
in range(teethNum
):
406 if toothCnt
% spoke
== 0:
407 for d
in (-width
, width
):
408 sv
, edgefaces
, edgefaces2
, sf
= add_spoke(a
+ s
, t
, d
,
409 radius
* c
, De
* c
, base
* c
,
410 spbevel
, spwidth
, splength
, 0, spresol
)
412 faces
.extend([j
+ fl
for j
in i
] for i
in sf
)
416 d2
= fl
- 2 * len(sv
)
418 faces
.extend([(i
+ d2
, j
+ d2
, j
+ d1
, i
+ d1
)
419 for (i
, j
) in zip(edgefaces
[:-1], edgefaces
[1:])])
420 faces
.extend([(i
+ d2
, j
+ d2
, j
+ d1
, i
+ d1
)
421 for (i
, j
) in zip(edgefaces2
[:-1], edgefaces2
[1:])])
424 for d
in (-width
, width
):
425 sv
, edgefaces
, edgefaces2
, sf
= add_spoke(a
+ s
, t
, d
,
426 radius
* c
, De
* c
, base
* c
,
427 spbevel
, spwidth
, splength
, 1, spresol
)
433 d2
= fl
- 2 * len(sv
)
435 faces
.extend([[i
+ d2
, i
+ 1 + d2
, i
+ 1 + d1
, i
+ d1
]
436 for (i
) in range(0, 3)])
437 faces
.extend([[i
+ d2
, i
+ 1 + d2
, i
+ 1 + d1
, i
+ d1
]
438 for (i
) in range(5, 8)])
443 # Create worm geometry.
445 # * A list of vertices
447 # * A list (group) of vertices of the tip
448 # * A list (group) of vertices of the valley
450 # teethNum ... Number of teeth on the worm
451 # radius ... Radius of the gear, negative for crown gear
452 # Ad ... Addendum, extent of tooth above radius
453 # De ... Dedendum, extent of tooth below radius
454 # p_angle ... Pressure angle. Skewness of tooth tip. (radiant)
455 # width ... Width, thickness of gear
456 # crown ... Inward pointing extend of crown teeth
458 # @todo: Fix teethNum. Some numbers are not possible yet
459 # @todo: Create start & end geometry (closing faces)
461 def add_worm(teethNum
, rowNum
, radius
, Ad
, De
, p_angle
,
462 width
=1, skew
=radians(11.25), crown
=0.0):
467 t
= 2 * pi
/ teethNum
471 vgroup_top
= [] # Vertex group of top/tip? vertices.
472 vgroup_valley
= [] # Vertex group of valley vertices
474 # width = width / 2.0
477 for Row
in range(rowNum
):
480 for toothCnt
in range(teethNum
):
488 if toothCnt
% (teethNum
/ worm
) != 0:
490 verts1
, verts2
, verts3
, verts4
= add_tooth(a
+ s
, t
, d
,
491 radius
- De
, 0.0, 0.0, 0, p_angle
)
493 # Ignore other verts than the "other base".
494 verts1
= verts3
= verts4
= []
499 verts1
, verts2
, verts3
, verts4
= add_tooth(a
+ s
, t
, d
,
500 radius
* c
, Ad
* c
, De
* c
, 0 * c
, p_angle
, 0, crown
)
502 # Remove various unneeded verts (if we are "inside" the tooth)
503 del(verts2
[2]) # Central vertex in the base of the tooth.
504 del(verts3
[1]) # Central vertex in the middle of the tooth.
506 vertsIdx2
= list(range(len(verts
), len(verts
) + len(verts2
)))
508 vertsIdx3
= list(range(len(verts
), len(verts
) + len(verts3
)))
510 vertsIdx4
= list(range(len(verts
), len(verts
) + len(verts4
)))
515 verts_current
.extend(vertsIdx2
[:2])
516 verts_current
.append(vertsIdx3
[0])
517 verts_current
.extend(vertsIdx4
)
518 verts_current
.append(vertsIdx3
[-1])
519 verts_current
.append(vertsIdx2
[-1])
521 # Valley = first 2 vertices of outer base:
522 vgroup_valley
.extend(vertsIdx2
[:1])
524 vgroup_top
.extend(vertsIdx4
)
528 verts_current
= vertsIdx2
530 # Valley - all of them.
531 vgroup_valley
.extend(vertsIdx2
)
533 edgeloop
.extend(verts_current
)
535 # Create faces between rings/rows.
537 faces_row
= createFaces(edgeloop
, edgeloop_prev
, closed
=True)
538 faces
.extend(faces_row
)
540 # Remember last ring/row of vertices for next ring/row iteration.
541 edgeloop_prev
= edgeloop
543 return verts
, faces
, vgroup_top
, vgroup_valley
545 def AddGearMesh(self
, context
):
547 verts
, faces
, verts_tip
, verts_valley
= add_gear(
548 self
.number_of_teeth
,
556 conangle
=self
.conangle
,
560 mesh
= bpy
.data
.meshes
.new("Gear")
561 mesh
.from_pydata(verts
, [], faces
)
563 return mesh
, verts_tip
, verts_valley
566 class AddGear(Operator
, object_utils
.AddObjectHelper
):
567 bl_idname
= "mesh.primitive_gear"
568 bl_label
= "Add Gear"
569 bl_description
= "Construct a gear mesh"
570 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
572 Gear
: BoolProperty(name
= "Gear",
574 description
= "Gear")
576 #### change properties
577 name
: StringProperty(name
= "Name",
578 description
= "Name")
580 change
: BoolProperty(name
= "Change",
582 description
= "change Gear")
584 number_of_teeth
: IntProperty(name
="Number of Teeth",
585 description
="Number of teeth on the gear",
590 radius
: FloatProperty(name
="Radius",
591 description
="Radius of the gear, negative for crown gear",
597 addendum
: FloatProperty(name
="Addendum",
598 description
="Addendum, extent of tooth above radius",
604 dedendum
: FloatProperty(name
="Dedendum",
605 description
="Dedendum, extent of tooth below radius",
611 angle
: FloatProperty(name
="Pressure Angle",
612 description
="Pressure angle, skewness of tooth tip",
613 soft_min
=radians(-45.0),
614 soft_max
=radians(45.0),
616 default
=radians(20.0)
618 base
: FloatProperty(name
="Base",
619 description
="Base, extent of gear below radius",
625 width
: FloatProperty(name
="Width",
626 description
="Width, thickness of gear",
632 skew
: FloatProperty(name
="Skewness",
633 description
="Skew of teeth",
634 soft_min
=radians(-360.0),
635 soft_max
=radians(360.0),
639 conangle
: FloatProperty(name
="Conical angle",
640 description
="Conical angle of gear",
641 soft_min
=radians(-360.0),
642 soft_max
=radians(360.0),
646 crown
: FloatProperty(name
="Crown",
647 description
="Inward pointing extend of crown teeth",
654 def draw(self
, context
):
658 box
.prop(self
, 'number_of_teeth')
661 box
.prop(self
, 'radius')
662 box
.prop(self
, 'width')
663 box
.prop(self
, 'base')
666 box
.prop(self
, 'dedendum')
667 box
.prop(self
, 'addendum')
670 box
.prop(self
, 'angle')
671 box
.prop(self
, 'skew')
672 box
.prop(self
, 'conangle')
673 box
.prop(self
, 'crown')
675 if self
.change
== False:
676 # generic transform props
678 box
.prop(self
, 'align', expand
=True)
679 box
.prop(self
, 'location', expand
=True)
680 box
.prop(self
, 'rotation', expand
=True)
683 def poll(cls
, context
):
684 return context
.scene
is not None
686 def execute(self
, context
):
687 # turn off 'Enter Edit Mode'
688 use_enter_edit_mode
= bpy
.context
.preferences
.edit
.use_enter_edit_mode
689 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= False
691 if bpy
.context
.mode
== "OBJECT":
692 if context
.selected_objects
!= [] and context
.active_object
and \
693 (context
.active_object
.data
is not None) and ('Gear' in context
.active_object
.data
.keys()) and \
694 (self
.change
== True):
695 obj
= context
.active_object
697 oldmeshname
= obj
.data
.name
698 mesh
, verts_tip
, verts_valley
= AddGearMesh(self
, context
)
701 bpy
.ops
.object.vertex_group_remove(all
=True)
705 for material
in oldmesh
.materials
:
706 obj
.data
.materials
.append(material
)
708 bpy
.data
.meshes
.remove(oldmesh
)
709 obj
.data
.name
= oldmeshname
711 mesh
, verts_tip
, verts_valley
= AddGearMesh(self
, context
)
712 obj
= object_utils
.object_data_add(context
, mesh
, operator
=self
)
714 # Create vertex groups from stored vertices.
715 tipGroup
= obj
.vertex_groups
.new(name
='Tips')
716 tipGroup
.add(verts_tip
, 1.0, 'ADD')
718 valleyGroup
= obj
.vertex_groups
.new(name
='Valleys')
719 valleyGroup
.add(verts_valley
, 1.0, 'ADD')
721 obj
.data
["Gear"] = True
722 obj
.data
["change"] = False
723 for prm
in GearParameters():
724 obj
.data
[prm
] = getattr(self
, prm
)
726 if bpy
.context
.mode
== "EDIT_MESH":
727 active_object
= context
.active_object
728 name_active_object
= active_object
.name
729 bpy
.ops
.object.mode_set(mode
='OBJECT')
730 mesh
, verts_tip
, verts_valley
= AddGearMesh(self
, context
)
731 obj
= object_utils
.object_data_add(context
, mesh
, operator
=self
)
733 # Create vertex groups from stored vertices.
734 tipGroup
= obj
.vertex_groups
.new(name
='Tips')
735 tipGroup
.add(verts_tip
, 1.0, 'ADD')
737 valleyGroup
= obj
.vertex_groups
.new(name
='Valleys')
738 valleyGroup
.add(verts_valley
, 1.0, 'ADD')
741 active_object
.select_set(True)
742 bpy
.context
.view_layer
.objects
.active
= active_object
743 bpy
.ops
.object.join()
744 context
.active_object
.name
= name_active_object
745 bpy
.ops
.object.mode_set(mode
='EDIT')
747 if use_enter_edit_mode
:
748 bpy
.ops
.object.mode_set(mode
= 'EDIT')
750 # restore pre operator state
751 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= use_enter_edit_mode
755 def invoke(self
, context
, event
):
756 self
.execute(context
)
760 def GearParameters():
773 return GearParameters
775 def AddWormGearMesh(self
, context
):
777 verts
, faces
, verts_tip
, verts_valley
= add_worm(
778 self
.number_of_teeth
,
784 width
=self
.row_height
,
789 mesh
= bpy
.data
.meshes
.new("Worm Gear")
790 mesh
.from_pydata(verts
, [], faces
)
792 return mesh
, verts_tip
, verts_valley
795 class AddWormGear(Operator
, object_utils
.AddObjectHelper
):
796 bl_idname
= "mesh.primitive_worm_gear"
797 bl_label
= "Add Worm Gear"
798 bl_description
= "Construct a worm gear mesh"
799 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
801 WormGear
: BoolProperty(name
= "WormGear",
803 description
= "WormGear")
805 #### change properties
806 name
: StringProperty(name
= "Name",
807 description
= "Name")
809 change
: BoolProperty(name
= "Change",
811 description
= "change WormGear")
813 number_of_teeth
: IntProperty(
814 name
="Number of Teeth",
815 description
="Number of teeth on the gear",
820 number_of_rows
: IntProperty(
821 name
="Number of Rows",
822 description
="Number of rows on the worm gear",
827 radius
: FloatProperty(
829 description
="Radius of the gear, negative for crown gear",
835 addendum
: FloatProperty(
837 description
="Addendum, extent of tooth above radius",
843 dedendum
: FloatProperty(
845 description
="Dedendum, extent of tooth below radius",
851 angle
: FloatProperty(
852 name
="Pressure Angle",
853 description
="Pressure angle, skewness of tooth tip",
854 soft_min
=radians(-45.0),
855 soft_max
=radians(45.0),
856 default
=radians(20.0),
859 row_height
: FloatProperty(
861 description
="Height of each Row",
868 name
="Skewness per Row",
869 description
="Skew of each row",
870 soft_min
=radians(-360.0),
871 soft_max
=radians(360.0),
872 default
=radians(11.25),
875 crown
: FloatProperty(
877 description
="Inward pointing extend of crown teeth",
884 def draw(self
, context
):
887 box
.prop(self
, "number_of_teeth")
888 box
.prop(self
, "number_of_rows")
889 box
.prop(self
, "radius")
890 box
.prop(self
, "row_height")
893 box
.prop(self
, "addendum")
894 box
.prop(self
, "dedendum")
897 box
.prop(self
, "angle")
898 box
.prop(self
, "skew")
899 box
.prop(self
, "crown")
901 if self
.change
== False:
902 # generic transform props
904 box
.prop(self
, 'align', expand
=True)
905 box
.prop(self
, 'location', expand
=True)
906 box
.prop(self
, 'rotation', expand
=True)
908 def execute(self
, context
):
909 # turn off 'Enter Edit Mode'
910 use_enter_edit_mode
= bpy
.context
.preferences
.edit
.use_enter_edit_mode
911 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= False
913 if bpy
.context
.mode
== "OBJECT":
914 if context
.selected_objects
!= [] and context
.active_object
and \
915 (context
.active_object
.data
is not None) and ('WormGear' in context
.active_object
.data
.keys()) and \
916 (self
.change
== True):
917 obj
= context
.active_object
919 oldmeshname
= obj
.data
.name
921 mesh
, verts_tip
, verts_valley
= AddWormGearMesh(self
, context
)
924 bpy
.ops
.object.vertex_group_remove(all
=True)
928 for material
in oldmesh
.materials
:
929 obj
.data
.materials
.append(material
)
931 bpy
.data
.meshes
.remove(oldmesh
)
932 obj
.data
.name
= oldmeshname
934 mesh
, verts_tip
, verts_valley
= AddWormGearMesh(self
, context
)
935 obj
= object_utils
.object_data_add(context
, mesh
, operator
=self
)
937 # Create vertex groups from stored vertices.
938 tipGroup
= obj
.vertex_groups
.new(name
= 'Tips')
939 tipGroup
.add(verts_tip
, 1.0, 'ADD')
941 valleyGroup
= obj
.vertex_groups
.new(name
= 'Valleys')
942 valleyGroup
.add(verts_valley
, 1.0, 'ADD')
944 obj
.data
["WormGear"] = True
945 obj
.data
["change"] = False
946 for prm
in WormGearParameters():
947 obj
.data
[prm
] = getattr(self
, prm
)
949 if bpy
.context
.mode
== "EDIT_MESH":
950 active_object
= context
.active_object
951 name_active_object
= active_object
.name
952 bpy
.ops
.object.mode_set(mode
='OBJECT')
953 mesh
, verts_tip
, verts_valley
= AddWormGearMesh(self
, context
)
954 obj
= object_utils
.object_data_add(context
, mesh
, operator
=self
)
956 # Create vertex groups from stored vertices.
957 tipGroup
= obj
.vertex_groups
.new(name
= 'Tips')
958 tipGroup
.add(verts_tip
, 1.0, 'ADD')
960 valleyGroup
= obj
.vertex_groups
.new(name
= 'Valleys')
961 valleyGroup
.add(verts_valley
, 1.0, 'ADD')
964 active_object
.select_set(True)
965 bpy
.context
.view_layer
.objects
.active
= active_object
966 bpy
.ops
.object.join()
967 context
.active_object
.name
= name_active_object
968 bpy
.ops
.object.mode_set(mode
='EDIT')
970 if use_enter_edit_mode
:
971 bpy
.ops
.object.mode_set(mode
= 'EDIT')
973 # restore pre operator state
974 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= use_enter_edit_mode
978 def WormGearParameters():
979 WormGearParameters
= [
990 return WormGearParameters