AnimAll: update translation
[blender-addons.git] / archimesh / achm_shelves_maker.py
blobbe1ef713f6db7b329e0a2f8c547e116b10197ab2
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 # ----------------------------------------------------------
10 import bpy
11 from copy import copy
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')
30 # Shelves
31 sNum: IntProperty(name='Shelves', min=0, max=12, default=6, description='Number total of shelves')
33 # 12 shelves (shelf)
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 # ------------------------------------------------------------------
54 # Define UI class
55 # Shelves
56 # ------------------------------------------------------------------
57 class ARCHIMESH_OT_Shelves(Operator):
58 bl_idname = "mesh.archimesh_shelves"
59 bl_label = "Shelves"
60 bl_description = "Shelves Generator"
61 bl_category = 'View'
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',
74 depth: FloatProperty(
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',
84 top: FloatProperty(
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',
94 stype: EnumProperty(
95 items=(
96 ('1', "Full side", ""),
97 ('4', "4 Legs", ""),
98 ('99', "None", "")),
99 name="Sides",
100 description="Type of side construction",
103 fitZ: BoolProperty(
104 name="Floor origin in Z=0",
105 description="Use Z=0 axis as vertical origin floor position",
106 default=True,
109 shelves_num: IntProperty(
110 name='Number of Units',
111 min=1, max=10,
112 default=1,
113 description='Number total of shelves units',
115 shelves: CollectionProperty(type=ShelvesProperties)
117 # Materials
118 crt_mat: BoolProperty(
119 name="Create default Cycles materials",
120 description="Create default materials for Cycles render",
121 default=True,
124 # -----------------------------------------------------
125 # Draw (create UI interface)
126 # -----------------------------------------------------
127 # noinspection PyUnusedLocal
128 def draw(self, context):
129 layout = self.layout
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":
134 row = layout.row()
135 row.label(text="Warning: Imperial units not supported", icon='COLOR_RED')
137 box = layout.box()
138 row = box.row()
139 row.prop(self, 'thickness')
140 row.prop(self, 'sthickness')
141 row = box.row()
142 row.prop(self, 'depth')
143 row.prop(self, 'height')
144 row = box.row()
145 row.prop(self, 'top')
146 row.prop(self, 'bottom')
147 row = box.row()
148 row.prop(self, 'stype')
149 row.prop(self, 'fitZ')
151 # Furniture number
152 row = layout.row()
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):
157 box = layout.box()
158 add_shelves(self, box, idx + 1, self.shelves[idx])
160 box = layout.box()
161 if not context.scene.render.engine in {'CYCLES', 'BLENDER_EEVEE'}:
162 box.enabled = False
163 box.prop(self, 'crt_mat')
164 else:
165 row = layout.row()
166 row.label(text="Warning: Operator does not work in local view mode", icon='ERROR')
168 # -----------------------------------------------------
169 # Execute
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):
176 self.shelves.add()
178 # Create shelves
179 create_shelves_mesh(self)
180 return {'FINISHED'}
181 else:
182 self.report({'WARNING'}, "Archimesh: Option only valid in Object mode")
183 return {'CANCELLED'}
186 # -----------------------------------------------------
187 # Add shelves parameters
188 # -----------------------------------------------------
189 def add_shelves(self, box, num, sh):
190 row = box.row()
191 row.label(text="Unit " + str(num))
192 row.prop(sh, 'sX')
194 row = box.row()
195 row.prop(sh, 'wY')
196 row.prop(sh, 'wZ')
197 if self.stype != "99":
198 row.prop(sh, 'left')
199 row.prop(sh, 'right')
201 row = box.row()
202 row.prop(sh, 'pX')
203 row.prop(sh, 'pY')
204 row.prop(sh, 'pZ')
206 row = box.row()
207 row.prop(sh, 'sNum', slider=True)
209 if sh.sNum >= 1:
210 row = box.row()
211 row.prop(sh, 'Z01')
212 if sh.sNum >= 2:
213 row.prop(sh, 'Z02')
214 if sh.sNum >= 3:
215 row.prop(sh, 'Z03')
217 if sh.sNum >= 4:
218 row = box.row()
219 row.prop(sh, 'Z04')
220 if sh.sNum >= 5:
221 row.prop(sh, 'Z05')
222 if sh.sNum >= 6:
223 row.prop(sh, 'Z06')
225 if sh.sNum >= 7:
226 row = box.row()
227 row.prop(sh, 'Z07')
228 if sh.sNum >= 8:
229 row.prop(sh, 'Z08')
230 if sh.sNum >= 9:
231 row.prop(sh, 'Z09')
233 if sh.sNum >= 10:
234 row = box.row()
235 row.prop(sh, 'Z10')
236 if sh.sNum >= 11:
237 row.prop(sh, 'Z11')
238 if sh.sNum >= 12:
239 row.prop(sh, 'Z12')
242 # ------------------------------------------------------------------------------
243 # Generate mesh data
244 # All custom values are passed using self container (self.myvariable)
245 # ------------------------------------------------------------------------------
246 def create_shelves_mesh(self):
247 # deactivate others
248 for o in bpy.data.objects:
249 if o.select_get() is True:
250 o.select_set(False)
251 bpy.ops.object.select_all(action='DESELECT')
252 # Create units
253 generate_shelves(self)
255 return
258 # ------------------------------------------------------------------------------
259 # Generate Units
260 # All custom values are passed using self container (self.myvariable)
261 # ------------------------------------------------------------------------------
262 def generate_shelves(self):
264 boxes = []
265 location = bpy.context.scene.cursor.location
266 myloc = copy(location) # copy location to keep 3D cursor position
267 # Fit to floor
268 if self.fitZ:
269 myloc[2] = 0
271 # Create units
272 lastx = myloc[0]
273 # ------------------------------------------------------------------------------
274 # Shelves
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]])
289 lastx = mydata[1]
291 # refine units
292 for box in boxes:
293 remove_doubles(box)
294 set_normals(box)
296 # deactivate others
297 for o in bpy.data.objects:
298 if o.select_get() is True:
299 o.select_set(False)
301 boxes[0].select_set(True)
302 bpy.context.view_layer.objects.active = boxes[0]
304 # Create materials
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)
307 for box in boxes:
308 set_material(box, mat)
310 return
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)
320 # sX: Size in X axis
321 # sY: Size in Y axis
322 # sZ: Size in Z axis
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,
334 top, bottom):
336 myvertex = []
337 myfaces = []
338 v = 0
340 # no Sides, then no thickness
341 if stype == "99":
342 thickness = 0
344 # ------------------------------
345 # Left side
346 # ------------------------------
347 if left and stype != "99":
348 # Full side
349 if stype == "1":
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)])
355 v += 8
356 # Four legs
357 if stype == "4":
358 # back
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),
361 (thickness, 0, 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)])
365 v += 8
366 # Front
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)])
373 v += 8
375 # -----------------
376 # Right side
377 # -----------------
378 if right and stype != "99":
379 width = sx - thickness
380 # Full side
381 if stype == "1":
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)])
387 v += 8
388 # Four legs
389 if stype == "4":
390 # back
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)])
396 v += 8
397 # Front
398 myvertex.extend(
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)])
404 v += 8
405 # -----------------
406 # shelves
407 # -----------------
408 posx = 0
409 # calculate width
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
416 if shelves > 2:
417 space = dist / (shelves - 1)
418 else:
419 space = 0
421 posz1 = bottom
423 for x in range(shelves):
424 # bottom
425 if x == 0:
426 posz1 = bottom
427 # top
428 if x == shelves - 1:
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])])
437 myfaces.extend(
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)])
440 v += 8
441 posz1 += space
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