1 # SPDX-License-Identifier: GPL-2.0-or-later
2 # Author: Dominic Kröper, (dommetysk)
9 from bpy
.types
import Operator
10 from mathutils
import (
14 from bpy
.props
import (
20 from bpy_extras
import object_utils
22 # mesh generating function, returns mesh
23 def add_mesh_Brilliant(context
, s
, table_w
, crown_h
, girdle_t
, pavi_d
, bezel_f
,
24 pavi_f
, culet
, girdle_real
, keep_lga
, g_real_smooth
):
26 # # possible user inputs ( output 100% = 2 blender units )
27 # s # no. of girdle facets (steps) default: 16
28 # table_w # table width default: 0.530
29 # crown_h # crown height default: 0.162
30 # girdle_t # girdle thickness default: 0.017
31 # pavi_d # pavilion depth default: 0.431
32 # bezel_f # bezel factor default: 0.250
33 # pavi_f # pavilion factor default: 0.400
34 # culet # culet size default: 0.000
35 # girdle_real # type of girdle flat/real default: True
36 # g_real_smooth # smooth or flat shading default: False
37 # keep_lga # when culet > 0, keep lga default: False
39 # variables / shortcuts
40 if s
% 2: # prevent odd number of steps (messes up mesh)
44 ang
= 2 * pi
/ s
# angle step size
45 Verts
= [] # collect all vertices
46 Faces
= [] # collect all faces
53 def fa(*vs
): # shortcut Faces.append
59 def va(vx
, vz
, iang
, sang
, n
): # shortcut Verts.append
61 v
= Vector((vx
, 0, vz
))
63 E_rot
= Euler((0, 0, ai
), 'XYZ')
65 Verts
.append((v
.x
, v
.y
, v
.z
))
68 uga
= (1 - bezel_f
) * crown_h
* 2 / (ca2
-
69 (table_w
+ (1 - table_w
) * bezel_f
) * ca2
/ ca
)
73 if pavi_f
> 0 and pavi_f
< 1:
74 lga
= (1 - pavi_f
) * pavi_d
* 2 / (ca2
- pavi_f
* ca2
/ ca
)
80 lga
= (1 - pavi_f
) * pavi_d
* 2 / (ca2
-
81 (culet
+ (1 - culet
) * pavi_f
) * ca2
/ ca
)
83 # append girdle vertices
85 va(1, 2 * girdle_t
, ang
, 0, s
)
87 # append real girdle vertices
90 dfu
= uga
* (ta8
+ ta4
) * sa4
92 dfl
= lga
* (ta8
+ ta4
) * sa4
93 if abs(dnu
) + abs(dnl
) > 2 * girdle_t
or dnu
< 0 or dnl
< 0:
96 va(1, dnl
, ang
, ang
/ 2, s
)
97 va(1, 2 * girdle_t
- dnu
, ang
, ang
/ 2, s
)
98 va(1, dfl
, ang
/ 2, ang
/ 4, 2 * s
)
99 va(1, 2 * girdle_t
- dfu
, ang
/ 2, ang
/ 4, 2 * s
)
102 l1
= len(Verts
) # 2*s / 8*s
106 fa(i
, i
+ s
, 2 * i
+ 6 * s
, 2 * i
+ 4 * s
)
108 fa(i
, s
, l1
- 1, 6 * s
- 1)
110 fa(i
, i
+ s
, 2 * i
+ 6 * s
- 1, 2 * i
+ 4 * s
- 1)
111 elif i
> 2 * s
- 1 and i
< 3 * s
:
112 fa(i
, i
+ s
, 2 * (i
+ s
), 2 * i
)
113 fa(i
, i
+ s
, 2 * (i
+ s
) + 1, 2 * i
+ 1)
116 fa(i
, i
+ s
, i
+ s
+ 1, i
+ 1)
120 # append upper girdle facet vertices
121 va((table_w
+ (1 - table_w
) * bezel_f
) / ca
, (1 - bezel_f
) * 2 * crown_h
+
122 2 * girdle_t
, 2 * ang
, ang
, int(s
/ 2))
124 # make upper girdle facet faces
125 l2
= len(Verts
) # 2.5*s / 8.5*s
127 if i
> s
and i
< 2 * s
- 1 and i
% 2 != 0:
129 fa(i
, 2 * (i
+ 2 * s
), i
+ 2 * s
, 2 * (i
+ 2 * s
) + 1, i
+ 1,
130 int(7.5 * s
) + int((i
- 1) / 2))
131 fa(i
, 2 * (i
+ 2 * s
) - 1, i
+ 2 * s
- 1, 2 * (i
+ 2 * s
- 1),
132 i
- 1, int(7.5 * s
) + int((i
- 1) / 2))
134 fa(i
, i
+ 1, int((i
+ 3 * s
) / 2))
135 fa(i
, i
- 1, int((i
+ 3 * s
) / 2))
138 fa(i
, l1
- 1, 4 * s
- 1, l1
- 2, 2 * i
- 1, l2
- 1)
139 fa(2 * i
- 2, l1
- 4, 4 * s
- 2, l1
- 3, 2 * i
- 1, l2
- 1)
141 fa(i
, 2 * i
- 1, l2
- 1)
142 fa(2 * i
- 1, 2 * i
- 2, l2
- 1)
144 # append table vertices
145 va(table_w
, (crown_h
+ girdle_t
) * 2, 2 * ang
, 0, int(s
/ 2))
147 # make bezel facet faces and star facet faces
148 l3
= len(Verts
) # 3*s / 9*s
150 if i
> l2
- 1 and i
< l3
- 1:
151 fa(i
, i
+ 1, i
- int(s
/ 2))
152 fa(i
+ 1, i
- int(s
/ 2), 2 * (i
- l2
) + 2 + s
, i
- int(s
/ 2) + 1)
155 fa(s
, l2
- 1, l2
, l2
- int(s
/ 2))
157 # make table facet face
164 # append lower girdle facet vertices
166 va(pavi_f
/ ca
, (pavi_f
- 1) * pavi_d
* 2, 2 * ang
, ang
, int(s
/ 2))
168 va((pavi_f
* (1 - culet
) + culet
) / ca
, (pavi_f
- 1) * pavi_d
* 2, 2 * ang
,
171 # make lower girdle facet faces
172 l4
= len(Verts
) # 3.5*s / 9.5*s
174 if i
> 0 and i
< s
- 1 and i
% 2 == 0:
176 fa(i
, 2 * (i
+ 2 * s
), i
+ 2 * s
, 2 * (i
+ 2 * s
) + 1, i
+ 1,
178 fa(i
, 2 * (i
+ 2 * s
) - 1, i
+ 2 * s
- 1, 2 * (i
+ 2 * s
- 1),
179 i
- 1, int(i
/ 2) + 9 * s
- 1)
181 fa(i
, i
+ 1, int(i
/ 2) + l4
- int(s
/ 2))
182 fa(i
, i
- 1, int(i
/ 2) + l4
- int(s
/ 2) - 1)
185 fa(0, 4 * s
, 2 * s
, 4 * s
+ 1, 1, 9 * s
)
186 fa(0, 6 * s
- 1, 3 * s
- 1, 6 * s
- 2, s
- 1, l4
- 1)
188 fa(0, 1, l4
- int(s
/ 2))
191 # append culet vertice(s)
193 va(0, pavi_d
* (-2), 0, 0, 1)
196 va(culet
* pavi_f
/ ca
, pavi_d
* (-2) + culet
* pavi_f
* 2 * pavi_d
,
197 2 * ang
, ang
, int(s
/ 2))
199 va(culet
/ ca
, pavi_d
* (-2), 2 * ang
, ang
, int(s
/ 2))
201 # make pavilion facet face
202 l5
= len(Verts
) # 4*s / 10*s //if !culet: 3.5*s+1 / 9.5*s+1
204 if i
> 0 and i
< s
- 1 and i
% 2 == 0:
206 fa(i
, l3
+ int(i
/ 2), l3
+ int((s
+ i
) / 2),
207 l3
+ int((s
+ i
) / 2) - 1, l3
+ int(i
/ 2) - 1)
209 fa(i
, l3
+ int(i
/ 2), l5
- 1, l3
+ int(i
/ 2) - 1)
212 fa(i
, l3
, l4
, l5
- 1, l4
- 1)
214 fa(i
, l3
, l5
- 1, l4
- 1)
216 # make culet facet face
224 # create actual mesh and object based on Verts and Faces given
225 dmesh
= bpy
.data
.meshes
.new("dmesh")
226 dmesh
.from_pydata(Verts
, [], Faces
)
231 # object generating function, returns final object
232 def addBrilliant(context
, self
, s
, table_w
, crown_h
, girdle_t
, pavi_d
, bezel_f
,
233 pavi_f
, culet
, girdle_real
, keep_lga
, g_real_smooth
):
235 # deactivate possible active Objects
236 bpy
.context
.view_layer
.objects
.active
= None
238 # create actual mesh and object based on Verts and Faces given
239 dmesh
= add_mesh_Brilliant(context
, s
, table_w
, crown_h
, girdle_t
, pavi_d
, bezel_f
,
240 pavi_f
, culet
, girdle_real
, keep_lga
, g_real_smooth
)
242 # Create object and link it into scene.
243 dobj
= object_utils
.object_data_add(context
, dmesh
, operator
=self
, name
="dobj")
245 # activate and select object
246 bpy
.context
.view_layer
.objects
.active
= dobj
247 dobj
.select_set(True)
248 obj
= bpy
.context
.active_object
250 # flip all face normals outside
251 bpy
.ops
.object.mode_set(mode
='EDIT', toggle
=False)
252 sel_mode
= bpy
.context
.tool_settings
.mesh_select_mode
253 bpy
.context
.tool_settings
.mesh_select_mode
= [False, False, True]
254 bpy
.ops
.object.mode_set(mode
='OBJECT', toggle
=False)
255 for i
, face
in enumerate(obj
.data
.polygons
):
257 bpy
.ops
.object.mode_set(mode
='EDIT', toggle
=False)
258 bpy
.ops
.mesh
.normals_make_consistent(inside
=False)
259 bpy
.context
.tool_settings
.mesh_select_mode
= sel_mode
260 bpy
.ops
.object.mode_set(mode
='OBJECT', toggle
=False)
262 # make girdle smooth for complex girdle
263 if girdle_real
and g_real_smooth
:
265 bpy
.ops
.object.mode_set(mode
='EDIT', toggle
=False)
267 bpy
.ops
.mesh
.select_all(action
='DESELECT') # deselect all mesh data
268 bpy
.ops
.object.mode_set(mode
='OBJECT')
270 dp
= obj
.data
.polygons
[:4 * s
] # only consider faces of girdle
271 ov
= obj
.data
.vertices
273 for i
, p
in enumerate(dp
):
274 pls
.extend(p
.vertices
) # list all verts of girdle
276 for i
, e
in enumerate(obj
.data
.edges
): # select edges to mark sharp
277 if e
.vertices
[0] in pls
and e
.vertices
[1] in pls
and abs(
278 ov
[e
.vertices
[0]].co
.x
- ov
[e
.vertices
[1]].co
.x
):
279 obj
.data
.edges
[i
].select
= True
281 obj
.data
.edges
[i
].select
= False
283 bpy
.ops
.object.mode_set(mode
='EDIT', toggle
=False)
284 bpy
.ops
.mesh
.mark_sharp()
286 bpy
.context
.tool_settings
.mesh_select_mode
= [False, False, True]
287 bpy
.ops
.object.mode_set(mode
='OBJECT', toggle
=False)
288 bpy
.ops
.object.select_all(action
='DESELECT')
289 for i
, face
in enumerate(obj
.data
.polygons
):
294 bpy
.ops
.object.mode_set(mode
='EDIT', toggle
=False)
295 bpy
.ops
.mesh
.faces_shade_smooth()
297 bpy
.ops
.object.modifier_add(type='EDGE_SPLIT')
299 bpy
.context
.tool_settings
.mesh_select_mode
= sel_mode
300 bpy
.ops
.object.mode_set(mode
='OBJECT', toggle
=False)
302 bpy
.ops
.object.modifier_apply(modifier
="EdgeSplit")
307 # add new operator for object
308 class MESH_OT_primitive_brilliant_add(Operator
, object_utils
.AddObjectHelper
):
309 bl_idname
= "mesh.primitive_brilliant_add"
310 bl_label
= "Custom Brilliant"
311 bl_description
= "Construct a custom brilliant mesh"
312 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
314 Brilliant
: BoolProperty(name
= "Brilliant",
316 description
= "Brilliant")
317 change
: BoolProperty(name
= "Change",
319 description
= "change Brilliant")
323 description
="Longitudial segmentation",
330 table_w
: FloatProperty(
332 description
="Width of table",
338 crown_h
: FloatProperty(
340 description
="Height of crown",
346 girdle_t
: FloatProperty(
347 name
="Girdle height",
348 description
="Height of girdle",
354 girdle_real
: BoolProperty(
356 description
="More beautiful girdle; has more polygons",
359 g_real_smooth
: BoolProperty(
360 name
="Smooth girdle",
361 description
="smooth shading for girdle, only available for real girdle",
364 pavi_d
: FloatProperty(
365 name
="Pavilion depth",
366 description
="Height of pavilion",
372 bezel_f
: FloatProperty(
373 name
="Upper facet factor",
374 description
="Determines the form of bezel and upper girdle facets",
380 pavi_f
: FloatProperty(
381 name
="Lower facet factor",
382 description
="Determines the form of pavilion and lower girdle facets",
388 culet
: FloatProperty(
390 description
="0: no culet (default)",
396 keep_lga
: BoolProperty(
397 name
="Retain lower angle",
398 description
="If culet > 0, retains angle of pavilion facets",
402 def draw(self
, context
):
406 box
.prop(self
, "table_w")
407 box
.prop(self
, "crown_h")
408 box
.prop(self
, "girdle_t")
409 box
.prop(self
, "girdle_real")
410 box
.prop(self
, "g_real_smooth")
411 box
.prop(self
, "pavi_d")
412 box
.prop(self
, "bezel_f")
413 box
.prop(self
, "pavi_f")
414 box
.prop(self
, "culet")
415 box
.prop(self
, "keep_lga")
417 if self
.change
== False:
418 # generic transform props
420 box
.prop(self
, 'align', expand
=True)
421 box
.prop(self
, 'location', expand
=True)
422 box
.prop(self
, 'rotation', expand
=True)
424 # call mesh/object generator function with user inputs
425 def execute(self
, context
):
426 # turn off 'Enter Edit Mode'
427 use_enter_edit_mode
= bpy
.context
.preferences
.edit
.use_enter_edit_mode
428 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= False
430 if bpy
.context
.mode
== "OBJECT":
431 if context
.selected_objects
!= [] and context
.active_object
and \
432 (context
.active_object
.data
is not None) and ('Brilliant' in context
.active_object
.data
.keys()) and \
433 (self
.change
== True):
434 obj
= context
.active_object
436 oldmeshname
= obj
.data
.name
437 mesh
= add_mesh_Brilliant(context
, self
.s
, self
.table_w
, self
.crown_h
,
438 self
.girdle_t
, self
.pavi_d
, self
.bezel_f
,
439 self
.pavi_f
, self
.culet
, self
.girdle_real
,
440 self
.keep_lga
, self
.g_real_smooth
443 for material
in oldmesh
.materials
:
444 obj
.data
.materials
.append(material
)
445 bpy
.data
.meshes
.remove(oldmesh
)
446 obj
.data
.name
= oldmeshname
448 obj
= addBrilliant(context
, self
, self
.s
, self
.table_w
, self
.crown_h
,
449 self
.girdle_t
, self
.pavi_d
, self
.bezel_f
,
450 self
.pavi_f
, self
.culet
, self
.girdle_real
,
451 self
.keep_lga
, self
.g_real_smooth
454 obj
.data
["Brilliant"] = True
455 obj
.data
["change"] = False
456 for prm
in BrilliantParameters():
457 obj
.data
[prm
] = getattr(self
, prm
)
459 if bpy
.context
.mode
== "EDIT_MESH":
460 active_object
= context
.active_object
461 name_active_object
= active_object
.name
462 bpy
.ops
.object.mode_set(mode
='OBJECT')
463 obj
= addBrilliant(context
, self
, self
.s
, self
.table_w
, self
.crown_h
,
464 self
.girdle_t
, self
.pavi_d
, self
.bezel_f
,
465 self
.pavi_f
, self
.culet
, self
.girdle_real
,
466 self
.keep_lga
, self
.g_real_smooth
469 active_object
.select_set(True)
470 bpy
.context
.view_layer
.objects
.active
= active_object
471 bpy
.ops
.object.join()
472 context
.active_object
.name
= name_active_object
473 bpy
.ops
.object.mode_set(mode
='EDIT')
475 if use_enter_edit_mode
:
476 bpy
.ops
.object.mode_set(mode
= 'EDIT')
478 # restore pre operator state
479 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= use_enter_edit_mode
483 def BrilliantParameters():
484 BrilliantParameters
= [
497 return BrilliantParameters