Cleanup: camera_turnaround (pep8)
[blender-addons.git] / add_mesh_extra_objects / add_mesh_gemstones.py
blobc47e4131d58d747133e14ef77fd81d3d9c84e298
1 # GPL # "author": "Pontiac, Fourmadmen, Dreampainter"
3 import bpy
4 from bpy.types import Operator
5 from mathutils import (
6 Vector,
7 Quaternion,
9 from math import cos, sin, pi
10 from bpy.props import (
11 FloatProperty,
12 IntProperty,
13 BoolProperty,
14 StringProperty,
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):
25 # Create new mesh
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.
32 mesh.update()
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):
41 faces = []
43 if not vertIdx1 or not vertIdx2:
44 return None
46 if len(vertIdx1) < 2 and len(vertIdx2) < 2:
47 return None
49 fan = False
50 if (len(vertIdx1) != len(vertIdx2)):
51 if (len(vertIdx1) == 1 and len(vertIdx2) > 1):
52 fan = True
53 else:
54 return None
56 total = len(vertIdx2)
58 if closed:
59 # Bridge the start with the end
60 if flipped:
61 face = [
62 vertIdx1[0],
63 vertIdx2[0],
64 vertIdx2[total - 1]]
65 if not fan:
66 face.append(vertIdx1[total - 1])
67 faces.append(face)
69 else:
70 face = [vertIdx2[0], vertIdx1[0]]
71 if not fan:
72 face.append(vertIdx1[total - 1])
73 face.append(vertIdx2[total - 1])
74 faces.append(face)
76 # Bridge the rest of the faces
77 for num in range(total - 1):
78 if flipped:
79 if fan:
80 face = [vertIdx2[num], vertIdx1[0], vertIdx2[num + 1]]
81 else:
82 face = [vertIdx2[num], vertIdx1[num],
83 vertIdx1[num + 1], vertIdx2[num + 1]]
84 faces.append(face)
85 else:
86 if fan:
87 face = [vertIdx1[0], vertIdx2[num], vertIdx2[num + 1]]
88 else:
89 face = [vertIdx1[num], vertIdx2[num],
90 vertIdx2[num + 1], vertIdx1[num + 1]]
91 faces.append(face)
93 return faces
96 # @todo Clean up vertex&face creation process a bit.
97 def add_gem(r1, r2, seg, h1, h2):
98 """
99 r1 = pavilion radius
100 r2 = crown radius
101 seg = number of segments
102 h1 = pavilion height
103 h2 = crown height
104 Generates the vertices and faces of the gem
107 verts = []
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
117 # Tip
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)))
125 edgeloop_flat = []
126 for i in range(seg):
127 s1 = sin(i * a)
128 s2 = sin(offset + i * a)
129 c1 = cos(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
138 faces = []
140 for index in range(seg):
141 i = index * 4
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)
151 faces.extend(faces_flat)
153 return verts, faces
156 def add_diamond(segments, girdle_radius, table_radius,
157 crown_height, pavilion_height):
159 PI_2 = pi * 2.0
160 z_axis = (0.0, 0.0, -1.0)
162 verts = []
163 faces = []
165 height_flat = crown_height
166 height_middle = 0.0
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)))
173 # Tip
174 vert_tip = len(verts)
175 verts.append(Vector((0.0, 0.0, height_tip)))
177 verts_flat = []
178 verts_girdle = []
180 for index in range(segments):
181 quat = Quaternion(z_axis, (index / segments) * PI_2)
183 # angle = PI_2 * index / segments # UNUSED
185 # Row for flat side
186 verts_flat.append(len(verts))
187 vec = quat @ Vector((table_radius, 0.0, height_flat))
188 verts.append(vec)
190 # Row for the middle/girdle
191 verts_girdle.append(len(verts))
192 vec = quat @ Vector((girdle_radius, 0.0, height_middle))
193 verts.append(vec)
195 # Flat face
196 faces_flat = createFaces([vert_flat], verts_flat, closed=True,
197 flipped=True)
198 # Side face
199 faces_side = createFaces(verts_girdle, verts_flat, closed=True)
200 # Tip faces
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)
207 return verts, faces
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",
217 default = True,
218 description = "Diamond")
220 #### change properties
221 name : StringProperty(name = "Name",
222 description = "Name")
224 change : BoolProperty(name = "Change",
225 default = False,
226 description = "change Diamond")
228 segments: IntProperty(
229 name="Segments",
230 description="Number of segments for the diamond",
231 min=3,
232 max=256,
233 default=32
235 girdle_radius: FloatProperty(
236 name="Girdle Radius",
237 description="Girdle radius of the diamond",
238 min=0.01,
239 max=9999.0,
240 default=1.0
242 table_radius: FloatProperty(
243 name="Table Radius",
244 description="Girdle radius of the diamond",
245 min=0.01,
246 max=9999.0,
247 default=0.6
249 crown_height: FloatProperty(
250 name="Crown Height",
251 description="Crown height of the diamond",
252 min=0.01,
253 max=9999.0,
254 default=0.35
256 pavilion_height: FloatProperty(
257 name="Pavilion Height",
258 description="Pavilion height of the diamond",
259 min=0.01,
260 max=9999.0,
261 default=0.8
264 def draw(self, context):
265 layout = self.layout
266 box = layout.box()
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
275 box = layout.box()
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 ('Diamond' in context.active_object.data.keys()) and (self.change == True):
288 obj = context.active_object
289 oldmesh = obj.data
290 oldmeshname = obj.data.name
292 verts, faces = add_diamond(self.segments,
293 self.girdle_radius,
294 self.table_radius,
295 self.crown_height,
296 self.pavilion_height)
297 mesh = bpy.data.meshes.new("TMP")
298 mesh.from_pydata(verts, [], faces)
299 mesh.update()
300 obj.data = mesh
302 for material in oldmesh.materials:
303 obj.data.materials.append(material)
305 bpy.data.meshes.remove(oldmesh)
306 obj.data.name = oldmeshname
307 else:
308 verts, faces = add_diamond(self.segments,
309 self.girdle_radius,
310 self.table_radius,
311 self.crown_height,
312 self.pavilion_height)
314 obj = create_mesh_object(context, self, verts, [], faces, "Diamond")
316 obj.data["Diamond"] = True
317 obj.data["change"] = False
318 for prm in DiamondParameters():
319 obj.data[prm] = getattr(self, prm)
321 if bpy.context.mode == "EDIT_MESH":
322 active_object = context.active_object
323 name_active_object = active_object.name
324 bpy.ops.object.mode_set(mode='OBJECT')
325 verts, faces = add_diamond(self.segments,
326 self.girdle_radius,
327 self.table_radius,
328 self.crown_height,
329 self.pavilion_height)
331 obj = create_mesh_object(context, self, verts, [], faces, "TMP")
333 obj.select_set(True)
334 active_object.select_set(True)
335 bpy.ops.object.join()
336 context.active_object.name = name_active_object
337 bpy.ops.object.mode_set(mode='EDIT')
339 if use_enter_edit_mode:
340 bpy.ops.object.mode_set(mode = 'EDIT')
342 # restore pre operator state
343 bpy.context.preferences.edit.use_enter_edit_mode = use_enter_edit_mode
345 return {'FINISHED'}
347 def DiamondParameters():
348 DiamondParameters = [
349 "segments",
350 "girdle_radius",
351 "table_radius",
352 "crown_height",
353 "pavilion_height",
355 return DiamondParameters
358 class AddGem(Operator, object_utils.AddObjectHelper):
359 bl_idname = "mesh.primitive_gem_add"
360 bl_label = "Add Gem"
361 bl_description = "Construct an offset faceted gem mesh"
362 bl_options = {'REGISTER', 'UNDO', 'PRESET'}
364 Gem : BoolProperty(name = "Gem",
365 default = True,
366 description = "Gem")
368 #### change properties
369 name : StringProperty(name = "Name",
370 description = "Name")
372 change : BoolProperty(name = "Change",
373 default = False,
374 description = "change Gem")
376 segments: IntProperty(
377 name="Segments",
378 description="Longitudial segmentation",
379 min=3,
380 max=265,
381 default=8
383 pavilion_radius: FloatProperty(
384 name="Radius",
385 description="Radius of the gem",
386 min=0.01,
387 max=9999.0,
388 default=1.0
390 crown_radius: FloatProperty(
391 name="Table Radius",
392 description="Radius of the table(top)",
393 min=0.01,
394 max=9999.0,
395 default=0.6
397 crown_height: FloatProperty(
398 name="Table height",
399 description="Height of the top half",
400 min=0.01,
401 max=9999.0,
402 default=0.35
404 pavilion_height: FloatProperty(
405 name="Pavilion height",
406 description="Height of bottom half",
407 min=0.01,
408 max=9999.0,
409 default=0.8
412 def draw(self, context):
413 layout = self.layout
414 box = layout.box()
415 box.prop(self, "segments")
416 box.prop(self, "pavilion_radius")
417 box.prop(self, "crown_radius")
418 box.prop(self, "crown_height")
419 box.prop(self, "pavilion_height")
421 if self.change == False:
422 # generic transform props
423 box = layout.box()
424 box.prop(self, 'align', expand=True)
425 box.prop(self, 'location', expand=True)
426 box.prop(self, 'rotation', expand=True)
428 def execute(self, context):
429 # turn off 'Enter Edit Mode'
430 use_enter_edit_mode = bpy.context.preferences.edit.use_enter_edit_mode
431 bpy.context.preferences.edit.use_enter_edit_mode = False
433 if bpy.context.mode == "OBJECT":
434 if context.selected_objects != [] and context.active_object and \
435 ('Gem' in context.active_object.data.keys()) and (self.change == True):
436 obj = context.active_object
437 oldmesh = obj.data
438 oldmeshname = obj.data.name
439 verts, faces = add_gem(
440 self.pavilion_radius,
441 self.crown_radius,
442 self.segments,
443 self.pavilion_height,
444 self.crown_height)
445 mesh = bpy.data.meshes.new("TMP")
446 mesh.from_pydata(verts, [], faces)
447 mesh.update()
448 obj.data = mesh
449 for material in oldmesh.materials:
450 obj.data.materials.append(material)
451 bpy.data.meshes.remove(oldmesh)
452 obj.data.name = oldmeshname
453 else:
454 verts, faces = add_gem(
455 self.pavilion_radius,
456 self.crown_radius,
457 self.segments,
458 self.pavilion_height,
459 self.crown_height)
461 obj = create_mesh_object(context, self, verts, [], faces, "Gem")
463 obj.data["Gem"] = True
464 obj.data["change"] = False
465 for prm in GemParameters():
466 obj.data[prm] = getattr(self, prm)
468 if bpy.context.mode == "EDIT_MESH":
469 active_object = context.active_object
470 name_active_object = active_object.name
471 bpy.ops.object.mode_set(mode='OBJECT')
472 verts, faces = add_gem(
473 self.pavilion_radius,
474 self.crown_radius,
475 self.segments,
476 self.pavilion_height,
477 self.crown_height)
479 obj = create_mesh_object(context, self, verts, [], faces, "TMP")
481 obj.select_set(True)
482 active_object.select_set(True)
483 bpy.ops.object.join()
484 context.active_object.name = name_active_object
485 bpy.ops.object.mode_set(mode='EDIT')
487 if use_enter_edit_mode:
488 bpy.ops.object.mode_set(mode = 'EDIT')
490 # restore pre operator state
491 bpy.context.preferences.edit.use_enter_edit_mode = use_enter_edit_mode
493 return {'FINISHED'}
495 def GemParameters():
496 GemParameters = [
497 "segments",
498 "pavilion_radius",
499 "crown_radius",
500 "crown_height",
501 "pavilion_height",
503 return GemParameters