Fix #105009: AnimAll: Error when inserting key on string attribute
[blender-addons.git] / archimesh / achm_column_maker.py
blob88dc3507641c952a19c3b539d6b7821b6c1f0199
1 # SPDX-FileCopyrightText: 2016-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 # ----------------------------------------------------------
6 # Automatic generation of columns
7 # Author: Antonio Vazquez (antonioya)
9 # ----------------------------------------------------------
10 # noinspection PyUnresolvedReferences
11 import bpy
12 from math import cos, sin, radians, atan, sqrt
13 from bpy.props import BoolProperty, IntProperty, FloatProperty, FloatVectorProperty
14 from .achm_tools import *
17 # ------------------------------------------------------------------
18 # Define UI class
19 # Columns
20 # ------------------------------------------------------------------
21 class ARCHIMESH_OT_Column(bpy.types.Operator):
22 bl_idname = "mesh.archimesh_column"
23 bl_label = "Column"
24 bl_description = "Columns Generator"
25 bl_category = 'View'
26 bl_options = {'REGISTER', 'UNDO'}
28 # Define properties
29 model: bpy.props.EnumProperty(
30 name="Model",
31 items=(
32 ('1', "Circular", ""),
33 ('2', "Rectangular", ""),
35 description="Type of column",
37 keep_size: BoolProperty(
38 name="Keep radius equal",
39 description="Keep all radius (top, mid and bottom) to the same size",
40 default=True,
43 rad_top: FloatProperty(
44 name='Top radius',
45 min=0.001, max=10, default=0.15, precision=3,
46 description='Radius of the column in the top',
48 rad_mid: FloatProperty(
49 name='Middle radius',
50 min=0.001, max=10, default=0.15, precision=3,
51 description='Radius of the column in the middle',
53 shift: FloatProperty(
54 name='',
55 min=-1, max=1, default=0, precision=3,
56 description='Middle displacement',
59 rad_bottom: FloatProperty(
60 name='Bottom radius',
61 min=0.001, max=10, default=0.15, precision=3,
62 description='Radius of the column in the bottom',
65 col_height: FloatProperty(
66 name='Total height',
67 min=0.001, max=10, default=2.4, precision=3,
68 description='Total height of column, including bases and tops',
70 col_sx: FloatProperty(
71 name='X size',
72 min=0.001, max=10, default=0.30, precision=3,
73 description='Column size for x axis',
75 col_sy: FloatProperty(
76 name='Y size',
77 min=0.001, max=10, default=0.30, precision=3,
78 description='Column size for y axis',
81 cir_base: BoolProperty(
82 name="Include circular base",
83 description="Include a base with circular form",
84 default=False,
86 cir_base_r: FloatProperty(
87 name='Radio',
88 min=0.001, max=10, default=0.08, precision=3,
89 description='Rise up radio of base',
91 cir_base_z: FloatProperty(
92 name='Height',
93 min=0.001, max=10, default=0.05, precision=3,
94 description='Size for z axis',
97 cir_top: BoolProperty(
98 name="Include circular top",
99 description="Include a top with circular form",
100 default=False,
102 cir_top_r: FloatProperty(
103 name='Radio',
104 min=0.001, max=10, default=0.08, precision=3,
105 description='Rise up radio of top',
107 cir_top_z: FloatProperty(
108 name='Height',
109 min=0.001, max=10, default=0.05, precision=3,
110 description='Size for z axis',
113 box_base: BoolProperty(
114 name="Include rectangular base",
115 description="Include a base with rectangular form",
116 default=True,
118 box_base_x: FloatProperty(
119 name='X size',
120 min=0.001, max=10, default=0.40, precision=3,
121 description='Size for x axis',
123 box_base_y: FloatProperty(
124 name='Y size',
125 min=0.001, max=10, default=0.40, precision=3,
126 description='Size for y axis',
128 box_base_z: FloatProperty(
129 name='Height',
130 min=0.001, max=10, default=0.05, precision=3,
131 description='Size for z axis',
134 box_top: BoolProperty(
135 name="Include rectangular top",
136 description="Include a top with rectangular form",
137 default=True,
139 box_top_x: FloatProperty(
140 name='X size',
141 min=0.001, max=10, default=0.40, precision=3,
142 description='Size for x axis',
144 box_top_y: FloatProperty(
145 name='Y size',
146 min=0.001, max=10, default=0.40, precision=3,
147 description='Size for y axis',
149 box_top_z: FloatProperty(
150 name='Height',
151 min=0.001, max=10, default=0.05, precision=3,
152 description='Size for z axis',
155 arc_top: BoolProperty(
156 name="Create top arch",
157 description="Include an arch in the top of the column",
158 default=False,
160 arc_radio: FloatProperty(
161 name='Arc Radio',
162 min=0.001, max=10, default=1, precision=1,
163 description='Radio of the arch',
165 arc_width: FloatProperty(
166 name='Thickness',
167 min=0.01, max=10, default=0.15, precision=2,
168 description='Thickness of the arch wall',
170 arc_gap: FloatProperty(
171 name='Arc gap',
172 min=0.01, max=10, default=0.25, precision=2,
173 description='Size of the gap in the arch sides',
176 crt_mat: BoolProperty(
177 name="Create default Cycles materials",
178 description="Create default materials for Cycles render",
179 default=True,
181 crt_array: BoolProperty(
182 name="Create array of elements",
183 description="Create a modifier array for all elemnst",
184 default=False,
186 array_num_x: IntProperty(
187 name='Count X',
188 min=0, max=100, default=3,
189 description='Number of elements in array',
191 array_space_x: FloatProperty(
192 name='Distance X',
193 min=0.000, max=10, default=1, precision=3,
194 description='Distance between elements (only arc disabled)',
196 array_num_y: IntProperty(
197 name='Count Y',
198 min=0, max=100, default=0,
199 description='Number of elements in array',
201 array_space_y: FloatProperty(
202 name='Distance Y',
203 min=0.000, max=10, default=1, precision=3,
204 description='Distance between elements (only arc disabled)',
206 array_space_z: FloatProperty(
207 name='Distance Z',
208 min=-10, max=10, default=0, precision=3,
209 description='Combined X/Z distance between elements (only arc disabled)',
211 ramp: BoolProperty(
212 name="Deform",
213 description="Deform top base with Z displacement", default=True,
215 array_space_factor: FloatProperty(
216 name='Move Y center',
217 min=0.00, max=1, default=0.0, precision=3,
218 description='Move the center of the arch in Y axis. (0 centered)',
221 # -----------------------------------------------------
222 # Draw (create UI interface)
223 # -----------------------------------------------------
224 # noinspection PyUnusedLocal
225 def draw(self, context):
226 layout = self.layout
227 space = bpy.context.space_data
228 if not space.local_view:
229 # Imperial units warning
230 if bpy.context.scene.unit_settings.system == "IMPERIAL":
231 row = layout.row()
232 row.label(text="Warning: Imperial units not supported", icon='COLOR_RED')
233 box = layout.box()
234 box.prop(self, 'model')
235 # Circular
236 if self.model == "1":
237 box.prop(self, 'keep_size')
238 box.prop(self, 'rad_top')
239 if self.keep_size is False:
240 row = box.row()
241 row.prop(self, 'rad_mid')
242 row.prop(self, 'shift')
243 box.prop(self, 'rad_bottom')
245 # Rectangular
246 if self.model == "2":
247 box.prop(self, 'col_sx')
248 box.prop(self, 'col_sy')
250 box.prop(self, 'col_height')
252 box = layout.box()
253 box.prop(self, 'box_base')
254 if self.box_base is True:
255 row = box.row()
256 row.prop(self, 'box_base_x')
257 row.prop(self, 'box_base_y')
258 row.prop(self, 'box_base_z')
260 box = layout.box()
261 box.prop(self, 'box_top')
262 if self.box_top is True:
263 row = box.row()
264 row.prop(self, 'box_top_x')
265 row.prop(self, 'box_top_y')
266 row.prop(self, 'box_top_z')
268 box = layout.box()
269 box.prop(self, 'cir_base')
270 if self.cir_base is True:
271 row = box.row()
272 row.prop(self, 'cir_base_r')
273 row.prop(self, 'cir_base_z')
275 box = layout.box()
276 box.prop(self, 'cir_top')
277 if self.cir_top is True:
278 row = box.row()
279 row.prop(self, 'cir_top_r')
280 row.prop(self, 'cir_top_z')
282 box = layout.box()
283 box.prop(self, 'arc_top')
284 if self.arc_top is True:
285 row = box.row()
286 row.prop(self, 'arc_radio')
287 row.prop(self, 'arc_width')
288 row = box.row()
289 row.prop(self, 'arc_gap')
290 row.prop(self, 'array_space_factor')
292 box = layout.box()
293 box.prop(self, 'crt_array')
294 if self.crt_array is True:
295 row = box.row()
296 row.prop(self, 'array_num_x')
297 row.prop(self, 'array_num_y')
298 if self.arc_top is True:
299 box.label(text="Use arch radio and thickness to set distances")
301 if self.arc_top is False:
302 row = box.row()
303 row.prop(self, 'array_space_x')
304 row.prop(self, 'array_space_y')
305 row = box.row()
306 row.prop(self, 'array_space_z')
307 row.prop(self, 'ramp')
309 box = layout.box()
310 if not context.scene.render.engine in {'CYCLES', 'BLENDER_EEVEE'}:
311 box.enabled = False
312 box.prop(self, 'crt_mat')
313 else:
314 row = layout.row()
315 row.label(text="Warning: Operator does not work in local view mode", icon='ERROR')
317 # -----------------------------------------------------
318 # Execute
319 # -----------------------------------------------------
320 # noinspection PyUnusedLocal
321 def execute(self, context):
322 if bpy.context.mode == "OBJECT":
323 create_column_mesh(self)
324 return {'FINISHED'}
325 else:
326 self.report({'WARNING'}, "Archimesh: Option only valid in Object mode")
327 return {'CANCELLED'}
330 # ------------------------------------------------------------------------------
331 # Generate mesh data
332 # All custom values are passed using self container (self.myvariable)
333 # ------------------------------------------------------------------------------
334 def create_column_mesh(self):
335 myarc = None
336 cir_top = None
337 cir_bottom = None
338 box_top = None
339 box_bottom = None
340 mycolumn = None
341 # deactivate others
342 for o in bpy.data.objects:
343 if o.select_get() is True:
344 o.select_set(False)
346 bpy.ops.object.select_all(action='DESELECT')
348 radio_top = self.rad_top
349 if self.keep_size is True:
350 radio_mid = radio_top
351 radio_bottom = radio_top
352 else:
353 radio_mid = self.rad_mid
354 radio_bottom = self.rad_bottom
356 # Calculate height
357 height = self.col_height
358 if self.box_base:
359 height = height - self.box_base_z
360 if self.box_top:
361 height = height - self.box_top_z
363 # ------------------------
364 # Create circular column
365 # ------------------------
366 if self.model == "1":
367 bpy.ops.object.select_all(action='DESELECT')
368 mycolumn = create_circular_column(self, "Column", radio_top, radio_mid, radio_bottom, height)
369 mycolumn.select_set(True)
370 bpy.context.view_layer.objects.active = mycolumn
371 # Subsurf
372 set_smooth(mycolumn)
373 set_modifier_subsurf(mycolumn)
374 # ------------------------
375 # Create rectangular column
376 # ------------------------
377 if self.model == "2":
378 mycolumn = create_rectangular_base(self, "Column", self.col_sx, self.col_sy, height)
379 bpy.ops.object.select_all(action='DESELECT')
380 mycolumn.select_set(True)
381 bpy.context.view_layer.objects.active = mycolumn
382 set_normals(mycolumn)
383 # ------------------------
384 # Circular base
385 # ------------------------
386 if self.cir_base is True:
387 cir_bottom = create_torus("Column_cir_bottom", radio_bottom, self.cir_base_r, self.cir_base_z)
388 bpy.ops.object.select_all(action='DESELECT')
389 cir_bottom.select_set(True)
390 bpy.context.view_layer.objects.active = cir_bottom
391 set_modifier_subsurf(cir_bottom)
392 set_smooth(cir_bottom)
393 cir_bottom.location.x = 0.0
394 cir_bottom.location.y = 0.0
395 cir_bottom.location.z = self.cir_base_z / 2
396 cir_bottom.parent = mycolumn
398 # ------------------------
399 # Rectangular base
400 # ------------------------
401 if self.box_base is True:
402 box_bottom = create_rectangular_base(self, "Column_box_bottom", self.box_base_x, self.box_base_y,
403 self.box_base_z)
404 bpy.ops.object.select_all(action='DESELECT')
405 box_bottom.select_set(True)
406 bpy.context.view_layer.objects.active = box_bottom
407 box_bottom.parent = mycolumn
408 set_normals(box_bottom)
409 box_bottom.location.x = 0.0
410 box_bottom.location.y = 0.0
411 box_bottom.location.z = - self.box_base_z
412 # move column
413 mycolumn.location.z += self.box_base_z
415 # ------------------------
416 # Circular top
417 # ------------------------
418 if self.cir_top is True:
419 cir_top = create_torus("Column_cir_top", radio_top, self.cir_top_r, self.cir_top_z)
420 bpy.ops.object.select_all(action='DESELECT')
421 cir_top.select_set(True)
422 bpy.context.view_layer.objects.active = cir_top
423 set_modifier_subsurf(cir_top)
424 set_smooth(cir_top)
425 cir_top.parent = mycolumn
426 cir_top.location.x = 0.0
427 cir_top.location.y = 0.0
428 cir_top.location.z = height - self.cir_top_z / 2
430 # ------------------------
431 # Rectangular top
432 # ------------------------
433 if self.box_top is True:
434 box_top = create_rectangular_base(self, "Column_box_top", self.box_top_x, self.box_top_y,
435 self.box_top_z, self.ramp)
436 bpy.ops.object.select_all(action='DESELECT')
437 box_top.select_set(True)
438 bpy.context.view_layer.objects.active = box_top
439 set_normals(box_top)
440 box_top.parent = mycolumn
441 box_top.location.x = 0.0
442 box_top.location.y = 0.0
443 box_top.location.z = height
445 # ------------------------
446 # Create arc
447 # ------------------------
448 if self.arc_top:
449 myarc = create_arc("Column_arch", self.arc_radio, self.arc_gap, self.arc_width,
450 self.array_space_factor)
451 myarc.parent = mycolumn
452 bpy.ops.object.select_all(action='DESELECT')
453 myarc.select_set(True)
454 bpy.context.view_layer.objects.active = myarc
455 set_normals(myarc)
456 set_modifier_mirror(myarc, "X")
457 myarc.location.x = self.arc_radio + self.arc_gap
458 myarc.location.y = 0.0
459 if self.box_top is True:
460 myarc.location.z = height + self.box_top_z
461 else:
462 myarc.location.z = height
463 # ------------------------
464 # Create Array X
465 # ------------------------
466 if self.array_num_x > 0:
467 if self.arc_top:
468 distance = ((self.arc_radio + self.arc_gap) * 2)
469 zmove = 0
470 else:
471 distance = self.array_space_x
472 zmove = self.array_space_z
474 if self.crt_array:
475 set_modifier_array(mycolumn, "X", 0, self.array_num_x, True, distance, zmove)
477 if self.box_base is True:
478 set_modifier_array(box_bottom, "X", 0, self.array_num_x, True, distance, zmove)
479 if self.box_top is True:
480 set_modifier_array(box_top, "X", 0, self.array_num_x, True, distance, zmove)
482 if self.cir_base is True:
483 set_modifier_array(cir_bottom, "X", 0, self.array_num_x, True, distance, zmove)
484 if self.cir_top is True:
485 set_modifier_array(cir_top, "X", 0, self.array_num_x, True, distance, zmove)
487 if self.arc_top:
488 if self.array_num_x > 1:
489 set_modifier_array(myarc, "X", 1, self.array_num_x - 1) # one arc minus
490 # ------------------------
491 # Create Array Y
492 # ------------------------
493 if self.array_num_y > 0:
494 if self.arc_top:
495 distance = self.arc_width
496 else:
497 distance = self.array_space_y
499 if self.crt_array:
500 set_modifier_array(mycolumn, "Y", 0, self.array_num_y, True, distance)
502 if self.box_base is True:
503 set_modifier_array(box_bottom, "Y", 0, self.array_num_y, True, distance)
504 if self.box_top is True:
505 set_modifier_array(box_top, "Y", 0, self.array_num_y, True, distance)
507 if self.cir_base is True:
508 set_modifier_array(cir_bottom, "Y", 0, self.array_num_y, True, distance)
509 if self.cir_top is True:
510 set_modifier_array(cir_top, "Y", 0, self.array_num_y, True, distance)
512 if self.arc_top:
513 if self.array_num_y > 1:
514 set_modifier_array(myarc, "Y", 1, self.array_num_y - 1) # one less
516 # ------------------------
517 # Create materials
518 # ------------------------
519 if self.crt_mat and bpy.context.scene.render.engine in {'CYCLES', 'BLENDER_EEVEE'}:
520 # Column material
521 mat = create_diffuse_material("Column_material", False, 0.748, 0.734, 0.392, 0.573, 0.581, 0.318)
522 set_material(mycolumn, mat)
524 if self.box_base is True or self.box_top is True:
525 mat = create_diffuse_material("Column_rect", False, 0.56, 0.56, 0.56, 0.56, 0.56, 0.56)
526 if self.box_base is True:
527 set_material(box_bottom, mat)
528 if self.box_top is True:
529 set_material(box_top, mat)
531 if self.cir_base is True or self.cir_top is True:
532 mat = create_diffuse_material("Column_cir", False, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65)
533 if self.cir_base is True:
534 set_material(cir_bottom, mat)
535 if self.cir_top is True:
536 set_material(cir_top, mat)
538 if self.arc_top:
539 mat = create_diffuse_material("Column_arch", False, 0.8, 0.8, 0.8)
540 set_material(myarc, mat)
542 bpy.ops.object.select_all(action='DESELECT')
543 mycolumn.select_set(True)
544 bpy.context.view_layer.objects.active = mycolumn
546 return
549 # ------------------------------------------------------------------------------
550 # Create Column
551 # ------------------------------------------------------------------------------
552 def create_circular_column(self, objname, radio_top, radio_mid, radio_bottom, height):
553 myvertex = []
554 myfaces = []
555 pies = [0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330] # circle
557 # Add bottom circle
558 for pie in pies:
559 x = cos(radians(pie)) * radio_bottom
560 y = sin(radians(pie)) * radio_bottom
561 mypoint = [(x, y, 0.0)]
562 myvertex.extend(mypoint)
563 # Add middle circle
564 for pie in pies:
565 x = cos(radians(pie)) * radio_mid
566 y = sin(radians(pie)) * radio_mid
567 mypoint = [(x, y, (height / 2) + ((height / 2) * self.shift))]
568 myvertex.extend(mypoint)
569 # Add top circle
570 for pie in pies:
571 x = cos(radians(pie)) * radio_top
572 y = sin(radians(pie)) * radio_top
573 mypoint = [(x, y, height)]
574 myvertex.extend(mypoint)
575 # -------------------------------------
576 # Faces
577 # -------------------------------------
578 t = 1
579 for n in range(0, len(pies) * 2):
580 t += 1
581 if t > len(pies):
582 t = 1
583 myface = [(n, n - len(pies) + 1, n + 1, n + len(pies))]
584 myfaces.extend(myface)
585 else:
586 myface = [(n, n + 1, n + len(pies) + 1, n + len(pies))]
587 myfaces.extend(myface)
589 mesh = bpy.data.meshes.new(objname)
590 myobject = bpy.data.objects.new(objname, mesh)
592 myobject.location = bpy.context.scene.cursor.location
593 bpy.context.collection.objects.link(myobject)
595 mesh.from_pydata(myvertex, [], myfaces)
596 mesh.update(calc_edges=True)
598 return myobject
601 # ------------------------------------------------------------------------------
602 # Create Torus
603 # ------------------------------------------------------------------------------
604 def create_torus(objname, radio_inside, radio_outside, height):
605 myvertex = []
606 myfaces = []
607 pies = [0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330] # circle
608 segments = [80, 60, 30, 0, 330, 300, 280] # section
610 radio_mid = radio_outside + radio_inside - (height / 2)
611 # Add internal circles Top
612 for pie in pies:
613 x = cos(radians(pie)) * radio_inside
614 y = sin(radians(pie)) * radio_inside
615 mypoint = [(x, y, height / 2)]
616 myvertex.extend(mypoint)
617 # Add external circles Top
618 for pie in pies:
619 x = cos(radians(pie)) * radio_mid
620 y = sin(radians(pie)) * radio_mid
621 mypoint = [(x, y, height / 2)]
622 myvertex.extend(mypoint)
623 # Add Intermediate lines
624 for segment in segments:
625 for pie in pies:
626 radio_externo = radio_mid + (height * cos(radians(segment)))
627 x = cos(radians(pie)) * radio_externo
628 y = sin(radians(pie)) * radio_externo
629 z = sin(radians(segment)) * (height / 2)
631 mypoint = [(x, y, z)]
632 myvertex.extend(mypoint)
634 # Add internal circles Bottom
635 for pie in pies:
636 x = cos(radians(pie)) * radio_inside
637 y = sin(radians(pie)) * radio_inside
638 mypoint = [(x, y, height / 2 * -1)]
639 myvertex.extend(mypoint)
640 # Add external circles bottom
641 for pie in pies:
642 x = cos(radians(pie)) * radio_mid
643 y = sin(radians(pie)) * radio_mid
644 mypoint = [(x, y, height / 2 * -1)]
645 myvertex.extend(mypoint)
647 # -------------------------------------
648 # Faces
649 # -------------------------------------
650 t = 1
651 for n in range(0, len(pies) * len(segments) + (len(pies) * 2)):
652 t += 1
653 if t > len(pies):
654 t = 1
655 myface = [(n, n - len(pies) + 1, n + 1, n + len(pies))]
656 myfaces.extend(myface)
657 else:
658 myface = [(n, n + 1, n + len(pies) + 1, n + len(pies))]
659 myfaces.extend(myface)
661 mesh = bpy.data.meshes.new(objname)
662 myobject = bpy.data.objects.new(objname, mesh)
664 myobject.location = bpy.context.scene.cursor.location
665 bpy.context.collection.objects.link(myobject)
667 mesh.from_pydata(myvertex, [], myfaces)
668 mesh.update(calc_edges=True)
670 return myobject
673 # ------------------------------------------------------------------------------
674 # Create rectangular base
675 # ------------------------------------------------------------------------------
676 def create_rectangular_base(self, objname, x, y, z, ramp=False):
677 elements = self.array_num_x - 1
678 height = self.array_space_z * elements
679 width = self.array_space_x * elements
680 if width > 0:
681 angle = atan(height / width)
682 else:
683 angle = 0
685 radio = sqrt((x * x) + (self.array_space_z * self.array_space_z))
686 disp = radio * sin(angle)
688 if ramp is False or self.arc_top:
689 addz1 = 0
690 addz2 = 0
691 else:
692 if self.array_space_z >= 0:
693 addz1 = 0
694 addz2 = disp
695 else:
696 addz1 = disp * -1
697 addz2 = 0
699 myvertex = [(-x / 2, -y / 2, 0.0),
700 (-x / 2, y / 2, 0.0),
701 (x / 2, y / 2, 0.0),
702 (x / 2, -y / 2, 0.0),
703 (-x / 2, -y / 2, z + addz1),
704 (-x / 2, y / 2, z + addz1),
705 (x / 2, y / 2, z + addz2),
706 (x / 2, -y / 2, z + addz2)]
708 myfaces = [(0, 1, 2, 3), (0, 1, 5, 4), (1, 2, 6, 5), (2, 6, 7, 3), (5, 6, 7, 4), (0, 4, 7, 3)]
710 mesh = bpy.data.meshes.new(objname)
711 myobject = bpy.data.objects.new(objname, mesh)
713 myobject.location = bpy.context.scene.cursor.location
714 bpy.context.collection.objects.link(myobject)
716 mesh.from_pydata(myvertex, [], myfaces)
717 mesh.update(calc_edges=True)
719 return myobject
722 # ------------------------------------------------------------------------------
723 # Create arc
724 # ------------------------------------------------------------------------------
725 def create_arc(objname, radio, gap, thickness, center):
726 myvertex = []
728 half = (thickness / 2)
729 move = half * center
731 listdata = [half + move, -half + move]
732 for pos_y in listdata:
733 # --------------------------------
734 # First vertices
735 # --------------------------------
736 myvertex.extend([(-radio - gap, pos_y, radio + radio / 10)])
737 # Flat cuts
738 angle = 13 * (180 / 16)
739 for i in range(1, 4):
740 z = sin(radians(angle)) * radio
741 mypoint = [(-radio - gap, pos_y, z)]
742 myvertex.extend(mypoint)
743 angle += 180 / 16
745 myvertex.extend([(-radio - gap, pos_y, 0.0)])
746 # --------------------------------
747 # Arc points
748 # --------------------------------
749 angle = 180
750 for i in range(0, 9):
751 x = cos(radians(angle)) * radio
752 z = sin(radians(angle)) * radio
753 mypoint = [(x, pos_y, z)]
754 myvertex.extend(mypoint)
756 angle -= 180 / 16
757 # --------------------------------
758 # vertical cut points
759 # --------------------------------
760 angle = 8 * (180 / 16)
761 for i in range(1, 5):
762 x = cos(radians(angle)) * radio
763 mypoint = [(x, pos_y, radio + radio / 10)]
764 myvertex.extend(mypoint)
766 angle += 180 / 16
768 myfaces = [(23, 24, 21, 22), (24, 25, 20, 21), (25, 26, 19, 20), (27, 18, 19, 26), (18, 27, 28, 35),
769 (28, 29, 34, 35), (29, 30, 33, 34), (30, 31, 32, 33), (12, 13, 31, 30), (29, 11, 12, 30),
770 (11, 29, 28, 10), (10, 28, 27, 9), (9, 27, 26, 8), (25, 7, 8, 26), (24, 6, 7, 25),
771 (23, 5, 6, 24), (22, 4, 5, 23), (5, 4, 3, 6), (6, 3, 2, 7), (7, 2, 1, 8),
772 (8, 1, 0, 9), (9, 0, 17, 10), (10, 17, 16, 11), (11, 16, 15, 12), (14, 13, 12, 15),
773 (21, 3, 4, 22), (20, 2, 3, 21), (19, 1, 2, 20), (1, 19, 18, 0), (0, 18, 35, 17),
774 (17, 35, 34, 16), (33, 15, 16, 34), (32, 14, 15, 33)]
776 mesh = bpy.data.meshes.new(objname)
777 myobject = bpy.data.objects.new(objname, mesh)
779 myobject.location = bpy.context.scene.cursor.location
780 bpy.context.collection.objects.link(myobject)
782 mesh.from_pydata(myvertex, [], myfaces)
783 mesh.update(calc_edges=True)
785 return myobject