Import_3ds: Improved distance cue node setup
[blender-addons.git] / add_mesh_extra_objects / add_mesh_round_brilliant.py
blob5fefbd657c041a2ca5244c7b1460319efb2acd82
1 # SPDX-FileCopyrightText: 2015-2023 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 import bpy
6 from math import (
7 pi, sin,
8 cos, tan,
10 from bpy.types import Operator
11 from mathutils import (
12 Vector,
13 Euler,
15 from bpy.props import (
16 IntProperty,
17 FloatProperty,
18 BoolProperty,
19 StringProperty,
21 from bpy_extras import object_utils
23 # mesh generating function, returns mesh
24 def add_mesh_Brilliant(context, s, table_w, crown_h, girdle_t, pavi_d, bezel_f,
25 pavi_f, culet, girdle_real, keep_lga, g_real_smooth):
27 # # possible user inputs ( output 100% = 2 blender units )
28 # s # no. of girdle facets (steps) default: 16
29 # table_w # table width default: 0.530
30 # crown_h # crown height default: 0.162
31 # girdle_t # girdle thickness default: 0.017
32 # pavi_d # pavilion depth default: 0.431
33 # bezel_f # bezel factor default: 0.250
34 # pavi_f # pavilion factor default: 0.400
35 # culet # culet size default: 0.000
36 # girdle_real # type of girdle flat/real default: True
37 # g_real_smooth # smooth or flat shading default: False
38 # keep_lga # when culet > 0, keep lga default: False
40 # variables / shortcuts
41 if s % 2: # prevent odd number of steps (messes up mesh)
42 s = s - 1
43 if not girdle_real:
44 g_real_smooth = False
45 ang = 2 * pi / s # angle step size
46 Verts = [] # collect all vertices
47 Faces = [] # collect all faces
48 ca = cos(ang)
49 ca2 = cos(ang / 2)
50 sa4 = sin(ang / 4)
51 ta4 = tan(ang / 4)
52 ta8 = tan(ang / 8)
54 def fa(*vs): # shortcut Faces.append
55 v = []
56 for u in vs:
57 v.append(u)
58 Faces.append(v)
60 def va(vx, vz, iang, sang, n): # shortcut Verts.append
61 for i in range(n):
62 v = Vector((vx, 0, vz))
63 ai = sang + iang * i
64 E_rot = Euler((0, 0, ai), 'XYZ')
65 v.rotate(E_rot)
66 Verts.append((v.x, v.y, v.z))
68 # upper girdle angle
69 uga = (1 - bezel_f) * crown_h * 2 / (ca2 -
70 (table_w + (1 - table_w) * bezel_f) * ca2 / ca)
72 # lower girdle angle
73 if keep_lga:
74 if pavi_f > 0 and pavi_f < 1:
75 lga = (1 - pavi_f) * pavi_d * 2 / (ca2 - pavi_f * ca2 / ca)
76 elif pavi_f == 1:
77 lga = 0
78 else:
79 lga = 2 * pavi_d * ca
80 else:
81 lga = (1 - pavi_f) * pavi_d * 2 / (ca2 -
82 (culet + (1 - culet) * pavi_f) * ca2 / ca)
84 # append girdle vertices
85 va(1, 0, ang, 0, s)
86 va(1, 2 * girdle_t, ang, 0, s)
88 # append real girdle vertices
89 if girdle_real:
90 dnu = uga * (1 - ca2)
91 dfu = uga * (ta8 + ta4) * sa4
92 dnl = lga * (1 - ca2)
93 dfl = lga * (ta8 + ta4) * sa4
94 if abs(dnu) + abs(dnl) > 2 * girdle_t or dnu < 0 or dnl < 0:
95 girdle_real = False
96 else:
97 va(1, dnl, ang, ang / 2, s)
98 va(1, 2 * girdle_t - dnu, ang, ang / 2, s)
99 va(1, dfl, ang / 2, ang / 4, 2 * s)
100 va(1, 2 * girdle_t - dfu, ang / 2, ang / 4, 2 * s)
102 # make girdle faces
103 l1 = len(Verts) # 2*s / 8*s
104 for i in range(l1):
105 if girdle_real:
106 if i < s:
107 fa(i, i + s, 2 * i + 6 * s, 2 * i + 4 * s)
108 if i == 0:
109 fa(i, s, l1 - 1, 6 * s - 1)
110 else:
111 fa(i, i + s, 2 * i + 6 * s - 1, 2 * i + 4 * s - 1)
112 elif i > 2 * s - 1 and i < 3 * s:
113 fa(i, i + s, 2 * (i + s), 2 * i)
114 fa(i, i + s, 2 * (i + s) + 1, 2 * i + 1)
115 else:
116 if i < s - 1:
117 fa(i, i + s, i + s + 1, i + 1)
118 elif i == s - 1:
119 fa(i, i + s, s, 0)
121 # append upper girdle facet vertices
122 va((table_w + (1 - table_w) * bezel_f) / ca, (1 - bezel_f) * 2 * crown_h +
123 2 * girdle_t, 2 * ang, ang, int(s / 2))
125 # make upper girdle facet faces
126 l2 = len(Verts) # 2.5*s / 8.5*s
127 for i in range(l2):
128 if i > s and i < 2 * s - 1 and i % 2 != 0:
129 if girdle_real:
130 fa(i, 2 * (i + 2 * s), i + 2 * s, 2 * (i + 2 * s) + 1, i + 1,
131 int(7.5 * s) + int((i - 1) / 2))
132 fa(i, 2 * (i + 2 * s) - 1, i + 2 * s - 1, 2 * (i + 2 * s - 1),
133 i - 1, int(7.5 * s) + int((i - 1) / 2))
134 else:
135 fa(i, i + 1, int((i + 3 * s) / 2))
136 fa(i, i - 1, int((i + 3 * s) / 2))
137 elif i == s:
138 if girdle_real:
139 fa(i, l1 - 1, 4 * s - 1, l1 - 2, 2 * i - 1, l2 - 1)
140 fa(2 * i - 2, l1 - 4, 4 * s - 2, l1 - 3, 2 * i - 1, l2 - 1)
141 else:
142 fa(i, 2 * i - 1, l2 - 1)
143 fa(2 * i - 1, 2 * i - 2, l2 - 1)
145 # append table vertices
146 va(table_w, (crown_h + girdle_t) * 2, 2 * ang, 0, int(s / 2))
148 # make bezel facet faces and star facet faces
149 l3 = len(Verts) # 3*s / 9*s
150 for i in range(l3):
151 if i > l2 - 1 and i < l3 - 1:
152 fa(i, i + 1, i - int(s / 2))
153 fa(i + 1, i - int(s / 2), 2 * (i - l2) + 2 + s, i - int(s / 2) + 1)
154 elif i == l3 - 1:
155 fa(i, l2, l2 - 1)
156 fa(s, l2 - 1, l2, l2 - int(s / 2))
158 # make table facet face
159 tf = []
160 for i in range(l3):
161 if i > l2 - 1:
162 tf.append(i)
163 fa(*tf)
165 # append lower girdle facet vertices
166 if keep_lga:
167 va(pavi_f / ca, (pavi_f - 1) * pavi_d * 2, 2 * ang, ang, int(s / 2))
168 else:
169 va((pavi_f * (1 - culet) + culet) / ca, (pavi_f - 1) * pavi_d * 2, 2 * ang,
170 ang, int(s / 2))
172 # make lower girdle facet faces
173 l4 = len(Verts) # 3.5*s / 9.5*s
174 for i in range(l4):
175 if i > 0 and i < s - 1 and i % 2 == 0:
176 if girdle_real:
177 fa(i, 2 * (i + 2 * s), i + 2 * s, 2 * (i + 2 * s) + 1, i + 1,
178 int(i / 2) + 9 * s)
179 fa(i, 2 * (i + 2 * s) - 1, i + 2 * s - 1, 2 * (i + 2 * s - 1),
180 i - 1, int(i / 2) + 9 * s - 1)
181 else:
182 fa(i, i + 1, int(i / 2) + l4 - int(s / 2))
183 fa(i, i - 1, int(i / 2) + l4 - int(s / 2) - 1)
184 elif i == 0:
185 if girdle_real:
186 fa(0, 4 * s, 2 * s, 4 * s + 1, 1, 9 * s)
187 fa(0, 6 * s - 1, 3 * s - 1, 6 * s - 2, s - 1, l4 - 1)
188 else:
189 fa(0, 1, l4 - int(s / 2))
190 fa(0, s - 1, l4 - 1)
192 # append culet vertice(s)
193 if culet == 0:
194 va(0, pavi_d * (-2), 0, 0, 1)
195 else:
196 if keep_lga:
197 va(culet * pavi_f / ca, pavi_d * (-2) + culet * pavi_f * 2 * pavi_d,
198 2 * ang, ang, int(s / 2))
199 else:
200 va(culet / ca, pavi_d * (-2), 2 * ang, ang, int(s / 2))
202 # make pavilion facet face
203 l5 = len(Verts) # 4*s / 10*s //if !culet: 3.5*s+1 / 9.5*s+1
204 for i in range(l5):
205 if i > 0 and i < s - 1 and i % 2 == 0:
206 if culet:
207 fa(i, l3 + int(i / 2), l3 + int((s + i) / 2),
208 l3 + int((s + i) / 2) - 1, l3 + int(i / 2) - 1)
209 else:
210 fa(i, l3 + int(i / 2), l5 - 1, l3 + int(i / 2) - 1)
211 elif i == 0:
212 if culet:
213 fa(i, l3, l4, l5 - 1, l4 - 1)
214 else:
215 fa(i, l3, l5 - 1, l4 - 1)
217 # make culet facet face
218 if culet:
219 cf = []
220 for i in range(l5):
221 if i > l4 - 1:
222 cf.append(i)
223 fa(*cf)
225 # create actual mesh and object based on Verts and Faces given
226 dmesh = bpy.data.meshes.new("dmesh")
227 dmesh.from_pydata(Verts, [], Faces)
228 dmesh.update()
230 return dmesh
232 # object generating function, returns final object
233 def addBrilliant(context, self, s, table_w, crown_h, girdle_t, pavi_d, bezel_f,
234 pavi_f, culet, girdle_real, keep_lga, g_real_smooth):
236 # deactivate possible active Objects
237 bpy.context.view_layer.objects.active = None
239 # create actual mesh and object based on Verts and Faces given
240 dmesh = add_mesh_Brilliant(context, s, table_w, crown_h, girdle_t, pavi_d, bezel_f,
241 pavi_f, culet, girdle_real, keep_lga, g_real_smooth)
243 # Create object and link it into scene.
244 dobj = object_utils.object_data_add(context, dmesh, operator=self, name="dobj")
246 # activate and select object
247 bpy.context.view_layer.objects.active = dobj
248 dobj.select_set(True)
249 obj = bpy.context.active_object
251 # flip all face normals outside
252 bpy.ops.object.mode_set(mode='EDIT', toggle=False)
253 sel_mode = bpy.context.tool_settings.mesh_select_mode
254 bpy.context.tool_settings.mesh_select_mode = [False, False, True]
255 bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
256 for i, face in enumerate(obj.data.polygons):
257 face.select = True
258 bpy.ops.object.mode_set(mode='EDIT', toggle=False)
259 bpy.ops.mesh.normals_make_consistent(inside=False)
260 bpy.context.tool_settings.mesh_select_mode = sel_mode
261 bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
263 # make girdle smooth for complex girdle
264 if girdle_real and g_real_smooth:
266 bpy.ops.object.mode_set(mode='EDIT', toggle=False)
268 bpy.ops.mesh.select_all(action='DESELECT') # deselect all mesh data
269 bpy.ops.object.mode_set(mode='OBJECT')
270 pls = []
271 dp = obj.data.polygons[:4 * s] # only consider faces of girdle
272 ov = obj.data.vertices
274 for i, p in enumerate(dp):
275 pls.extend(p.vertices) # list all verts of girdle
277 for i, e in enumerate(obj.data.edges): # select edges to mark sharp
278 if e.vertices[0] in pls and e.vertices[1] in pls and abs(
279 ov[e.vertices[0]].co.x - ov[e.vertices[1]].co.x):
280 obj.data.edges[i].select = True
281 continue
282 obj.data.edges[i].select = False
284 bpy.ops.object.mode_set(mode='EDIT', toggle=False)
285 bpy.ops.mesh.mark_sharp()
287 bpy.context.tool_settings.mesh_select_mode = [False, False, True]
288 bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
289 bpy.ops.object.select_all(action='DESELECT')
290 for i, face in enumerate(obj.data.polygons):
291 if i < 4 * s:
292 face.select = True
293 continue
294 face.select = False
295 bpy.ops.object.mode_set(mode='EDIT', toggle=False)
296 bpy.ops.mesh.faces_shade_smooth()
298 edge_split_modifier = context.object.modifiers.new("", 'EDGE_SPLIT')
300 bpy.context.tool_settings.mesh_select_mode = sel_mode
301 bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
303 bpy.ops.object.modifier_apply(modifier=edge_split_modifier.name)
305 return dobj
308 # add new operator for object
309 class MESH_OT_primitive_brilliant_add(Operator, object_utils.AddObjectHelper):
310 bl_idname = "mesh.primitive_brilliant_add"
311 bl_label = "Custom Brilliant"
312 bl_description = "Construct a custom brilliant mesh"
313 bl_options = {'REGISTER', 'UNDO', 'PRESET'}
315 Brilliant : BoolProperty(name = "Brilliant",
316 default = True,
317 description = "Brilliant")
318 change : BoolProperty(name = "Change",
319 default = False,
320 description = "change Brilliant")
322 s: IntProperty(
323 name="Segments",
324 description="Longitudial segmentation",
325 step=1,
326 min=6,
327 max=128,
328 default=16,
329 subtype='FACTOR'
331 table_w: FloatProperty(
332 name="Table width",
333 description="Width of table",
334 min=0.001,
335 max=1.0,
336 default=0.53,
337 subtype='PERCENTAGE'
339 crown_h: FloatProperty(
340 name="Crown height",
341 description="Height of crown",
342 min=0.0,
343 max=1.0,
344 default=0.162,
345 subtype='PERCENTAGE'
347 girdle_t: FloatProperty(
348 name="Girdle height",
349 description="Height of girdle",
350 min=0.0,
351 max=0.5,
352 default=0.017,
353 subtype='PERCENTAGE'
355 girdle_real: BoolProperty(
356 name="Real girdle",
357 description="More beautiful girdle; has more polygons",
358 default=True
360 g_real_smooth: BoolProperty(
361 name="Smooth girdle",
362 description="smooth shading for girdle, only available for real girdle",
363 default=False
365 pavi_d: FloatProperty(
366 name="Pavilion depth",
367 description="Height of pavilion",
368 min=0.0,
369 max=1.0,
370 default=0.431,
371 subtype='PERCENTAGE'
373 bezel_f: FloatProperty(
374 name="Upper facet factor",
375 description="Determines the form of bezel and upper girdle facets",
376 min=0.0,
377 max=1.0,
378 default=0.250,
379 subtype='PERCENTAGE'
381 pavi_f: FloatProperty(
382 name="Lower facet factor",
383 description="Determines the form of pavilion and lower girdle facets",
384 min=0.001,
385 max=1.0,
386 default=0.400,
387 subtype='PERCENTAGE'
389 culet: FloatProperty(
390 name="Culet size",
391 description="0: no culet (default)",
392 min=0.0,
393 max=0.999,
394 default=0.0,
395 subtype='PERCENTAGE'
397 keep_lga: BoolProperty(
398 name="Retain lower angle",
399 description="If culet > 0, retains angle of pavilion facets",
400 default=False
403 def draw(self, context):
404 layout = self.layout
405 box = layout.box()
406 box.prop(self, "s")
407 box.prop(self, "table_w")
408 box.prop(self, "crown_h")
409 box.prop(self, "girdle_t")
410 box.prop(self, "girdle_real")
411 box.prop(self, "g_real_smooth")
412 box.prop(self, "pavi_d")
413 box.prop(self, "bezel_f")
414 box.prop(self, "pavi_f")
415 box.prop(self, "culet")
416 box.prop(self, "keep_lga")
418 if self.change == False:
419 # generic transform props
420 box = layout.box()
421 box.prop(self, 'align', expand=True)
422 box.prop(self, 'location', expand=True)
423 box.prop(self, 'rotation', expand=True)
425 # call mesh/object generator function with user inputs
426 def execute(self, context):
427 # turn off 'Enter Edit Mode'
428 use_enter_edit_mode = bpy.context.preferences.edit.use_enter_edit_mode
429 bpy.context.preferences.edit.use_enter_edit_mode = False
431 if bpy.context.mode == "OBJECT":
432 if context.selected_objects != [] and context.active_object and \
433 (context.active_object.data is not None) and ('Brilliant' in context.active_object.data.keys()) and \
434 (self.change == True):
435 obj = context.active_object
436 oldmesh = obj.data
437 oldmeshname = obj.data.name
438 mesh = add_mesh_Brilliant(context, self.s, self.table_w, self.crown_h,
439 self.girdle_t, self.pavi_d, self.bezel_f,
440 self.pavi_f, self.culet, self.girdle_real,
441 self.keep_lga, self.g_real_smooth
443 obj.data = mesh
444 for material in oldmesh.materials:
445 obj.data.materials.append(material)
446 bpy.data.meshes.remove(oldmesh)
447 obj.data.name = oldmeshname
448 else:
449 obj = addBrilliant(context, self, self.s, self.table_w, self.crown_h,
450 self.girdle_t, self.pavi_d, self.bezel_f,
451 self.pavi_f, self.culet, self.girdle_real,
452 self.keep_lga, self.g_real_smooth
455 obj.data["Brilliant"] = True
456 obj.data["change"] = False
457 for prm in BrilliantParameters():
458 obj.data[prm] = getattr(self, prm)
460 if bpy.context.mode == "EDIT_MESH":
461 active_object = context.active_object
462 name_active_object = active_object.name
463 bpy.ops.object.mode_set(mode='OBJECT')
464 obj = addBrilliant(context, self, self.s, self.table_w, self.crown_h,
465 self.girdle_t, self.pavi_d, self.bezel_f,
466 self.pavi_f, self.culet, self.girdle_real,
467 self.keep_lga, self.g_real_smooth
469 obj.select_set(True)
470 active_object.select_set(True)
471 bpy.context.view_layer.objects.active = active_object
472 bpy.ops.object.join()
473 context.active_object.name = name_active_object
474 bpy.ops.object.mode_set(mode='EDIT')
476 if use_enter_edit_mode:
477 bpy.ops.object.mode_set(mode = 'EDIT')
479 # restore pre operator state
480 bpy.context.preferences.edit.use_enter_edit_mode = use_enter_edit_mode
482 return {'FINISHED'}
484 def BrilliantParameters():
485 BrilliantParameters = [
486 "s",
487 "table_w",
488 "crown_h",
489 "girdle_t",
490 "girdle_real",
491 "g_real_smooth",
492 "pavi_d",
493 "bezel_f",
494 "pavi_f",
495 "culet",
496 "keep_lga",
498 return BrilliantParameters