1 # SPDX-FileCopyrightText: 2016-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 # ----------------------------------------------------------
6 # Automatic generation of shelves
7 # Author: Antonio Vazquez (antonioya)
9 # ----------------------------------------------------------
12 from bpy
.types
import Operator
, PropertyGroup
13 from bpy
.props
import FloatProperty
, BoolProperty
, IntProperty
, CollectionProperty
, EnumProperty
14 from .achm_tools
import *
17 # ------------------------------------------------------------------
18 # Define property group class for shelves properties
19 # ------------------------------------------------------------------
20 class ShelvesProperties(PropertyGroup
):
21 sX
: FloatProperty(name
='width', min=0.001, max=10, default
=1,
22 precision
=3, description
='Furniture width')
23 wY
: FloatProperty(name
='', min=-10, max=10, default
=0, precision
=3, description
='Modify y size')
24 wZ
: FloatProperty(name
='', min=-10, max=10, default
=0, precision
=3, description
='Modify z size')
25 # Cabinet position shift
26 pX
: FloatProperty(name
='', min=0, max=10, default
=0, precision
=3, description
='Position x shift')
27 pY
: FloatProperty(name
='', min=-10, max=10, default
=0, precision
=3, description
='Position y shift')
28 pZ
: FloatProperty(name
='', min=-10, max=10, default
=0, precision
=3, description
='Position z shift')
31 sNum
: IntProperty(name
='Shelves', min=0, max=12, default
=6, description
='Number total of shelves')
34 Z01
: FloatProperty(name
='zS1', min=-10, max=10, default
=0, precision
=3, description
='Position z shift')
35 Z02
: FloatProperty(name
='zS2', min=-10, max=10, default
=0, precision
=3, description
='Position z shift')
36 Z03
: FloatProperty(name
='zS3', min=-10, max=10, default
=0, precision
=3, description
='Position z shift')
37 Z04
: FloatProperty(name
='zS4', min=-10, max=10, default
=0, precision
=3, description
='Position z shift')
38 Z05
: FloatProperty(name
='zS5', min=-10, max=10, default
=0, precision
=3, description
='Position z shift')
39 Z06
: FloatProperty(name
='zS6', min=-10, max=10, default
=0, precision
=3, description
='Position z shift')
40 Z07
: FloatProperty(name
='zS7', min=-10, max=10, default
=0, precision
=3, description
='Position z shift')
41 Z08
: FloatProperty(name
='zS8', min=-10, max=10, default
=0, precision
=3, description
='Position z shift')
42 Z09
: FloatProperty(name
='zS9', min=-10, max=10, default
=0, precision
=3, description
='Position z shift')
43 Z10
: FloatProperty(name
='zS10', min=-10, max=10, default
=0, precision
=3, description
='Position z shift')
44 Z11
: FloatProperty(name
='zS11', min=-10, max=10, default
=0, precision
=3, description
='Position z shift')
45 Z12
: FloatProperty(name
='zS12', min=-10, max=10, default
=0, precision
=3, description
='Position z shift')
47 right
: BoolProperty(name
="Right", description
="Create right side", default
=True)
48 left
: BoolProperty(name
="Left", description
="Create left side", default
=True)
50 bpy
.utils
.register_class(ShelvesProperties
)
53 # ------------------------------------------------------------------
56 # ------------------------------------------------------------------
57 class ARCHIMESH_OT_Shelves(Operator
):
58 bl_idname
= "mesh.archimesh_shelves"
60 bl_description
= "Shelves Generator"
62 bl_options
= {'REGISTER', 'UNDO'}
64 thickness
: FloatProperty(
65 name
='Side Thickness', min=0.001, max=5,
66 default
=0.03, precision
=3,
67 description
='Board thickness',
69 sthickness
: FloatProperty(
70 name
='Shelves Thickness', min=0.001, max=5,
71 default
=0.03, precision
=3,
72 description
='Board thickness',
75 name
='Depth', min=0.001, max=50,
76 default
=0.28, precision
=3,
77 description
='Default unit depth',
79 height
: FloatProperty(
80 name
='Height', min=0.001, max=50,
81 default
=2, precision
=3,
82 description
='Default unit height',
85 name
='Top', min=0, max=50,
86 default
=0.03, precision
=3,
87 description
='Default top shelf position',
89 bottom
: FloatProperty(
90 name
='Bottom', min=0, max=50,
91 default
=0.07, precision
=3,
92 description
='Default bottom self position',
96 ('1', "Full side", ""),
100 description
="Type of side construction",
104 name
="Floor origin in Z=0",
105 description
="Use Z=0 axis as vertical origin floor position",
109 shelves_num
: IntProperty(
110 name
='Number of Units',
113 description
='Number total of shelves units',
115 shelves
: CollectionProperty(type=ShelvesProperties
)
118 crt_mat
: BoolProperty(
119 name
="Create default Cycles materials",
120 description
="Create default materials for Cycles render",
124 # -----------------------------------------------------
125 # Draw (create UI interface)
126 # -----------------------------------------------------
127 # noinspection PyUnusedLocal
128 def draw(self
, context
):
130 space
= bpy
.context
.space_data
131 if not space
.local_view
:
132 # Imperial units warning
133 if bpy
.context
.scene
.unit_settings
.system
== "IMPERIAL":
135 row
.label(text
="Warning: Imperial units not supported", icon
='COLOR_RED')
139 row
.prop(self
, 'thickness')
140 row
.prop(self
, 'sthickness')
142 row
.prop(self
, 'depth')
143 row
.prop(self
, 'height')
145 row
.prop(self
, 'top')
146 row
.prop(self
, 'bottom')
148 row
.prop(self
, 'stype')
149 row
.prop(self
, 'fitZ')
153 row
.prop(self
, 'shelves_num')
154 # Add menu for shelves
155 if self
.shelves_num
> 0:
156 for idx
in range(0, self
.shelves_num
):
158 add_shelves(self
, box
, idx
+ 1, self
.shelves
[idx
])
161 if not context
.scene
.render
.engine
in {'CYCLES', 'BLENDER_EEVEE'}:
163 box
.prop(self
, 'crt_mat')
166 row
.label(text
="Warning: Operator does not work in local view mode", icon
='ERROR')
168 # -----------------------------------------------------
170 # -----------------------------------------------------
171 # noinspection PyUnusedLocal
172 def execute(self
, context
):
173 if bpy
.context
.mode
== "OBJECT":
174 # Create all elements
175 for i
in range(len(self
.shelves
) - 1, self
.shelves_num
):
179 create_shelves_mesh(self
)
182 self
.report({'WARNING'}, "Archimesh: Option only valid in Object mode")
186 # -----------------------------------------------------
187 # Add shelves parameters
188 # -----------------------------------------------------
189 def add_shelves(self
, box
, num
, sh
):
191 row
.label(text
="Unit " + str(num
))
197 if self
.stype
!= "99":
199 row
.prop(sh
, 'right')
207 row
.prop(sh
, 'sNum', slider
=True)
242 # ------------------------------------------------------------------------------
244 # All custom values are passed using self container (self.myvariable)
245 # ------------------------------------------------------------------------------
246 def create_shelves_mesh(self
):
248 for o
in bpy
.data
.objects
:
249 if o
.select_get() is True:
251 bpy
.ops
.object.select_all(action
='DESELECT')
253 generate_shelves(self
)
258 # ------------------------------------------------------------------------------
260 # All custom values are passed using self container (self.myvariable)
261 # ------------------------------------------------------------------------------
262 def generate_shelves(self
):
265 location
= bpy
.context
.scene
.cursor
.location
266 myloc
= copy(location
) # copy location to keep 3D cursor position
273 # ------------------------------------------------------------------------------
275 # ------------------------------------------------------------------------------
276 for i
in range(0, self
.shelves_num
):
277 mydata
= create_unit(self
.stype
, "Shelves" + str(i
+ 1),
278 self
.thickness
, self
.sthickness
,
279 self
.shelves
[i
].sX
, self
.depth
+ self
.shelves
[i
].wY
, self
.height
+ self
.shelves
[i
].wZ
,
280 self
.shelves
[i
].pX
+ lastx
, myloc
[1] + self
.shelves
[i
].pY
, myloc
[2] + self
.shelves
[i
].pZ
,
281 self
.shelves
[i
].left
, self
.shelves
[i
].right
,
282 self
.shelves
[i
].sNum
,
283 (self
.shelves
[i
].Z01
, self
.shelves
[i
].Z02
, self
.shelves
[i
].Z03
,
284 self
.shelves
[i
].Z04
, self
.shelves
[i
].Z05
, self
.shelves
[i
].Z06
,
285 self
.shelves
[i
].Z07
, self
.shelves
[i
].Z08
, self
.shelves
[i
].Z09
,
286 self
.shelves
[i
].Z10
, self
.shelves
[i
].Z11
, self
.shelves
[i
].Z12
),
287 self
.top
, self
.bottom
)
288 boxes
.extend([mydata
[0]])
297 for o
in bpy
.data
.objects
:
298 if o
.select_get() is True:
301 boxes
[0].select_set(True)
302 bpy
.context
.view_layer
.objects
.active
= boxes
[0]
305 if self
.crt_mat
and bpy
.context
.scene
.render
.engine
in {'CYCLES', 'BLENDER_EEVEE'}:
306 mat
= create_diffuse_material("Shelves_material", False, 0.8, 0.8, 0.8)
308 set_material(box
, mat
)
313 # ------------------------------------------------------------------------------
314 # Create shelves unit
316 # stype: type of sides
317 # objName: Name for the new object
318 # thickness: wood thickness (sides)
319 # sthickness: wood thickness (shelves)
323 # pX: position X axis
324 # pY: position Y axis
325 # pZ: position Z axis
326 # right: True-> create right side
327 # left: True-> create left side
328 # shelves: Number of shelves
329 # zPos: List with z shift for each self
330 # top: position of top shelf
331 # bottom: position of bottom shelf
332 # ------------------------------------------------------------------------------
333 def create_unit(stype
, objname
, thickness
, sthickness
, sx
, sy
, sz
, px
, py
, pz
, left
, right
, shelves
, zpos
,
340 # no Sides, then no thickness
344 # ------------------------------
346 # ------------------------------
347 if left
and stype
!= "99":
350 myvertex
.extend([(0, 0, 0), (0, -sy
, 0), (0, -sy
, sz
), (0, 0, sz
),
351 (thickness
, 0, 0), (thickness
, -sy
, 0), (thickness
, -sy
, sz
), (thickness
, 0, sz
)])
352 myfaces
.extend([(v
, v
+ 1, v
+ 2, v
+ 3), (v
+ 4, v
+ 5, v
+ 6, v
+ 7), (v
, v
+ 4, v
+ 7, v
+ 3),
353 (v
, v
+ 1, v
+ 5, v
+ 4),
354 (v
+ 3, v
+ 2, v
+ 6, v
+ 7), (v
+ 1, v
+ 2, v
+ 6, v
+ 5)])
359 myvertex
.extend([(0, 0, 0), (0, -thickness
, 0), (0, -thickness
, sz
), (0, 0, sz
),
360 (thickness
, 0, 0), (thickness
, -thickness
, 0), (thickness
, -thickness
, sz
),
362 myfaces
.extend([(v
, v
+ 1, v
+ 2, v
+ 3), (v
+ 4, v
+ 5, v
+ 6, v
+ 7), (v
, v
+ 4, v
+ 7, v
+ 3),
363 (v
, v
+ 1, v
+ 5, v
+ 4),
364 (v
+ 3, v
+ 2, v
+ 6, v
+ 7), (v
+ 1, v
+ 2, v
+ 6, v
+ 5)])
367 myvertex
.extend([(0, -sy
+ thickness
, 0), (0, -sy
, 0), (0, -sy
, sz
), (0, -sy
+ thickness
, sz
),
368 (thickness
, -sy
+ thickness
, 0), (thickness
, -sy
, 0), (thickness
, -sy
, sz
),
369 (thickness
, -sy
+ thickness
, sz
)])
370 myfaces
.extend([(v
, v
+ 1, v
+ 2, v
+ 3), (v
+ 4, v
+ 5, v
+ 6, v
+ 7), (v
, v
+ 4, v
+ 7, v
+ 3),
371 (v
, v
+ 1, v
+ 5, v
+ 4),
372 (v
+ 3, v
+ 2, v
+ 6, v
+ 7), (v
+ 1, v
+ 2, v
+ 6, v
+ 5)])
378 if right
and stype
!= "99":
379 width
= sx
- thickness
382 myvertex
.extend([(width
, 0, 0), (width
, -sy
, 0), (width
, -sy
, sz
), (width
, 0, sz
),
383 (width
+ thickness
, 0, 0), (width
+ thickness
, -sy
, 0), (width
+ thickness
, -sy
, sz
),
384 (width
+ thickness
, 0, sz
)])
385 myfaces
.extend([(v
, v
+ 1, v
+ 2, v
+ 3), (v
+ 4, v
+ 5, v
+ 6, v
+ 7), (v
, v
+ 4, v
+ 7, v
+ 3),
386 (v
, v
+ 1, v
+ 5, v
+ 4), (v
+ 3, v
+ 2, v
+ 6, v
+ 7), (v
+ 1, v
+ 2, v
+ 6, v
+ 5)])
391 myvertex
.extend([(width
, 0, 0), (width
, -thickness
, 0), (width
, -thickness
, sz
), (width
, 0, sz
),
392 (width
+ thickness
, 0, 0), (width
+ thickness
, -thickness
, 0),
393 (width
+ thickness
, -thickness
, sz
), (width
+ thickness
, 0, sz
)])
394 myfaces
.extend([(v
, v
+ 1, v
+ 2, v
+ 3), (v
+ 4, v
+ 5, v
+ 6, v
+ 7), (v
, v
+ 4, v
+ 7, v
+ 3),
395 (v
, v
+ 1, v
+ 5, v
+ 4), (v
+ 3, v
+ 2, v
+ 6, v
+ 7), (v
+ 1, v
+ 2, v
+ 6, v
+ 5)])
399 [(width
, -sy
+ thickness
, 0), (width
, -sy
, 0), (width
, -sy
, sz
), (width
, -sy
+ thickness
, sz
),
400 (width
+ thickness
, -sy
+ thickness
, 0), (width
+ thickness
, -sy
, 0), (width
+ thickness
, -sy
, sz
),
401 (width
+ thickness
, -sy
+ thickness
, sz
)])
402 myfaces
.extend([(v
, v
+ 1, v
+ 2, v
+ 3), (v
+ 4, v
+ 5, v
+ 6, v
+ 7), (v
, v
+ 4, v
+ 7, v
+ 3),
403 (v
, v
+ 1, v
+ 5, v
+ 4), (v
+ 3, v
+ 2, v
+ 6, v
+ 7), (v
+ 1, v
+ 2, v
+ 6, v
+ 5)])
410 width
= sx
- thickness
411 posx
= posx
+ thickness
413 # calculate vertical spaces
414 dist
= sz
- top
- bottom
- sthickness
415 # if only top/bottom the space is not necessary
417 space
= dist
/ (shelves
- 1)
423 for x
in range(shelves
):
429 posz1
= sz
- top
- sthickness
431 posz2
= posz1
- sthickness
432 myvertex
.extend([(posx
, 0, posz1
+ zpos
[x
]), (posx
, -sy
, posz1
+ zpos
[x
]),
433 (posx
, -sy
, posz2
+ zpos
[x
]), (posx
, 0, posz2
+ zpos
[x
]),
434 (width
, 0, posz1
+ zpos
[x
]), (width
, -sy
, posz1
+ zpos
[x
]),
435 (width
, -sy
, posz2
+ zpos
[x
]), (width
, 0, posz2
+ zpos
[x
])])
438 [(v
, v
+ 1, v
+ 2, v
+ 3), (v
+ 4, v
+ 5, v
+ 6, v
+ 7), (v
, v
+ 4, v
+ 7, v
+ 3), (v
, v
+ 1, v
+ 5, v
+ 4),
439 (v
+ 3, v
+ 2, v
+ 6, v
+ 7), (v
+ 1, v
+ 2, v
+ 6, v
+ 5)])
443 mymesh
= bpy
.data
.meshes
.new(objname
)
444 myobject
= bpy
.data
.objects
.new(objname
, mymesh
)
446 myobject
.location
[0] = px
447 myobject
.location
[1] = py
448 myobject
.location
[2] = pz
449 bpy
.context
.collection
.objects
.link(myobject
)
451 mymesh
.from_pydata(myvertex
, [], myfaces
)
452 mymesh
.update(calc_edges
=True)
454 return myobject
, px
+ sx
- thickness