1 # GPL # "author": "Pontiac, Fourmadmen, Dreampainter"
4 from bpy
.types
import Operator
5 from mathutils
import (
9 from math
import cos
, sin
, pi
10 from bpy
.props
import (
16 from bpy_extras
import object_utils
18 # Create a new mesh (object) from verts/edges/faces.
19 # verts/edges/faces ... List of vertices/edges/faces for the
20 # new mesh (as used in from_pydata)
21 # name ... Name of the new mesh (& object)
23 def create_mesh_object(context
, self
, verts
, edges
, faces
, name
):
26 mesh
= bpy
.data
.meshes
.new(name
)
28 # Make a mesh from a list of verts/edges/faces.
29 mesh
.from_pydata(verts
, edges
, faces
)
31 # Update mesh geometry after adding stuff.
34 from bpy_extras
import object_utils
35 return object_utils
.object_data_add(context
, mesh
, operator
=self
)
38 # A very simple "bridge" tool.
40 def createFaces(vertIdx1
, vertIdx2
, closed
=False, flipped
=False):
43 if not vertIdx1
or not vertIdx2
:
46 if len(vertIdx1
) < 2 and len(vertIdx2
) < 2:
50 if (len(vertIdx1
) != len(vertIdx2
)):
51 if (len(vertIdx1
) == 1 and len(vertIdx2
) > 1):
59 # Bridge the start with the end
66 face
.append(vertIdx1
[total
- 1])
70 face
= [vertIdx2
[0], vertIdx1
[0]]
72 face
.append(vertIdx1
[total
- 1])
73 face
.append(vertIdx2
[total
- 1])
76 # Bridge the rest of the faces
77 for num
in range(total
- 1):
80 face
= [vertIdx2
[num
], vertIdx1
[0], vertIdx2
[num
+ 1]]
82 face
= [vertIdx2
[num
], vertIdx1
[num
],
83 vertIdx1
[num
+ 1], vertIdx2
[num
+ 1]]
87 face
= [vertIdx1
[0], vertIdx2
[num
], vertIdx2
[num
+ 1]]
89 face
= [vertIdx1
[num
], vertIdx2
[num
],
90 vertIdx2
[num
+ 1], vertIdx1
[num
+ 1]]
96 # @todo Clean up vertex&face creation process a bit.
97 def add_gem(r1
, r2
, seg
, h1
, h2
):
101 seg = number of segments
104 Generates the vertices and faces of the gem
109 a
= 2.0 * pi
/ seg
# Angle between segments
110 offset
= a
/ 2.0 # Middle between segments
112 r3
= ((r1
+ r2
) / 2.0) / cos(offset
) # Middle of crown
113 r4
= (r1
/ 2.0) / cos(offset
) # Middle of pavilion
114 h3
= h2
/ 2.0 # Middle of crown height
115 h4
= -h1
/ 2.0 # Middle of pavilion height
118 vert_tip
= len(verts
)
119 verts
.append(Vector((0.0, 0.0, -h1
)))
121 # Middle vertex of the flat side (crown)
122 vert_flat
= len(verts
)
123 verts
.append(Vector((0.0, 0.0, h2
)))
128 s2
= sin(offset
+ i
* a
)
130 c2
= cos(offset
+ i
* a
)
132 verts
.append((r4
* s1
, r4
* c1
, h4
)) # Middle of pavilion
133 verts
.append((r1
* s2
, r1
* c2
, 0.0)) # Pavilion
134 verts
.append((r3
* s1
, r3
* c1
, h3
)) # Middle crown
135 edgeloop_flat
.append(len(verts
))
136 verts
.append((r2
* s2
, r2
* c2
, h2
)) # Crown
140 for index
in range(seg
):
142 j
= ((index
+ 1) % seg
) * 4
144 faces
.append([j
+ 2, vert_tip
, i
+ 2, i
+ 3]) # Tip -> Middle of pav
145 faces
.append([j
+ 2, i
+ 3, j
+ 3]) # Middle of pav -> pav
146 faces
.append([j
+ 3, i
+ 3, j
+ 4]) # Pav -> Middle crown
147 faces
.append([j
+ 4, i
+ 3, i
+ 4, i
+ 5]) # Crown quads
148 faces
.append([j
+ 4, i
+ 5, j
+ 5]) # Middle crown -> crown
150 faces_flat
= createFaces([vert_flat
], edgeloop_flat
, closed
=True, flipped
=True)
151 faces
.extend(faces_flat
)
156 def add_diamond(segments
, girdle_radius
, table_radius
,
157 crown_height
, pavilion_height
):
160 z_axis
= (0.0, 0.0, -1.0)
165 height_flat
= crown_height
167 height_tip
= -pavilion_height
169 # Middle vertex of the flat side (crown)
170 vert_flat
= len(verts
)
171 verts
.append(Vector((0.0, 0.0, height_flat
)))
174 vert_tip
= len(verts
)
175 verts
.append(Vector((0.0, 0.0, height_tip
)))
180 for index
in range(segments
):
181 quat
= Quaternion(z_axis
, (index
/ segments
) * PI_2
)
183 # angle = PI_2 * index / segments # UNUSED
186 verts_flat
.append(len(verts
))
187 vec
= quat
@ Vector((table_radius
, 0.0, height_flat
))
190 # Row for the middle/girdle
191 verts_girdle
.append(len(verts
))
192 vec
= quat
@ Vector((girdle_radius
, 0.0, height_middle
))
196 faces_flat
= createFaces([vert_flat
], verts_flat
, closed
=True,
199 faces_side
= createFaces(verts_girdle
, verts_flat
, closed
=True)
201 faces_tip
= createFaces([vert_tip
], verts_girdle
, closed
=True)
203 faces
.extend(faces_tip
)
204 faces
.extend(faces_side
)
205 faces
.extend(faces_flat
)
210 class AddDiamond(Operator
, object_utils
.AddObjectHelper
):
211 bl_idname
= "mesh.primitive_diamond_add"
212 bl_label
= "Add Diamond"
213 bl_description
= "Construct a diamond mesh"
214 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
216 Diamond
: BoolProperty(name
= "Diamond",
218 description
= "Diamond")
220 #### change properties
221 name
: StringProperty(name
= "Name",
222 description
= "Name")
224 change
: BoolProperty(name
= "Change",
226 description
= "change Diamond")
228 segments
: IntProperty(
230 description
="Number of segments for the diamond",
235 girdle_radius
: FloatProperty(
236 name
="Girdle Radius",
237 description
="Girdle radius of the diamond",
242 table_radius
: FloatProperty(
244 description
="Girdle radius of the diamond",
249 crown_height
: FloatProperty(
251 description
="Crown height of the diamond",
256 pavilion_height
: FloatProperty(
257 name
="Pavilion Height",
258 description
="Pavilion height of the diamond",
264 def draw(self
, context
):
267 box
.prop(self
, "segments")
268 box
.prop(self
, "girdle_radius")
269 box
.prop(self
, "table_radius")
270 box
.prop(self
, "crown_height")
271 box
.prop(self
, "pavilion_height")
273 if self
.change
== False:
274 # generic transform props
276 box
.prop(self
, 'align', expand
=True)
277 box
.prop(self
, 'location', expand
=True)
278 box
.prop(self
, 'rotation', expand
=True)
280 def execute(self
, context
):
281 # turn off 'Enter Edit Mode'
282 use_enter_edit_mode
= bpy
.context
.preferences
.edit
.use_enter_edit_mode
283 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= False
285 if bpy
.context
.mode
== "OBJECT":
286 if context
.selected_objects
!= [] and context
.active_object
and \
287 (context
.active_object
.data
is not None) and ('Diamond' in context
.active_object
.data
.keys()) and \
288 (self
.change
== True):
289 obj
= context
.active_object
291 oldmeshname
= obj
.data
.name
293 verts
, faces
= add_diamond(self
.segments
,
297 self
.pavilion_height
)
298 mesh
= bpy
.data
.meshes
.new("TMP")
299 mesh
.from_pydata(verts
, [], faces
)
303 for material
in oldmesh
.materials
:
304 obj
.data
.materials
.append(material
)
306 bpy
.data
.meshes
.remove(oldmesh
)
307 obj
.data
.name
= oldmeshname
309 verts
, faces
= add_diamond(self
.segments
,
313 self
.pavilion_height
)
315 obj
= create_mesh_object(context
, self
, verts
, [], faces
, "Diamond")
317 obj
.data
["Diamond"] = True
318 obj
.data
["change"] = False
319 for prm
in DiamondParameters():
320 obj
.data
[prm
] = getattr(self
, prm
)
322 if bpy
.context
.mode
== "EDIT_MESH":
323 active_object
= context
.active_object
324 name_active_object
= active_object
.name
325 bpy
.ops
.object.mode_set(mode
='OBJECT')
326 verts
, faces
= add_diamond(self
.segments
,
330 self
.pavilion_height
)
332 obj
= create_mesh_object(context
, self
, verts
, [], faces
, "TMP")
335 active_object
.select_set(True)
336 bpy
.context
.view_layer
.objects
.active
= active_object
337 bpy
.ops
.object.join()
338 context
.active_object
.name
= name_active_object
339 bpy
.ops
.object.mode_set(mode
='EDIT')
341 if use_enter_edit_mode
:
342 bpy
.ops
.object.mode_set(mode
= 'EDIT')
344 # restore pre operator state
345 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= use_enter_edit_mode
349 def DiamondParameters():
350 DiamondParameters
= [
357 return DiamondParameters
360 class AddGem(Operator
, object_utils
.AddObjectHelper
):
361 bl_idname
= "mesh.primitive_gem_add"
363 bl_description
= "Construct an offset faceted gem mesh"
364 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
366 Gem
: BoolProperty(name
= "Gem",
370 #### change properties
371 name
: StringProperty(name
= "Name",
372 description
= "Name")
374 change
: BoolProperty(name
= "Change",
376 description
= "change Gem")
378 segments
: IntProperty(
380 description
="Longitudial segmentation",
385 pavilion_radius
: FloatProperty(
387 description
="Radius of the gem",
392 crown_radius
: FloatProperty(
394 description
="Radius of the table(top)",
399 crown_height
: FloatProperty(
401 description
="Height of the top half",
406 pavilion_height
: FloatProperty(
407 name
="Pavilion height",
408 description
="Height of bottom half",
414 def draw(self
, context
):
417 box
.prop(self
, "segments")
418 box
.prop(self
, "pavilion_radius")
419 box
.prop(self
, "crown_radius")
420 box
.prop(self
, "crown_height")
421 box
.prop(self
, "pavilion_height")
423 if self
.change
== False:
424 # generic transform props
426 box
.prop(self
, 'align', expand
=True)
427 box
.prop(self
, 'location', expand
=True)
428 box
.prop(self
, 'rotation', expand
=True)
430 def execute(self
, context
):
431 # turn off 'Enter Edit Mode'
432 use_enter_edit_mode
= bpy
.context
.preferences
.edit
.use_enter_edit_mode
433 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= False
435 if bpy
.context
.mode
== "OBJECT":
436 if context
.selected_objects
!= [] and context
.active_object
and \
437 (context
.active_object
.data
is not None) and ('Gem' in context
.active_object
.data
.keys()) and \
438 (self
.change
== True):
439 obj
= context
.active_object
441 oldmeshname
= obj
.data
.name
442 verts
, faces
= add_gem(
443 self
.pavilion_radius
,
446 self
.pavilion_height
,
448 mesh
= bpy
.data
.meshes
.new("TMP")
449 mesh
.from_pydata(verts
, [], faces
)
452 for material
in oldmesh
.materials
:
453 obj
.data
.materials
.append(material
)
454 bpy
.data
.meshes
.remove(oldmesh
)
455 obj
.data
.name
= oldmeshname
457 verts
, faces
= add_gem(
458 self
.pavilion_radius
,
461 self
.pavilion_height
,
464 obj
= create_mesh_object(context
, self
, verts
, [], faces
, "Gem")
466 obj
.data
["Gem"] = True
467 obj
.data
["change"] = False
468 for prm
in GemParameters():
469 obj
.data
[prm
] = getattr(self
, prm
)
471 if bpy
.context
.mode
== "EDIT_MESH":
472 active_object
= context
.active_object
473 name_active_object
= active_object
.name
474 bpy
.ops
.object.mode_set(mode
='OBJECT')
475 verts
, faces
= add_gem(
476 self
.pavilion_radius
,
479 self
.pavilion_height
,
482 obj
= create_mesh_object(context
, self
, verts
, [], faces
, "TMP")
485 active_object
.select_set(True)
486 bpy
.context
.view_layer
.objects
.active
= active_object
487 bpy
.ops
.object.join()
488 context
.active_object
.name
= name_active_object
489 bpy
.ops
.object.mode_set(mode
='EDIT')
491 if use_enter_edit_mode
:
492 bpy
.ops
.object.mode_set(mode
= 'EDIT')
494 # restore pre operator state
495 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= use_enter_edit_mode