GPencil Tools: Optimize Undo for Rotate Canvas
[blender-addons.git] / archimesh / achm_lamp_maker.py
blob5d653195031db6483241271053c11ea8b01bb54f
1 # SPDX-FileCopyrightText: 2016-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 # ----------------------------------------------------------
6 # Automatic generation of lamps
7 # Author: Antonio Vazquez (antonioya)
9 # ----------------------------------------------------------
10 import bpy
11 from math import cos, sin, radians
12 from copy import copy
13 from bpy.types import Operator
14 from bpy.props import EnumProperty, FloatProperty, IntProperty, BoolProperty, FloatVectorProperty
15 from .achm_tools import *
18 # ------------------------------------------------------
19 # set predefined designs
21 # self: self container
22 # ------------------------------------------------------
23 def set_preset(self):
24 # -----------------------
25 # Sphere
26 # -----------------------
27 if self.preset == "1":
28 self.base_height = 0.22
29 self.base_segments = 16
30 self.base_rings = 6
31 self.smooth = True
32 self.subdivide = True
33 self.br01 = 0.05
34 self.br02 = 0.07
35 self.br03 = 0.11
36 self.br04 = 0.11
37 self.br05 = 0.07
38 self.br06 = 0.03
40 self.bz01 = 0
41 self.bz02 = -1
42 self.bz03 = -0.456
43 self.bz04 = 0.089
44 self.bz05 = -0.038
45 self.bz06 = -0.165
46 # -----------------------
47 # Pear
48 # -----------------------
49 if self.preset == "2":
50 self.base_height = 0.20
51 self.base_segments = 16
52 self.base_rings = 6
53 self.smooth = True
54 self.subdivide = True
55 self.br01 = 0.056
56 self.br02 = 0.062
57 self.br03 = 0.072
58 self.br04 = 0.090
59 self.br05 = 0.074
60 self.br06 = 0.03
62 self.bz01 = 0
63 self.bz02 = 0
64 self.bz03 = 0
65 self.bz04 = 0
66 self.bz05 = 0
67 self.bz06 = 0
68 # -----------------------
69 # Vase
70 # -----------------------
71 if self.preset == "3":
72 self.base_height = 0.20
73 self.base_segments = 8
74 self.base_rings = 6
75 self.smooth = True
76 self.subdivide = True
77 self.br01 = 0.05
78 self.br02 = 0.11
79 self.br03 = 0.15
80 self.br04 = 0.07
81 self.br05 = 0.05
82 self.br06 = 0.03
84 self.bz01 = 0
85 self.bz02 = 0
86 self.bz03 = 0
87 self.bz04 = 0
88 self.bz05 = 0
89 self.bz06 = 0
90 # -----------------------
91 # Rectangular
92 # -----------------------
93 if self.preset == "4":
94 self.base_height = 0.15
95 self.base_segments = 4
96 self.base_rings = 5
97 self.smooth = False
98 self.subdivide = False
99 self.br01 = 0.08
100 self.br02 = 0.08
101 self.br03 = 0.08
102 self.br04 = 0.08
103 self.br05 = 0.03
105 self.bz01 = 0
106 self.bz02 = 0
107 self.bz03 = 0
108 self.bz04 = 0.25
109 self.bz05 = 0
112 # ------------------------------------------------------------------
113 # Define UI class
114 # Lamps
115 # ------------------------------------------------------------------
116 class ARCHIMESH_PT_Lamp(Operator):
117 bl_idname = "mesh.archimesh_light"
118 bl_label = "Lamp"
119 bl_description = "Lamp Generator"
120 bl_category = 'View'
121 bl_options = {'REGISTER', 'UNDO'}
122 # preset
123 preset: EnumProperty(
124 items=(
125 ('0', "None", ""),
126 ('1', "Sphere", ""),
127 ('2', "Pear", ""),
128 ('3', "Vase", ""),
129 ('4', "Rectangular", ""),
131 name="Predefined",
132 description="Apply predefined design",
134 oldpreset: EnumProperty(
135 items=(
136 ('0', "None", ""),
137 ('1', "Sphere", ""),
138 ('2', "Pear", ""),
139 ('3', "Vase", ""),
140 ('4', "Rectangular", ""),
142 name="Predefined",
143 description="Apply predefined design",
146 base_height: FloatProperty(
147 name='Height',
148 min=0.01, max=10, default=0.20, precision=3,
149 description='lamp base height',
151 base_segments: IntProperty(
152 name='Segments',
153 min=3, max=128, default=16,
154 description='Number of segments (vertical)',
156 base_rings: IntProperty(
157 name='Rings',
158 min=2, max=12, default=6,
159 description='Number of rings (horizontal)',
161 holder: FloatProperty(
162 name='Lampholder',
163 min=0.001, max=10, default=0.02, precision=3,
164 description='Lampholder height',
166 smooth: BoolProperty(
167 name="Smooth",
168 description="Use smooth shader",
169 default=True,
171 subdivide: BoolProperty(
172 name="Subdivide",
173 description="Add subdivision modifier",
174 default=True,
177 bz01: FloatProperty(name='S1', min=-1, max=1, default=0, precision=3, description='Z shift factor')
178 bz02: FloatProperty(name='S2', min=-1, max=1, default=0, precision=3, description='Z shift factor')
179 bz03: FloatProperty(name='S3', min=-1, max=1, default=0, precision=3, description='Z shift factor')
180 bz04: FloatProperty(name='S4', min=-1, max=1, default=0, precision=3, description='Z shift factor')
181 bz05: FloatProperty(name='S5', min=-1, max=1, default=0, precision=3, description='Z shift factor')
182 bz06: FloatProperty(name='S6', min=-1, max=1, default=0, precision=3, description='Z shift factor')
183 bz07: FloatProperty(name='S7', min=-1, max=1, default=0, precision=3, description='Z shift factor')
184 bz08: FloatProperty(name='S8', min=-1, max=1, default=0, precision=3, description='Z shift factor')
185 bz09: FloatProperty(name='S9', min=-1, max=1, default=0, precision=3, description='Z shift factor')
186 bz10: FloatProperty(name='S10', min=-1, max=1, default=0, precision=3, description='Z shift factor')
187 bz11: FloatProperty(name='S11', min=-1, max=1, default=0, precision=3, description='Z shift factor')
188 bz12: FloatProperty(name='S12', min=-1, max=1, default=0, precision=3, description='Z shift factor')
190 br01: FloatProperty(name='R1', min=0.001, max=10, default=0.06, precision=3, description='Ring radio')
191 br02: FloatProperty(name='R2', min=0.001, max=10, default=0.08, precision=3, description='Ring radio')
192 br03: FloatProperty(name='R3', min=0.001, max=10, default=0.09, precision=3, description='Ring radio')
193 br04: FloatProperty(name='R4', min=0.001, max=10, default=0.08, precision=3, description='Ring radio')
194 br05: FloatProperty(name='R5', min=0.001, max=10, default=0.06, precision=3, description='Ring radio')
195 br06: FloatProperty(name='R6', min=0.001, max=10, default=0.03, precision=3, description='Ring radio')
196 br07: FloatProperty(name='R7', min=0.001, max=10, default=0.10, precision=3, description='Ring radio')
197 br08: FloatProperty(name='R8', min=0.001, max=10, default=0.10, precision=3, description='Ring radio')
198 br09: FloatProperty(name='R9', min=0.001, max=10, default=0.10, precision=3, description='Ring radio')
199 br10: FloatProperty(name='R10', min=0.001, max=10, default=0.10, precision=3, description='Ring radio')
200 br11: FloatProperty(name='R11', min=0.001, max=10, default=0.10, precision=3, description='Ring radio')
201 br12: FloatProperty(name='R12', min=0.001, max=10, default=0.10, precision=3, description='Ring radio')
203 top_height: FloatProperty(
204 name='Height', min=0.01, max=10,
205 default=0.20, precision=3,
206 description='lampshade height',
208 top_segments: IntProperty(
209 name='Segments', min=3, max=128,
210 default=32,
211 description='Number of segments (vertical)',
213 tr01: FloatProperty(
214 name='R1', min=0.001, max=10,
215 default=0.16, precision=3,
216 description='lampshade bottom radio',
218 tr02: FloatProperty(name='R2', min=0.001, max=10,
219 default=0.08, precision=3,
220 description='lampshade top radio')
221 pleats: BoolProperty(
222 name="Pleats", description="Create pleats in the lampshade",
223 default=False,
225 tr03: FloatProperty(
226 name='R3', min=0.001, max=1,
227 default=0.01, precision=3, description='Pleats size',
229 energy: FloatProperty(
230 name='Light', min=0.00, max=1000,
231 default=15, precision=3,
232 description='Light intensity',
234 opacity: FloatProperty(
235 name='Translucency', min=0.00, max=1,
236 default=0.3, precision=3,
237 description='Lampshade translucency factor (1 completely translucent)',
240 # Materials
241 crt_mat: BoolProperty(
242 name="Create default Cycles materials",
243 description="Create default materials for Cycles render",
244 default=True,
246 objcol: FloatVectorProperty(
247 name="Color",
248 description="Color for material",
249 default=(1.0, 1.0, 1.0, 1.0),
250 min=0.1, max=1,
251 subtype='COLOR',
252 size=4,
255 # -----------------------------------------------------
256 # Draw (create UI interface)
257 # -----------------------------------------------------
258 # noinspection PyUnusedLocal
259 def draw(self, context):
260 layout = self.layout
261 space = bpy.context.space_data
262 if not space.local_view:
263 # Imperial units warning
264 if bpy.context.scene.unit_settings.system == "IMPERIAL":
265 row = layout.row()
266 row.label(text="Warning: Imperial units not supported", icon='COLOR_RED')
268 box = layout.box()
269 box.label(text="Lamp base")
270 row = box.row()
271 row.prop(self, 'preset')
272 row = box.row()
273 row.prop(self, 'base_height')
274 row.prop(self, 'base_segments')
275 row.prop(self, 'base_rings')
276 row = box.row()
277 row.prop(self, 'smooth')
278 row.prop(self, 'subdivide')
279 row = box.row()
280 row.prop(self, 'holder')
282 if self.base_rings >= 1:
283 row = box.row()
284 row.prop(self, 'br01')
285 row.prop(self, 'bz01', slider=True)
286 if self.base_rings >= 2:
287 row = box.row()
288 row.prop(self, 'br02')
289 row.prop(self, 'bz02', slider=True)
290 if self.base_rings >= 3:
291 row = box.row()
292 row.prop(self, 'br03')
293 row.prop(self, 'bz03', slider=True)
295 if self.base_rings >= 4:
296 row = box.row()
297 row.prop(self, 'br04')
298 row.prop(self, 'bz04', slider=True)
299 if self.base_rings >= 5:
300 row = box.row()
301 row.prop(self, 'br05')
302 row.prop(self, 'bz05', slider=True)
303 if self.base_rings >= 6:
304 row = box.row()
305 row.prop(self, 'br06')
306 row.prop(self, 'bz06', slider=True)
308 if self.base_rings >= 7:
309 row = box.row()
310 row.prop(self, 'br07')
311 row.prop(self, 'bz07', slider=True)
312 if self.base_rings >= 8:
313 row = box.row()
314 row.prop(self, 'br08')
315 row.prop(self, 'bz08', slider=True)
316 if self.base_rings >= 9:
317 row = box.row()
318 row.prop(self, 'br09')
319 row.prop(self, 'bz09', slider=True)
321 if self.base_rings >= 10:
322 row = box.row()
323 row.prop(self, 'br10')
324 row.prop(self, 'bz10', slider=True)
325 if self.base_rings >= 11:
326 row = box.row()
327 row.prop(self, 'br11')
328 row.prop(self, 'bz11', slider=True)
329 if self.base_rings >= 12:
330 row = box.row()
331 row.prop(self, 'br12')
332 row.prop(self, 'bz12', slider=True)
334 box = layout.box()
335 box.label(text="Lampshade")
336 row = box.row()
337 row.prop(self, 'top_height')
338 row.prop(self, 'top_segments')
339 row = box.row()
340 row.prop(self, 'tr01')
341 row.prop(self, 'tr02')
342 row = box.row()
343 row.prop(self, 'energy')
344 row.prop(self, 'opacity', slider=True)
345 row = box.row()
346 row.prop(self, 'pleats')
347 if self.pleats:
348 row.prop(self, 'tr03')
350 box = layout.box()
351 if not context.scene.render.engine in {'CYCLES', 'BLENDER_EEVEE'}:
352 box.enabled = False
353 box.prop(self, 'crt_mat')
354 if self.crt_mat:
355 row = box.row()
356 row.prop(self, 'objcol')
357 else:
358 row = layout.row()
359 row.label(text="Warning: Operator does not work in local view mode", icon='ERROR')
361 # -----------------------------------------------------
362 # Execute
363 # -----------------------------------------------------
364 # noinspection PyUnusedLocal
365 def execute(self, context):
366 if bpy.context.mode == "OBJECT":
367 if self.oldpreset != self.preset:
368 set_preset(self)
369 self.oldpreset = self.preset
371 # Create lamp
372 create_light_mesh(self)
373 return {'FINISHED'}
374 else:
375 self.report({'WARNING'}, "Archimesh: Option only valid in Object mode")
376 return {'CANCELLED'}
379 # ------------------------------------------------------------------------------
380 # Generate mesh data
381 # All custom values are passed using self container (self.myvariable)
382 # ------------------------------------------------------------------------------
383 def create_light_mesh(self):
384 # deactivate others
385 for o in bpy.data.objects:
386 if o.select_get() is True:
387 o.select_set(False)
388 bpy.ops.object.select_all(action='DESELECT')
389 generate_light(self)
391 return
394 # ------------------------------------------------------------------------------
395 # Generate lamps
396 # All custom values are passed using self container (self.myvariable)
397 # ------------------------------------------------------------------------------
398 def generate_light(self):
399 location = bpy.context.scene.cursor.location
400 myloc = copy(location) # copy location to keep 3D cursor position
401 # ---------------------
402 # Lamp base
403 # ---------------------
404 mydata = create_light_base("Lamp_base", self.base_height,
405 myloc.x, myloc.y, myloc.z,
406 self.base_segments, self.base_rings,
407 [self.br01, self.br02, self.br03, self.br04, self.br05, self.br06,
408 self.br07, self.br08, self.br09, self.br10, self.br11, self.br12],
409 (self.bz01, self.bz02, self.bz03, self.bz04, self.bz05, self.bz06,
410 self.bz07, self.bz08, self.bz09, self.bz10, self.bz11, self.bz12),
411 self.subdivide,
412 self.crt_mat, self.objcol)
413 mybase = mydata[0]
414 posz = mydata[1]
415 # refine
416 remove_doubles(mybase)
417 set_normals(mybase)
418 # Smooth
419 if self.smooth:
420 set_smooth(mybase)
421 if self.subdivide:
422 set_modifier_subsurf(mybase)
423 # ---------------------
424 # Lampholder
425 # ---------------------
426 myholder = create_lightholder("Lampholder", self.holder,
427 myloc.x, myloc.y, myloc.z,
428 self.crt_mat)
429 # refine
430 remove_doubles(myholder)
431 set_normals(myholder)
432 set_smooth(myholder)
434 myholder.parent = mybase
435 myholder.location.x = 0
436 myholder.location.y = 0
437 myholder.location.z = posz
438 # ---------------------
439 # Lamp strings
440 # ---------------------
441 mystrings = create_lightholder_strings("Lampstrings", self.holder,
442 myloc.x, myloc.y, myloc.z,
443 self.tr02,
444 self.top_height,
445 self.crt_mat)
446 # refine
447 remove_doubles(mystrings)
448 set_normals(mystrings)
450 mystrings.parent = myholder
451 mystrings.location.x = 0
452 mystrings.location.y = 0
453 mystrings.location.z = 0.03
454 # ---------------------
455 # Lampshade
456 # ---------------------
457 mytop = create_lightshade("Lampshade", self.top_height,
458 myloc.x, myloc.y, myloc.z,
459 self.top_segments,
460 self.tr01, self.tr02,
461 self.pleats, self.tr03,
462 self.opacity,
463 self.crt_mat)
464 # refine
465 remove_doubles(mytop)
466 set_normals(mytop)
467 if self.pleats is False:
468 set_smooth(mytop)
470 mytop.parent = mybase
471 mytop.location.x = 0
472 mytop.location.y = 0
473 mytop.location.z = posz + self.holder
474 # ---------------------
475 # Light bulb
476 # ---------------------
477 radbulb = 0.02
478 bpy.ops.mesh.primitive_uv_sphere_add(segments=16, radius=radbulb)
479 mybulb = bpy.data.objects[bpy.context.active_object.name]
480 mybulb.name = "Lamp_Bulb"
481 mybulb.parent = myholder
482 mybulb.location = (0, 0, radbulb + self.holder + 0.04)
483 if self.crt_mat and bpy.context.scene.render.engine in {'CYCLES', 'BLENDER_EEVEE'}:
484 mat = create_emission_material(mybulb.name, True, 0.8, 0.8, 0.8, self.energy)
485 set_material(mybulb, mat)
487 # deactivate others
488 for o in bpy.data.objects:
489 if o.select_get() is True:
490 o.select_set(False)
492 mybase.select_set(True)
493 bpy.context.view_layer.objects.active = mybase
495 return
498 # ------------------------------------------------------------------------------
499 # Create lamp base
501 # objName: Name for the new object
502 # height: Size in Z axis
503 # pX: position X axis
504 # pY: position Y axis
505 # pZ: position Z axis
506 # segments: number of segments
507 # rings: number of rings
508 # radios: ring radios
509 # ratios: Z shift ratios
510 # subdivide: Subdivision flag
511 # mat: Flag for creating materials
512 # objcol: Color
513 # ------------------------------------------------------------------------------
514 def create_light_base(objname, height, px, py, pz, segments, rings, radios, ratios, subdivide, mat, objcol):
515 # Calculate heights
516 h = height / (rings - 1)
517 listheight = []
518 z = 0
519 for f in range(0, rings):
520 listheight.extend([z + (z * ratios[f])])
521 z += h
523 mydata = create_cylinder_data(segments, listheight,
524 radios,
525 True, True, False, 0, subdivide)
526 myvertex = mydata[0]
527 myfaces = mydata[1]
529 mymesh = bpy.data.meshes.new(objname)
530 mycylinder = bpy.data.objects.new(objname, mymesh)
531 bpy.context.collection.objects.link(mycylinder)
533 mymesh.from_pydata(myvertex, [], myfaces)
534 mymesh.update(calc_edges=True)
535 # Position
536 mycylinder.location.x = px
537 mycylinder.location.y = py
538 mycylinder.location.z = pz
539 # Materials
540 if mat and bpy.context.scene.render.engine in {'CYCLES', 'BLENDER_EEVEE'}:
541 rgb = objcol
542 mymat = create_diffuse_material(mycylinder.name + "_material", True, rgb[0], rgb[1], rgb[2], rgb[0], rgb[1],
543 rgb[2], 0.1)
544 set_material(mycylinder, mymat)
546 return mycylinder, listheight[len(listheight) - 1]
549 # ------------------------------------------------------------------------------
550 # Create lampholder
552 # objName: Name for the new object
553 # height: Size in Z axis
554 # pX: position X axis
555 # pY: position Y axis
556 # pZ: position Z axis
557 # mat: Flag for creating materials
558 # ------------------------------------------------------------------------------
559 def create_lightholder(objname, height, px, py, pz, mat):
560 mydata = create_cylinder_data(16, [0, height, height + 0.005, height + 0.008, height + 0.05],
561 [0.005, 0.005, 0.010, 0.018, 0.018],
562 False, False, False, 0, False)
563 myvertex = mydata[0]
564 myfaces = mydata[1]
566 mymesh = bpy.data.meshes.new(objname)
567 mycylinder = bpy.data.objects.new(objname, mymesh)
568 bpy.context.collection.objects.link(mycylinder)
570 mymesh.from_pydata(myvertex, [], myfaces)
571 mymesh.update(calc_edges=True)
572 # Position
573 mycylinder.location.x = px
574 mycylinder.location.y = py
575 mycylinder.location.z = pz
577 # Materials
578 if mat and bpy.context.scene.render.engine in {'CYCLES', 'BLENDER_EEVEE'}:
579 mat = create_diffuse_material(mycylinder.name + "_material", True, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.1)
580 set_material(mycylinder, mat)
582 return mycylinder
585 # ------------------------------------------------------------------------------
586 # Create lampholder strings
588 # objName: Name for the new object
589 # height: Size in Z axis
590 # pX: position X axis
591 # pY: position Y axis
592 # pZ: position Z axis
593 # radio: radio of lampshade
594 # shadeh: height of lampshader
595 # mat: Flag for creating materials
596 # ------------------------------------------------------------------------------
597 def create_lightholder_strings(objname, height, px, py, pz, radio, shadeh, mat):
598 mydata = create_cylinder_data(32, [height + 0.005, height + 0.005, height + 0.006, height + 0.006],
599 [0.018, 0.025, 0.025, 0.018],
600 False, False, False, 0, False)
601 myvertex = mydata[0]
602 myfaces = mydata[1]
604 mymesh = bpy.data.meshes.new(objname)
605 mycylinder = bpy.data.objects.new(objname, mymesh)
606 bpy.context.collection.objects.link(mycylinder)
608 mymesh.from_pydata(myvertex, [], myfaces)
609 mymesh.update(calc_edges=True)
610 # Position
611 mycylinder.location.x = px
612 mycylinder.location.y = py
613 mycylinder.location.z = pz
614 # Box1
615 box1 = create_box_segments("Lamp_B1", shadeh - 0.036, radio - 0.023)
616 box1.parent = mycylinder
617 box1.location = (0.021, 0, height + 0.004)
618 # Box2
619 box2 = create_box_segments("Lamp_B2", shadeh - 0.036, -radio + 0.023)
620 box2.parent = mycylinder
621 box2.location = (-0.021, 0, height + 0.004)
623 # Materials
624 if mat and bpy.context.scene.render.engine in {'CYCLES', 'BLENDER_EEVEE'}:
625 mat = create_diffuse_material(mycylinder.name + "_material", True, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.1)
626 set_material(mycylinder, mat)
627 set_material(box1, mat)
628 set_material(box2, mat)
630 return mycylinder
633 # ------------------------------------------------------------------------------
634 # Create lampshade
636 # objName: Name for the new object
637 # height: Size in Z axis
638 # pX: position X axis
639 # pY: position Y axis
640 # pZ: position Z axis
641 # segments: number of segments
642 # radio1: ring radio 1
643 # radio2: ring radio 2
644 # pleats: flag for pleats
645 # pleatsize: difference in radios (less)
646 # opacity: opacity factor
647 # mat: Flag for creating materials
648 # ------------------------------------------------------------------------------
649 def create_lightshade(objname, height, px, py, pz, segments, radio1, radio2, pleats, pleatsize, opacity, mat):
650 gap = 0.002
651 radios = [radio1 - gap, radio1 - gap, radio1, radio2, radio2 - gap, radio2 - gap]
652 heights = [gap * 2, 0, 0, height, height, height - (gap * 2)]
653 mydata = create_cylinder_data(segments, heights,
654 radios,
655 False, False, pleats, pleatsize, False)
656 myvertex = mydata[0]
657 myfaces = mydata[1]
659 mymesh = bpy.data.meshes.new(objname)
660 mycylinder = bpy.data.objects.new(objname, mymesh)
661 bpy.context.collection.objects.link(mycylinder)
663 mymesh.from_pydata(myvertex, [], myfaces)
664 mymesh.update(calc_edges=True)
665 # Position
666 mycylinder.location.x = px
667 mycylinder.location.y = py
668 mycylinder.location.z = pz
669 # materials
670 if mat and bpy.context.scene.render.engine in {'CYCLES', 'BLENDER_EEVEE'}:
671 mymat = create_translucent_material(mycylinder.name + "_material", True, 0.8, 0.65, 0.45, 0.8, 0.65, 0.45,
672 opacity)
673 set_material(mycylinder, mymat)
675 return mycylinder
678 # ------------------------------------------------------------------------------
679 # Create box segments
681 # objName: Name for the new object
682 # height: Size in Z axis
683 # shift: Shift movement
684 # ------------------------------------------------------------------------------
685 def create_box_segments(objname, height, shift):
686 gap = 0.001
687 myvertex = [(0, 0, 0), (0, gap, 0), (gap, gap, 0), (gap, 0, 0),
688 (shift, 0, height),
689 (shift, gap, height),
690 (shift + gap, gap, height),
691 (shift + gap, 0, height)]
692 myfaces = [(6, 5, 1, 2), (7, 6, 2, 3), (4, 7, 3, 0), (1, 5, 4, 0)]
694 mymesh = bpy.data.meshes.new(objname)
695 mysegment = bpy.data.objects.new(objname, mymesh)
696 bpy.context.collection.objects.link(mysegment)
698 mymesh.from_pydata(myvertex, [], myfaces)
699 mymesh.update(calc_edges=True)
700 # Position
701 mysegment.location.x = 0
702 mysegment.location.y = 0
703 mysegment.location.z = 0
705 return mysegment
708 # ------------------------------------------------------------------------------
709 # Create cylinders data
711 # segments: Number of pies
712 # listHeight: list of heights
713 # listRadio: list of radios
714 # top: top face flag
715 # bottom: bottom face flag
716 # pleats: flag for pleats
717 # pleatsize: difference in radios (less)
718 # subdiv: fix subdivision problem
719 # ------------------------------------------------------------------------------
720 def create_cylinder_data(segments, listheight, listradio, bottom, top, pleats, pleatsize, subdiv):
721 myvertex = []
722 myfaces = []
723 if subdiv:
724 # Add at element 0 to fix subdivision problems
725 listheight.insert(0, listheight[0] + 0.001)
726 listradio.insert(0, listradio[0])
727 # Add at last element to fix subdivision problems
728 e = len(listheight) - 1
729 listheight.insert(e, listheight[e] + 0.001)
730 listradio.insert(e, listradio[e])
731 # -------------------------------------
732 # Vertices
733 # -------------------------------------
734 idx = 0
735 rp = 0
736 for z in listheight:
737 seg = 0
738 for i in range(segments):
739 x = cos(radians(seg)) * (listradio[idx] + rp)
740 y = sin(radians(seg)) * (listradio[idx] + rp)
741 mypoint = [(x, y, z)]
742 myvertex.extend(mypoint)
743 seg += 360 / segments
744 # pleats
745 if pleats is True and rp == 0:
746 rp = -pleatsize
747 else:
748 rp = 0
750 idx += 1
751 # -------------------------------------
752 # Faces
753 # -------------------------------------
754 for r in range(0, len(listheight) - 1):
755 s = r * segments
756 t = 1
757 for n in range(0, segments):
758 t += 1
759 if t > segments:
760 t = 1
761 myface = [(n + s, n + s - segments + 1, n + s + 1, n + s + segments)]
762 myfaces.extend(myface)
763 else:
764 myface = [(n + s, n + s + 1, n + s + segments + 1, n + s + segments)]
765 myfaces.extend(myface)
767 # -----------------
768 # bottom face
769 # -----------------
770 if bottom:
771 fa = []
772 for f in range(0, segments):
773 fa.extend([f])
774 myfaces.extend([fa])
775 # -----------------
776 # top face
777 # -----------------
778 if top:
779 fa = []
780 for f in range(len(myvertex) - segments, len(myvertex)):
781 fa.extend([f])
782 myfaces.extend([fa])
784 return myvertex, myfaces