1 # SPDX-FileCopyrightText: 2009-2010 Michel J. Anders (varkenvarken)
3 # SPDX-License-Identifier: GPL-2.0-or-later
6 from bpy
.types
import Operator
12 from bpy
.props
import (
19 from mathutils
import (
23 from bpy_extras
import object_utils
25 # A very simple "bridge" tool.
26 # Connects two equally long vertex rows with faces.
27 # Returns a list of the new faces (list of lists)
29 # vertIdx1 ... First vertex list (list of vertex indices)
30 # vertIdx2 ... Second vertex list (list of vertex indices)
31 # closed ... Creates a loop (first & last are closed)
32 # flipped ... Invert the normal of the face(s)
34 # Note: You can set vertIdx1 to a single vertex index to create
36 # Note: If both vertex idx list are the same length they have
37 # to have at least 2 vertices
39 def createFaces(vertIdx1
, vertIdx2
, closed
=False, flipped
=False):
42 if not vertIdx1
or not vertIdx2
:
45 if len(vertIdx1
) < 2 and len(vertIdx2
) < 2:
49 if (len(vertIdx1
) != len(vertIdx2
)):
50 if (len(vertIdx1
) == 1 and len(vertIdx2
) > 1):
58 # Bridge the start with the end.
65 face
.append(vertIdx1
[total
- 1])
69 face
= [vertIdx2
[0], vertIdx1
[0]]
71 face
.append(vertIdx1
[total
- 1])
72 face
.append(vertIdx2
[total
- 1])
75 # Bridge the rest of the faces.
76 for num
in range(total
- 1):
79 face
= [vertIdx2
[num
], vertIdx1
[0], vertIdx2
[num
+ 1]]
81 face
= [vertIdx2
[num
], vertIdx1
[num
],
82 vertIdx1
[num
+ 1], vertIdx2
[num
+ 1]]
86 face
= [vertIdx1
[0], vertIdx2
[num
], vertIdx2
[num
+ 1]]
88 face
= [vertIdx1
[num
], vertIdx2
[num
],
89 vertIdx2
[num
+ 1], vertIdx1
[num
+ 1]]
95 # Calculate the vertex coordinates for a single
96 # section of a gear tooth.
97 # Returns 4 lists of vertex coords (list of tuples):
98 # *-*---*---* (1.) verts_inner_base
100 # *-*---*---* (2.) verts_outer_base
102 # *---*---* (3.) verts_middle_tooth
104 # *-*-* (4.) verts_tip_tooth
117 def add_tooth(a
, t
, d
, radius
, Ad
, De
, base
, p_angle
, rack
=0, crown
=0.0):
118 A
= [a
, a
+ t
/ 4, a
+ t
/ 2, a
+ 3 * t
/ 4]
119 C
= [cos(i
) for i
in A
]
120 S
= [sin(i
) for i
in A
]
126 # Pressure angle calc
127 O
= Ad
* tan(p_angle
)
129 p_angle
= atan(O
/ Ra
)
137 S
= [sin(t
/ 4) * I
for I
in range(-2, 3)]
138 Sp
= [0, sin(-t
/ 4 + p_angle
), 0, sin(t
/ 4 - p_angle
)]
140 verts_inner_base
= [(Rb
, radius
* S
[I
], d
) for I
in range(4)]
141 verts_outer_base
= [(Rd
, radius
* S
[I
], d
) for I
in range(4)]
142 verts_middle_tooth
= [(radius
, radius
* S
[I
], d
) for I
in range(1, 4)]
143 verts_tip_tooth
= [(Ra
, radius
* Sp
[I
], d
) for I
in range(1, 4)]
148 cos(a
+ t
/ 4 + p_angle
),
150 cos(a
+ 3 * t
/ 4 - p_angle
)]
152 sin(a
+ t
/ 4 + p_angle
),
154 sin(a
+ 3 * t
/ 4 - p_angle
)]
156 verts_inner_base
= [(Rb
* C
[I
], Rb
* S
[I
], d
)
158 verts_outer_base
= [(Rd
* C
[I
], Rd
* S
[I
], d
)
160 verts_middle_tooth
= [(radius
* C
[I
], radius
* S
[I
], d
+ crown
/ 3)
161 for I
in range(1, 4)]
162 verts_tip_tooth
= [(Ra
* Cp
[I
], Ra
* Sp
[I
], d
+ crown
)
163 for I
in range(1, 4)]
165 return (verts_inner_base
, verts_outer_base
,
166 verts_middle_tooth
, verts_tip_tooth
)
169 # EXPERIMENTAL Calculate the vertex coordinates for a single
170 # section of a gearspoke.
171 # Returns them as a list of tuples
187 def add_spoke(a
, t
, d
, radius
, De
, base
, s
, w
, l
, gap
=0, width
=19):
197 for N
in range(width
, 1, -2):
198 edgefaces
.append(len(verts
))
203 t4
= ts
+ td
* (width
- N
) / (width
- 3.0)
204 A
= [tm
+ (i
- int(N
/ 2)) * t4
for i
in range(N
)]
205 C
= [cos(i
) for i
in A
]
206 S
= [sin(i
) for i
in A
]
208 verts
.extend((Rb
* I
, Rb
* J
, d
) for (I
, J
) in zip(C
, S
))
209 edgefaces2
.append(len(verts
) - 1)
214 for N
in range(width
, 3, -2):
215 sf
.extend([(i
+ n
, i
+ 1 + n
, i
+ 2 + n
, i
+ N
+ n
)
216 for i
in range(0, N
- 1, 2)])
217 sf
.extend([(i
+ 2 + n
, i
+ N
+ n
, i
+ N
+ 1 + n
, i
+ N
+ 2 + n
)
218 for i
in range(0, N
- 3, 2)])
222 return verts
, edgefaces
, edgefaces2
, sf
225 # Create gear geometry.
227 # * A list of vertices (list of tuples)
228 # * A list of faces (list of lists)
229 # * A list (group) of vertices of the tip (list of vertex indices)
230 # * A list (group) of vertices of the valley (list of vertex indices)
232 # teethNum ... Number of teeth on the gear
233 # radius ... Radius of the gear, negative for crown gear
234 # Ad ... Addendum, extent of tooth above radius
235 # De ... Dedendum, extent of tooth below radius
236 # base ... Base, extent of gear below radius
237 # p_angle ... Pressure angle. Skewness of tooth tip. (radiant)
238 # width ... Width, thickness of gear
239 # skew ... Skew of teeth. (radiant)
240 # conangle ... Conical angle of gear. (radiant)
242 # crown ... Inward pointing extend of crown teeth
244 # inner radius = radius - (De + base)
246 def add_gear(teethNum
, radius
, Ad
, De
, base
, p_angle
,
247 width
=1, skew
=0, conangle
=0, rack
=0, crown
=0.0):
250 return None, None, None, None
252 t
= 2 * pi
/ teethNum
257 #print(radius, width, conangle)
259 scale
= (radius
- 2 * width
* tan(conangle
)) / radius
261 scale
= radius
- 2 * width
* tan(conangle
)
265 vgroup_top
= [] # Vertex group of top/tip? vertices.
266 vgroup_valley
= [] # Vertex group of valley vertices
268 verts_bridge_prev
= []
269 for toothCnt
in range(teethNum
):
272 verts_bridge_start
= []
273 verts_bridge_end
= []
275 verts_outside_top
= []
276 verts_outside_bottom
= []
278 in [(0, -width
, 1, True), (skew
, width
, scale
, False)]:
280 verts1
, verts2
, verts3
, verts4
= add_tooth(a
+ s
, t
, d
,
281 radius
* c
, Ad
* c
, De
* c
, base
* c
, p_angle
,
284 vertsIdx1
= list(range(len(verts
), len(verts
) + len(verts1
)))
286 vertsIdx2
= list(range(len(verts
), len(verts
) + len(verts2
)))
288 vertsIdx3
= list(range(len(verts
), len(verts
) + len(verts3
)))
290 vertsIdx4
= list(range(len(verts
), len(verts
) + len(verts4
)))
294 verts_outside
.extend(vertsIdx2
[:2])
295 verts_outside
.append(vertsIdx3
[0])
296 verts_outside
.extend(vertsIdx4
)
297 verts_outside
.append(vertsIdx3
[-1])
298 verts_outside
.append(vertsIdx2
[-1])
301 # verts_inside_top = vertsIdx1
302 verts_outside_top
= verts_outside
304 verts_bridge_start
.append(vertsIdx1
[0])
305 verts_bridge_start
.append(vertsIdx2
[0])
306 verts_bridge_end
.append(vertsIdx1
[-1])
307 verts_bridge_end
.append(vertsIdx2
[-1])
310 # verts_inside_bottom = vertsIdx1
311 verts_outside_bottom
= verts_outside
313 verts_bridge_start
.append(vertsIdx2
[0])
314 verts_bridge_start
.append(vertsIdx1
[0])
315 verts_bridge_end
.append(vertsIdx2
[-1])
316 verts_bridge_end
.append(vertsIdx1
[-1])
318 # Valley = first 2 vertices of outer base:
319 vgroup_valley
.extend(vertsIdx2
[:1])
321 vgroup_top
.extend(vertsIdx4
)
323 faces_tooth_middle_top
= createFaces(vertsIdx2
[1:], vertsIdx3
,
325 faces_tooth_outer_top
= createFaces(vertsIdx3
, vertsIdx4
,
328 faces_base_top
= createFaces(vertsIdx1
, vertsIdx2
, flipped
=top
)
329 faces
.extend(faces_base_top
)
331 faces
.extend(faces_tooth_middle_top
)
332 faces
.extend(faces_tooth_outer_top
)
334 # faces_inside = createFaces(verts_inside_top, verts_inside_bottom)
335 # faces.extend(faces_inside)
337 faces_outside
= createFaces(verts_outside_top
, verts_outside_bottom
,
339 faces
.extend(faces_outside
)
342 verts_bridge_first
= verts_bridge_start
344 # Bridge one tooth to the next
345 if verts_bridge_prev
:
346 faces_bridge
= createFaces(verts_bridge_prev
, verts_bridge_start
)
347 faces
.extend(faces_bridge
)
349 # Remember "end" vertices for next tooth.
350 verts_bridge_prev
= verts_bridge_end
352 # Bridge the first to the last tooth.
353 faces_bridge_f_l
= createFaces(verts_bridge_prev
, verts_bridge_first
)
354 faces
.extend(faces_bridge_f_l
)
356 return verts
, faces
, vgroup_top
, vgroup_valley
359 # Create spokes geometry
361 # * A list of vertices (list of tuples)
362 # * A list of faces (list of lists)
364 # teethNum ... Number of teeth on the gear.
365 # radius ... Radius of the gear, negative for crown gear
366 # De ... Dedendum, extent of tooth below radius
367 # base ... Base, extent of gear below radius
368 # width ... Width, thickness of gear
369 # conangle ... Conical angle of gear. (radiant)
378 # @todo Create a function that takes a "Gear" and creates a
379 # matching "Gear Spokes" object
381 def add_spokes(teethNum
, radius
, De
, base
, width
=1, conangle
=0, rack
=0,
382 spoke
=3, spbevel
=0.1, spwidth
=0.2, splength
=1.0, spresol
=9):
385 return None, None, None, None
388 return None, None, None, None
390 t
= 2 * pi
/ teethNum
395 scale
= (radius
- 2 * width
* tan(conangle
)) / radius
403 for toothCnt
in range(teethNum
):
407 if toothCnt
% spoke
== 0:
408 for d
in (-width
, width
):
409 sv
, edgefaces
, edgefaces2
, sf
= add_spoke(a
+ s
, t
, d
,
410 radius
* c
, De
* c
, base
* c
,
411 spbevel
, spwidth
, splength
, 0, spresol
)
413 faces
.extend([j
+ fl
for j
in i
] for i
in sf
)
417 d2
= fl
- 2 * len(sv
)
419 faces
.extend([(i
+ d2
, j
+ d2
, j
+ d1
, i
+ d1
)
420 for (i
, j
) in zip(edgefaces
[:-1], edgefaces
[1:])])
421 faces
.extend([(i
+ d2
, j
+ d2
, j
+ d1
, i
+ d1
)
422 for (i
, j
) in zip(edgefaces2
[:-1], edgefaces2
[1:])])
425 for d
in (-width
, width
):
426 sv
, edgefaces
, edgefaces2
, sf
= add_spoke(a
+ s
, t
, d
,
427 radius
* c
, De
* c
, base
* c
,
428 spbevel
, spwidth
, splength
, 1, spresol
)
434 d2
= fl
- 2 * len(sv
)
436 faces
.extend([[i
+ d2
, i
+ 1 + d2
, i
+ 1 + d1
, i
+ d1
]
437 for (i
) in range(0, 3)])
438 faces
.extend([[i
+ d2
, i
+ 1 + d2
, i
+ 1 + d1
, i
+ d1
]
439 for (i
) in range(5, 8)])
444 # Create worm geometry.
446 # * A list of vertices
448 # * A list (group) of vertices of the tip
449 # * A list (group) of vertices of the valley
451 # teethNum ... Number of teeth on the worm
452 # radius ... Radius of the gear, negative for crown gear
453 # Ad ... Addendum, extent of tooth above radius
454 # De ... Dedendum, extent of tooth below radius
455 # p_angle ... Pressure angle. Skewness of tooth tip. (radiant)
456 # width ... Width, thickness of gear
457 # crown ... Inward pointing extend of crown teeth
459 # @todo: Fix teethNum. Some numbers are not possible yet
460 # @todo: Create start & end geometry (closing faces)
462 def add_worm(teethNum
, rowNum
, radius
, Ad
, De
, p_angle
,
463 width
=1, skew
=radians(11.25), crown
=0.0):
468 t
= 2 * pi
/ teethNum
472 vgroup_top
= [] # Vertex group of top/tip? vertices.
473 vgroup_valley
= [] # Vertex group of valley vertices
475 # width = width / 2.0
478 for Row
in range(rowNum
):
481 for toothCnt
in range(teethNum
):
489 if toothCnt
% (teethNum
/ worm
) != 0:
491 verts1
, verts2
, verts3
, verts4
= add_tooth(a
+ s
, t
, d
,
492 radius
- De
, 0.0, 0.0, 0, p_angle
)
494 # Ignore other verts than the "other base".
495 verts1
= verts3
= verts4
= []
500 verts1
, verts2
, verts3
, verts4
= add_tooth(a
+ s
, t
, d
,
501 radius
* c
, Ad
* c
, De
* c
, 0 * c
, p_angle
, 0, crown
)
503 # Remove various unneeded verts (if we are "inside" the tooth)
504 del(verts2
[2]) # Central vertex in the base of the tooth.
505 del(verts3
[1]) # Central vertex in the middle of the tooth.
507 vertsIdx2
= list(range(len(verts
), len(verts
) + len(verts2
)))
509 vertsIdx3
= list(range(len(verts
), len(verts
) + len(verts3
)))
511 vertsIdx4
= list(range(len(verts
), len(verts
) + len(verts4
)))
516 verts_current
.extend(vertsIdx2
[:2])
517 verts_current
.append(vertsIdx3
[0])
518 verts_current
.extend(vertsIdx4
)
519 verts_current
.append(vertsIdx3
[-1])
520 verts_current
.append(vertsIdx2
[-1])
522 # Valley = first 2 vertices of outer base:
523 vgroup_valley
.extend(vertsIdx2
[:1])
525 vgroup_top
.extend(vertsIdx4
)
529 verts_current
= vertsIdx2
531 # Valley - all of them.
532 vgroup_valley
.extend(vertsIdx2
)
534 edgeloop
.extend(verts_current
)
536 # Create faces between rings/rows.
538 faces_row
= createFaces(edgeloop
, edgeloop_prev
, closed
=True)
539 faces
.extend(faces_row
)
541 # Remember last ring/row of vertices for next ring/row iteration.
542 edgeloop_prev
= edgeloop
544 return verts
, faces
, vgroup_top
, vgroup_valley
546 def AddGearMesh(self
, context
):
548 verts
, faces
, verts_tip
, verts_valley
= add_gear(
549 self
.number_of_teeth
,
557 conangle
=self
.conangle
,
561 mesh
= bpy
.data
.meshes
.new("Gear")
562 mesh
.from_pydata(verts
, [], faces
)
564 return mesh
, verts_tip
, verts_valley
567 class AddGear(Operator
, object_utils
.AddObjectHelper
):
568 bl_idname
= "mesh.primitive_gear"
569 bl_label
= "Add Gear"
570 bl_description
= "Construct a gear mesh"
571 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
573 Gear
: BoolProperty(name
= "Gear",
575 description
= "Gear")
577 #### change properties
578 name
: StringProperty(name
= "Name",
579 description
= "Name")
581 change
: BoolProperty(name
= "Change",
583 description
= "change Gear")
585 number_of_teeth
: IntProperty(name
="Number of Teeth",
586 description
="Number of teeth on the gear",
591 radius
: FloatProperty(name
="Radius",
592 description
="Radius of the gear, negative for crown gear",
598 addendum
: FloatProperty(name
="Addendum",
599 description
="Addendum, extent of tooth above radius",
605 dedendum
: FloatProperty(name
="Dedendum",
606 description
="Dedendum, extent of tooth below radius",
612 angle
: FloatProperty(name
="Pressure Angle",
613 description
="Pressure angle, skewness of tooth tip",
614 soft_min
=radians(-45.0),
615 soft_max
=radians(45.0),
617 default
=radians(20.0)
619 base
: FloatProperty(name
="Base",
620 description
="Base, extent of gear below radius",
626 width
: FloatProperty(name
="Width",
627 description
="Width, thickness of gear",
633 skew
: FloatProperty(name
="Skewness",
634 description
="Skew of teeth",
635 soft_min
=radians(-360.0),
636 soft_max
=radians(360.0),
640 conangle
: FloatProperty(name
="Conical angle",
641 description
="Conical angle of gear",
642 soft_min
=radians(-360.0),
643 soft_max
=radians(360.0),
647 crown
: FloatProperty(name
="Crown",
648 description
="Inward pointing extend of crown teeth",
655 def draw(self
, context
):
659 box
.prop(self
, 'number_of_teeth')
662 box
.prop(self
, 'radius')
663 box
.prop(self
, 'width')
664 box
.prop(self
, 'base')
667 box
.prop(self
, 'dedendum')
668 box
.prop(self
, 'addendum')
671 box
.prop(self
, 'angle')
672 box
.prop(self
, 'skew')
673 box
.prop(self
, 'conangle')
674 box
.prop(self
, 'crown')
676 if self
.change
== False:
677 # generic transform props
679 box
.prop(self
, 'align', expand
=True)
680 box
.prop(self
, 'location', expand
=True)
681 box
.prop(self
, 'rotation', expand
=True)
684 def poll(cls
, context
):
685 return context
.scene
is not None
687 def execute(self
, context
):
688 # turn off 'Enter Edit Mode'
689 use_enter_edit_mode
= bpy
.context
.preferences
.edit
.use_enter_edit_mode
690 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= False
692 if bpy
.context
.mode
== "OBJECT":
693 if context
.selected_objects
!= [] and context
.active_object
and \
694 (context
.active_object
.data
is not None) and ('Gear' in context
.active_object
.data
.keys()) and \
695 (self
.change
== True):
696 obj
= context
.active_object
698 oldmeshname
= obj
.data
.name
699 mesh
, verts_tip
, verts_valley
= AddGearMesh(self
, context
)
702 bpy
.ops
.object.vertex_group_remove(all
=True)
706 for material
in oldmesh
.materials
:
707 obj
.data
.materials
.append(material
)
709 bpy
.data
.meshes
.remove(oldmesh
)
710 obj
.data
.name
= oldmeshname
712 mesh
, verts_tip
, verts_valley
= AddGearMesh(self
, context
)
713 obj
= object_utils
.object_data_add(context
, mesh
, operator
=self
)
715 # Create vertex groups from stored vertices.
716 tipGroup
= obj
.vertex_groups
.new(name
='Tips')
717 tipGroup
.add(verts_tip
, 1.0, 'ADD')
719 valleyGroup
= obj
.vertex_groups
.new(name
='Valleys')
720 valleyGroup
.add(verts_valley
, 1.0, 'ADD')
722 obj
.data
["Gear"] = True
723 obj
.data
["change"] = False
724 for prm
in GearParameters():
725 obj
.data
[prm
] = getattr(self
, prm
)
727 if bpy
.context
.mode
== "EDIT_MESH":
728 active_object
= context
.active_object
729 name_active_object
= active_object
.name
730 bpy
.ops
.object.mode_set(mode
='OBJECT')
731 mesh
, verts_tip
, verts_valley
= AddGearMesh(self
, context
)
732 obj
= object_utils
.object_data_add(context
, mesh
, operator
=self
)
734 # Create vertex groups from stored vertices.
735 tipGroup
= obj
.vertex_groups
.new(name
='Tips')
736 tipGroup
.add(verts_tip
, 1.0, 'ADD')
738 valleyGroup
= obj
.vertex_groups
.new(name
='Valleys')
739 valleyGroup
.add(verts_valley
, 1.0, 'ADD')
742 active_object
.select_set(True)
743 bpy
.context
.view_layer
.objects
.active
= active_object
744 bpy
.ops
.object.join()
745 context
.active_object
.name
= name_active_object
746 bpy
.ops
.object.mode_set(mode
='EDIT')
748 if use_enter_edit_mode
:
749 bpy
.ops
.object.mode_set(mode
= 'EDIT')
751 # restore pre operator state
752 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= use_enter_edit_mode
756 def invoke(self
, context
, event
):
757 self
.execute(context
)
761 def GearParameters():
774 return GearParameters
776 def AddWormGearMesh(self
, context
):
778 verts
, faces
, verts_tip
, verts_valley
= add_worm(
779 self
.number_of_teeth
,
785 width
=self
.row_height
,
790 mesh
= bpy
.data
.meshes
.new("Worm Gear")
791 mesh
.from_pydata(verts
, [], faces
)
793 return mesh
, verts_tip
, verts_valley
796 class AddWormGear(Operator
, object_utils
.AddObjectHelper
):
797 bl_idname
= "mesh.primitive_worm_gear"
798 bl_label
= "Add Worm Gear"
799 bl_description
= "Construct a worm gear mesh"
800 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
802 WormGear
: BoolProperty(name
= "WormGear",
804 description
= "WormGear")
806 #### change properties
807 name
: StringProperty(name
= "Name",
808 description
= "Name")
810 change
: BoolProperty(name
= "Change",
812 description
= "change WormGear")
814 number_of_teeth
: IntProperty(
815 name
="Number of Teeth",
816 description
="Number of teeth on the gear",
821 number_of_rows
: IntProperty(
822 name
="Number of Rows",
823 description
="Number of rows on the worm gear",
828 radius
: FloatProperty(
830 description
="Radius of the gear, negative for crown gear",
836 addendum
: FloatProperty(
838 description
="Addendum, extent of tooth above radius",
844 dedendum
: FloatProperty(
846 description
="Dedendum, extent of tooth below radius",
852 angle
: FloatProperty(
853 name
="Pressure Angle",
854 description
="Pressure angle, skewness of tooth tip",
855 soft_min
=radians(-45.0),
856 soft_max
=radians(45.0),
857 default
=radians(20.0),
860 row_height
: FloatProperty(
862 description
="Height of each Row",
869 name
="Skewness per Row",
870 description
="Skew of each row",
871 soft_min
=radians(-360.0),
872 soft_max
=radians(360.0),
873 default
=radians(11.25),
876 crown
: FloatProperty(
878 description
="Inward pointing extend of crown teeth",
885 def draw(self
, context
):
888 box
.prop(self
, "number_of_teeth")
889 box
.prop(self
, "number_of_rows")
890 box
.prop(self
, "radius")
891 box
.prop(self
, "row_height")
894 box
.prop(self
, "addendum")
895 box
.prop(self
, "dedendum")
898 box
.prop(self
, "angle")
899 box
.prop(self
, "skew")
900 box
.prop(self
, "crown")
902 if self
.change
== False:
903 # generic transform props
905 box
.prop(self
, 'align', expand
=True)
906 box
.prop(self
, 'location', expand
=True)
907 box
.prop(self
, 'rotation', expand
=True)
909 def execute(self
, context
):
910 # turn off 'Enter Edit Mode'
911 use_enter_edit_mode
= bpy
.context
.preferences
.edit
.use_enter_edit_mode
912 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= False
914 if bpy
.context
.mode
== "OBJECT":
915 if context
.selected_objects
!= [] and context
.active_object
and \
916 (context
.active_object
.data
is not None) and ('WormGear' in context
.active_object
.data
.keys()) and \
917 (self
.change
== True):
918 obj
= context
.active_object
920 oldmeshname
= obj
.data
.name
922 mesh
, verts_tip
, verts_valley
= AddWormGearMesh(self
, context
)
925 bpy
.ops
.object.vertex_group_remove(all
=True)
929 for material
in oldmesh
.materials
:
930 obj
.data
.materials
.append(material
)
932 bpy
.data
.meshes
.remove(oldmesh
)
933 obj
.data
.name
= oldmeshname
935 mesh
, verts_tip
, verts_valley
= AddWormGearMesh(self
, context
)
936 obj
= object_utils
.object_data_add(context
, mesh
, operator
=self
)
938 # Create vertex groups from stored vertices.
939 tipGroup
= obj
.vertex_groups
.new(name
= 'Tips')
940 tipGroup
.add(verts_tip
, 1.0, 'ADD')
942 valleyGroup
= obj
.vertex_groups
.new(name
= 'Valleys')
943 valleyGroup
.add(verts_valley
, 1.0, 'ADD')
945 obj
.data
["WormGear"] = True
946 obj
.data
["change"] = False
947 for prm
in WormGearParameters():
948 obj
.data
[prm
] = getattr(self
, prm
)
950 if bpy
.context
.mode
== "EDIT_MESH":
951 active_object
= context
.active_object
952 name_active_object
= active_object
.name
953 bpy
.ops
.object.mode_set(mode
='OBJECT')
954 mesh
, verts_tip
, verts_valley
= AddWormGearMesh(self
, context
)
955 obj
= object_utils
.object_data_add(context
, mesh
, operator
=self
)
957 # Create vertex groups from stored vertices.
958 tipGroup
= obj
.vertex_groups
.new(name
= 'Tips')
959 tipGroup
.add(verts_tip
, 1.0, 'ADD')
961 valleyGroup
= obj
.vertex_groups
.new(name
= 'Valleys')
962 valleyGroup
.add(verts_valley
, 1.0, 'ADD')
965 active_object
.select_set(True)
966 bpy
.context
.view_layer
.objects
.active
= active_object
967 bpy
.ops
.object.join()
968 context
.active_object
.name
= name_active_object
969 bpy
.ops
.object.mode_set(mode
='EDIT')
971 if use_enter_edit_mode
:
972 bpy
.ops
.object.mode_set(mode
= 'EDIT')
974 # restore pre operator state
975 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= use_enter_edit_mode
979 def WormGearParameters():
980 WormGearParameters
= [
991 return WormGearParameters