From 2c76bb2bec64ac9f36e76d193c66b9b8f81b01e5 Mon Sep 17 00:00:00 2001 From: Maciej Klemarczyk Date: Sat, 11 Aug 2018 23:50:43 +0200 Subject: [PATCH 01/10] Simple shelve added, it generates simple shelve with door. --- __init__.py | 18 +- archlab_frnt_shelve_tool.py | 335 ++++++++++++++++++++++++++++++++++++ 2 files changed, 352 insertions(+), 1 deletion(-) create mode 100644 archlab_frnt_shelve_tool.py diff --git a/__init__.py b/__init__.py index 00fbe7e..8be5fe4 100644 --- a/__init__.py +++ b/__init__.py @@ -33,7 +33,7 @@ "name": "Architecture Lab", "author": "Insma Software - Maciej Klemarczyk (mklemarczyk)", "location": "View3D > Add > Mesh > ArchLab", - "version": (1, 0, 9), + "version": (1, 1, 0), "blender": (2, 7, 9), "description": "Creates rooms, doors, windows, and other architecture objects", "wiki_url": "https://github.com/insma/ArchitectureLab/wiki", @@ -52,6 +52,7 @@ importlib.reload(archlab_bldn_wall_tool) importlib.reload(archlab_dcrt_glass_tool) importlib.reload(archlab_dcrt_plate_tool) + importlib.reload(archlab_frnt_shelve_tool) importlib.reload(archlab_mesh_cube_tool) importlib.reload(archlab_mesh_cube_tool) importlib.reload(archlab_mesh_plane_tool) @@ -64,6 +65,7 @@ from . import archlab_bldn_wall_tool from . import archlab_dcrt_glass_tool from . import archlab_dcrt_plate_tool + from . import archlab_frnt_shelve_tool from . import archlab_mesh_circle_tool from . import archlab_mesh_cube_tool from . import archlab_mesh_plane_tool @@ -82,6 +84,8 @@ archlab_dcrt_glass_tool.ArchLabGlassGeneratorPanel, archlab_dcrt_plate_tool.ArchLabPlate, archlab_dcrt_plate_tool.ArchLabPlateGeneratorPanel, + archlab_frnt_shelve_tool.ArchLabShelve, + archlab_frnt_shelve_tool.ArchLabShelveGeneratorPanel, archlab_mesh_circle_tool.ArchLabCircle, archlab_mesh_circle_tool.ArchLabCircleGeneratorPanel, archlab_mesh_cube_tool.ArchLabCube, @@ -116,6 +120,16 @@ ) +# ---------------------------------------------------------- +# Furnitures menu +# ---------------------------------------------------------- +class ArchLabMeshFurnituresAdd(Menu): + bl_idname = "INFO_MT_archlab_mesh_furnitures_add" + bl_label = "Furnitures" + + def draw(self, context): + self.layout.operator("mesh.archlab_shelve", text="Add Shelve") + # ---------------------------------------------------------- # Decorations menu # ---------------------------------------------------------- @@ -156,9 +170,11 @@ def draw(self, context): self.layout.separator() self.layout.menu("INFO_MT_archlab_mesh_primitives_add", text="Primitives", icon="GROUP") self.layout.menu("INFO_MT_archlab_mesh_decorations_add", text="Decorations", icon="GROUP") + self.layout.menu("INFO_MT_archlab_mesh_furnitures_add", text="Furnitures", icon="GROUP") modules.extend([ ArchLabMeshCustomMenuAdd, + ArchLabMeshFurnituresAdd, ArchLabMeshDecorationsAdd, ArchLabMeshPrimitivesAdd ]) diff --git a/archlab_frnt_shelve_tool.py b/archlab_frnt_shelve_tool.py new file mode 100644 index 0000000..ba9ad7b --- /dev/null +++ b/archlab_frnt_shelve_tool.py @@ -0,0 +1,335 @@ +# ##### BEGIN MIT LICENSE BLOCK ##### +# MIT License +# +# Copyright (c) 2018 Insma Software +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ##### END MIT LICENSE BLOCK ##### + +# ---------------------------------------------------------- +# Author: Maciej Klemarczyk (mklemarczyk) +# ---------------------------------------------------------- +import bpy +from bpy.types import Operator, PropertyGroup, Object, Panel +from bpy.props import FloatProperty, CollectionProperty +from .archlab_utils import * + +# ------------------------------------------------------------------------------ +# Create main object for the shelve. +# ------------------------------------------------------------------------------ +def create_shelve(self, context): + # deselect all objects + for o in bpy.data.objects: + o.select = False + + # we create main object and mesh for shelve + shelvemesh = bpy.data.meshes.new("Shelve") + shelveobject = bpy.data.objects.new("Shelve", shelvemesh) + shelveobject.location = bpy.context.scene.cursor_location + bpy.context.scene.objects.link(shelveobject) + shelveobject.ArchLabShelveGenerator.add() + + shelveobject.ArchLabShelveGenerator[0].shelve_height = self.shelve_height + shelveobject.ArchLabShelveGenerator[0].shelve_width = self.shelve_width + shelveobject.ArchLabShelveGenerator[0].shelve_depth = self.shelve_depth + shelveobject.ArchLabShelveGenerator[0].shelve_thickness = self.shelve_thickness + + # we shape the mesh. + shape_shelve_mesh(shelveobject, shelvemesh) + + # we select, and activate, main object for the shelve. + shelveobject.select = True + bpy.context.scene.objects.active = shelveobject + +# ------------------------------------------------------------------------------ +# Shapes mesh and creates modifier solidify (the modifier, only the first time). +# ------------------------------------------------------------------------------ +def shape_shelve_mesh(myshelve, tmp_mesh, update=False): + sp = myshelve.ArchLabShelveGenerator[0] # "sp" means "shelve properties". + # Create shelve mesh data + update_shelve_mesh_data(tmp_mesh, sp.shelve_width, sp.shelve_height, sp.shelve_depth, sp.shelve_thickness) + myshelve.data = tmp_mesh + + remove_doubles(myshelve) + set_normals(myshelve) + + if sp.shelve_thickness > 0.0: + if update is False or is_solidify(myshelve) is False: + set_modifier_solidify(myshelve, sp.shelve_thickness) + else: + for mod in myshelve.modifiers: + if mod.type == 'SOLIDIFY': + mod.thickness = sp.shelve_thickness + # Move to Top SOLIDIFY + movetotopsolidify(myshelve) + + else: # clear not used SOLIDIFY + for mod in myshelve.modifiers: + if mod.type == 'SOLIDIFY': + myshelve.modifiers.remove(mod) + + # deactivate others + for o in bpy.data.objects: + if o.select is True and o.name != myshelve.name: + o.select = False + +# ------------------------------------------------------------------------------ +# Creates shelve mesh data. +# ------------------------------------------------------------------------------ +def update_shelve_mesh_data(mymesh, width, height, depth, thickness): + basethick = thickness /2 + posx = width /2 + posy = depth /2 + posz = height +basethick + + myvertices = [ + (-posx, -posy, basethick), (posx, -posy, basethick), + (-posx, posy, basethick), (posx, posy, basethick), + (-posx, -posy, posz), (posx, -posy, posz), + (-posx, posy, posz), (posx, posy, posz)] + + thickdiff = thickness /2 + 0.001 + myvertices.extend([ + (-posx + thickdiff, -posy + thickdiff, basethick + thickdiff), + (posx - thickdiff, -posy + thickdiff, basethick + thickdiff), + (-posx + thickdiff, -posy + thickdiff, posz - thickdiff), + (posx - thickdiff, -posy + thickdiff, posz - thickdiff) + ]) + + myfaces = [ + (0, 1, 3, 2), + (0, 4, 6, 2), + (1, 5, 7, 3), + (2, 3, 7, 6), + (4, 5, 7, 6), + + (8, 9, 11, 10) + ] + + mymesh.from_pydata(myvertices, [], myfaces) + mymesh.update(calc_edges=True) + +# ------------------------------------------------------------------------------ +# Update shelve mesh. +# ------------------------------------------------------------------------------ +def update_shelve(self, context): + # When we update, the active object is the main object of the shelve. + o = bpy.context.active_object + oldmesh = o.data + oldname = o.data.name + # Now we deselect that shelve object to not delete it. + o.select = False + # and we create a new mesh for the shelve: + tmp_mesh = bpy.data.meshes.new("temp") + # deselect all objects + for obj in bpy.data.objects: + obj.select = False + # Finally we shape the main mesh again, + shape_shelve_mesh(o, tmp_mesh, True) + o.data = tmp_mesh + # Remove data (mesh of active object), + bpy.data.meshes.remove(oldmesh) + tmp_mesh.name = oldname + # and select, and activate, the main object of the shelve. + o.select = True + bpy.context.scene.objects.active = o + +# ----------------------------------------------------- +# Verify if solidify exist +# ----------------------------------------------------- +def is_solidify(myobject): + flag = False + try: + if myobject.modifiers is None: + return False + + for mod in myobject.modifiers: + if mod.type == 'SOLIDIFY': + flag = True + break + return flag + except AttributeError: + return False + +# ----------------------------------------------------- +# Move Solidify to Top +# ----------------------------------------------------- +def movetotopsolidify(myobject): + mymod = None + try: + if myobject.modifiers is not None: + for mod in myobject.modifiers: + if mod.type == 'SOLIDIFY': + mymod = mod + + if mymod is not None: + while myobject.modifiers[0] != mymod: + bpy.ops.object.modifier_move_up(modifier=mymod.name) + except AttributeError: + return + +# ----------------------------------------------------- +# Property definition creator +# ----------------------------------------------------- +def shelve_height_property(callback=None): + return FloatProperty( + name='Height', + soft_min=0.001, + default=0.65, precision=3, unit = 'LENGTH', + description='Shelve height', update=callback, + ) + +def shelve_width_property(callback=None): + return FloatProperty( + name='Width', + soft_min=0.001, + default=0.60, precision=3, unit = 'LENGTH', + description='Shelve width', update=callback, + ) + +def shelve_depth_property(callback=None): + return FloatProperty( + name='Depth', + soft_min=0.001, + default=0.40, precision=3, unit = 'LENGTH', + description='Shelve depth', update=callback, + ) + +def shelve_thickness_property(callback=None): + return FloatProperty( + name='Thickness', + soft_min=0.001, + default=0.015, precision=4, unit = 'LENGTH', + description='Thickness of the shelve', update=callback, + ) + +# ------------------------------------------------------------------ +# Define property group class to create or modify a shelves. +# ------------------------------------------------------------------ +class ArchLabShelveProperties(PropertyGroup): + shelve_height = shelve_height_property(callback=update_shelve) + shelve_width = shelve_width_property(callback=update_shelve) + shelve_depth = shelve_depth_property(callback=update_shelve) + shelve_thickness = shelve_thickness_property(callback=update_shelve) + +bpy.utils.register_class(ArchLabShelveProperties) +Object.ArchLabShelveGenerator = CollectionProperty(type=ArchLabShelveProperties) + +# ------------------------------------------------------------------ +# Define panel class to modify shelves. +# ------------------------------------------------------------------ +class ArchLabShelveGeneratorPanel(Panel): + bl_idname = "OBJECT_PT_shelve_generator" + bl_label = "Shelve" + bl_space_type = 'VIEW_3D' + bl_region_type = 'TOOLS' + bl_category = 'ArchLab' + + # ----------------------------------------------------- + # Verify if visible + # ----------------------------------------------------- + @classmethod + def poll(cls, context): + o = context.object + act_op = context.active_operator + if o is None: + return False + if 'ArchLabShelveGenerator' not in o: + return False + if act_op is not None and act_op.bl_idname.endswith('archlab_shelve'): + return False + else: + return True + + # ----------------------------------------------------- + # Draw (create UI interface) + # ----------------------------------------------------- + def draw(self, context): + o = context.object + # If the selected object didn't be created with the group 'ArchLabShelveGenerator', this panel is not created. + try: + if 'ArchLabShelveGenerator' not in o: + return + except: + return + + layout = self.layout + if bpy.context.mode == 'EDIT_MESH': + layout.label('Warning: Operator does not work in edit mode.', icon='ERROR') + else: + shelve = o.ArchLabShelveGenerator[0] + row = layout.row() + row.prop(shelve, 'shelve_width') + row = layout.row() + row.prop(shelve, 'shelve_height') + row = layout.row() + row.prop(shelve, 'shelve_depth') + row = layout.row() + row.prop(shelve, 'shelve_thickness') + +# ------------------------------------------------------------------ +# Define operator class to create shelves +# ------------------------------------------------------------------ +class ArchLabShelve(Operator): + bl_idname = "mesh.archlab_shelve" + bl_label = "Add Shelve" + bl_description = "Generate shelve mesh" + bl_category = 'ArchLab' + bl_options = {'REGISTER', 'UNDO'} + + # preset + shelve_height = shelve_height_property() + shelve_width = shelve_width_property() + shelve_depth = shelve_depth_property() + shelve_thickness = shelve_thickness_property() + + # ----------------------------------------------------- + # Draw (create UI interface) + # ----------------------------------------------------- + def draw(self, context): + layout = self.layout + space = bpy.context.space_data + if not space.local_view: + row = layout.row() + row.prop(self, 'shelve_height') + row = layout.row() + row.prop(self, 'shelve_width') + row = layout.row() + row.prop(self, 'shelve_depth') + row = layout.row() + row.prop(self, 'shelve_thickness') + else: + row = layout.row() + row.label("Warning: Operator does not work in local view mode", icon='ERROR') + + # ----------------------------------------------------- + # Execute + # ----------------------------------------------------- + def execute(self, context): + if bpy.context.mode == "OBJECT": + space = bpy.context.space_data + if not space.local_view: + create_shelve(self, context) + return {'FINISHED'} + else: + self.report({'WARNING'}, "ArchLab: Option only valid in global view mode") + return {'CANCELLED'} + else: + self.report({'WARNING'}, "ArchLab: Option only valid in Object mode") + return {'CANCELLED'} From 864f597b877413fd8bd1136d87d374718f8a4b36 Mon Sep 17 00:00:00 2001 From: Maciej Klemarczyk Date: Sat, 11 Aug 2018 23:51:19 +0200 Subject: [PATCH 02/10] Rotation util simplified with Euler structure and Vector rotate operation. --- archlab_utils.py | 41 +++++------------------------------------ 1 file changed, 5 insertions(+), 36 deletions(-) diff --git a/archlab_utils.py b/archlab_utils.py index fa682f9..f40b82e 100644 --- a/archlab_utils.py +++ b/archlab_utils.py @@ -28,7 +28,7 @@ import bpy from math import sin, cos, radians -from mathutils import Vector, Matrix +from mathutils import Vector, Matrix, Euler from os import path import json @@ -172,41 +172,10 @@ def rotate_point3d(pos, anglex=0.0, angley=0.0, anglez=0.0): # Rotates a point in 3D space with specified angle in radians # -------------------------------------------------------------------- def rotate_point3d_rad(pos, anglex=0.0, angley=0.0, anglez=0.0): - v1 = Vector(pos) - mat1 = Matrix([ - [1, 0, 0], - [0, 1, 0], - [0, 0, 1] - ]) - if not anglez == 0.0: - cosa1 = cos(anglez) - sina1 = sin(anglez) - mat2 = Matrix([ - [cosa1, -sina1, 0], - [sina1, cosa1, 0], - [0, 0, 1] - ]) - mat1 = mat1 * mat2 - if not angley == 0.0: - cosa1 = cos(angley) - sina1 = sin(angley) - mat2 = Matrix([ - [cosa1, 0, -sina1], - [0, 1, 0], - [sina1, 0, cosa1] - ]) - mat1 = mat1 * mat2 - if not anglex == 0.0: - cosa1 = cos(anglex) - sina1 = sin(anglex) - mat2 = Matrix([ - [1, 0, 0], - [0, cosa1, -sina1], - [0, sina1, cosa1] - ]) - mat1 = mat1 * mat2 - v2 = mat1 * v1 - return v2 + genvector = Vector(pos) + myEuler = Euler((anglex, angley, anglez),'XYZ') + genvector.rotate(myEuler) + return genvector # -------------------------------------------------------------------- # Rotates a point in 2D space with specified angle From 7d2bcd0e56394ad8f9991f553a71553432b5bda0 Mon Sep 17 00:00:00 2001 From: Maciej Klemarczyk Date: Sun, 12 Aug 2018 18:55:24 +0200 Subject: [PATCH 03/10] Simple shelve armature door added --- archlab_frnt_shelve_tool.py | 142 +++++++++++++++++++++++++++++++++++- archlab_utils.py | 11 +++ 2 files changed, 151 insertions(+), 2 deletions(-) diff --git a/archlab_frnt_shelve_tool.py b/archlab_frnt_shelve_tool.py index ba9ad7b..c790473 100644 --- a/archlab_frnt_shelve_tool.py +++ b/archlab_frnt_shelve_tool.py @@ -27,7 +27,7 @@ # ---------------------------------------------------------- import bpy from bpy.types import Operator, PropertyGroup, Object, Panel -from bpy.props import FloatProperty, CollectionProperty +from bpy.props import BoolProperty, FloatProperty, CollectionProperty from .archlab_utils import * # ------------------------------------------------------------------------------ @@ -38,7 +38,7 @@ def create_shelve(self, context): for o in bpy.data.objects: o.select = False - # we create main object and mesh for shelve + # we create shelve object and mesh shelvemesh = bpy.data.meshes.new("Shelve") shelveobject = bpy.data.objects.new("Shelve", shelvemesh) shelveobject.location = bpy.context.scene.cursor_location @@ -49,10 +49,22 @@ def create_shelve(self, context): shelveobject.ArchLabShelveGenerator[0].shelve_width = self.shelve_width shelveobject.ArchLabShelveGenerator[0].shelve_depth = self.shelve_depth shelveobject.ArchLabShelveGenerator[0].shelve_thickness = self.shelve_thickness + shelveobject.ArchLabShelveGenerator[0].shelve_armature = self.shelve_armature # we shape the mesh. shape_shelve_mesh(shelveobject, shelvemesh) + if self.shelve_armature: + # we create main object and mesh for shelve + shelvearmature = bpy.data.armatures.new("Shelve Armature") + shelvearmatureobject = bpy.data.objects.new("Shelve Armature", shelvearmature) + shelvearmatureobject.location = bpy.context.scene.cursor_location + shelvearmatureobject.parent = shelveobject + bpy.context.scene.objects.link(shelvearmatureobject) + + # we shape the armature. + shape_shelve_armature(shelveobject, shelvearmatureobject, shelvearmature) + # we select, and activate, main object for the shelve. shelveobject.select = True bpy.context.scene.objects.active = shelveobject @@ -69,6 +81,12 @@ def shape_shelve_mesh(myshelve, tmp_mesh, update=False): remove_doubles(myshelve) set_normals(myshelve) + # Create Door vertex group + if not is_vertex_group(myshelve, 'Shelve Door'): + doorvg = myshelve.vertex_groups.new() + doorvg.name = 'Shelve Door' + doorvg.add(index=[8, 9, 11, 10], weight=1, type='ADD') + if sp.shelve_thickness > 0.0: if update is False or is_solidify(myshelve) is False: set_modifier_solidify(myshelve, sp.shelve_thickness) @@ -89,6 +107,29 @@ def shape_shelve_mesh(myshelve, tmp_mesh, update=False): if o.select is True and o.name != myshelve.name: o.select = False +# ------------------------------------------------------------------------------ +# Shapes armature and creates modifier armature (the modifier, only the first time). +# ------------------------------------------------------------------------------ +def shape_shelve_armature(myshelve, myarmatureobj, myarmature, update=False): + sp = myshelve.ArchLabShelveGenerator[0] # "sp" means "shelve properties". + # Create shelve armature data + update_shelve_armature_data(myarmatureobj, myarmature, sp.shelve_width, sp.shelve_height, sp.shelve_depth, sp.shelve_thickness) + + if sp.shelve_armature: + if update is False or is_armature(myshelve) is False: + set_modifier_armature(myshelve, myarmatureobj) + else: + for mod in myshelve.modifiers: + if mod.type == 'ARMATURE': + mod.thickness = sp.shelve_thickness + # Move to Top ARMATURE + movetotoparmature(myshelve) + + else: # clear not used ARMATURE + for mod in myshelve.modifiers: + if mod.type == 'ARMATURE': + myshelve.modifiers.remove(mod) + # ------------------------------------------------------------------------------ # Creates shelve mesh data. # ------------------------------------------------------------------------------ @@ -125,6 +166,39 @@ def update_shelve_mesh_data(mymesh, width, height, depth, thickness): mymesh.from_pydata(myvertices, [], myfaces) mymesh.update(calc_edges=True) +# ------------------------------------------------------------------------------ +# Creates shelve armature data. +# ------------------------------------------------------------------------------ +def update_shelve_armature_data(myarmatureobj, myarmature, width, height, depth, thickness): + basethick = thickness /2 + posx = width /2 + posy = depth /2 + posz = height /2 +basethick + thickdiff = thickness /2 + 0.001 + + prev_o = bpy.context.scene.objects.active + bpy.context.scene.objects.active = myarmatureobj + myarmatureobj.select = True + bpy.ops.object.editmode_toggle() + + doorbone = myarmature.edit_bones.new('Shelve Door') + doorbone.head = (posx - thickdiff, -posy + thickdiff, posz ) + doorbone.tail = (-posx + thickdiff, -posy + thickdiff, posz) + + bpy.ops.object.editmode_toggle() + bpy.context.scene.objects.active = prev_o + + doorbone = myarmatureobj.pose.bones[0] + doorbone.rotation_mode = 'XYZ' + doorbone.lock_location[0] = True + doorbone.lock_location[1] = True + doorbone.lock_location[2] = True + doorbone.lock_rotation[0] = True + doorbone.lock_rotation[1] = True + doorbone.lock_scale[0] = True + doorbone.lock_scale[1] = True + doorbone.lock_scale[2] = True + # ------------------------------------------------------------------------------ # Update shelve mesh. # ------------------------------------------------------------------------------ @@ -150,6 +224,57 @@ def update_shelve(self, context): o.select = True bpy.context.scene.objects.active = o +# ----------------------------------------------------- +# Verify if vertex group exist +# ----------------------------------------------------- +def is_vertex_group(myobject, vgname): + flag = False + try: + if myobject.vertex_groups is None: + return False + + for vg in myobject.vertex_groups: + if vg.name == vgname: + flag = True + break + return flag + except AttributeError: + return False + +# ----------------------------------------------------- +# Verify if armature exist +# ----------------------------------------------------- +def is_armature(myobject): + flag = False + try: + if myobject.modifiers is None: + return False + + for mod in myobject.modifiers: + if mod.type == 'ARMATURE': + flag = True + break + return flag + except AttributeError: + return False + +# ----------------------------------------------------- +# Move Armature to Top +# ----------------------------------------------------- +def movetotoparmature(myobject): + mymod = None + try: + if myobject.modifiers is not None: + for mod in myobject.modifiers: + if mod.type == 'ARMATURE': + mymod = mod + + if mymod is not None: + while myobject.modifiers[0] != mymod: + bpy.ops.object.modifier_move_up(modifier=mymod.name) + except AttributeError: + return + # ----------------------------------------------------- # Verify if solidify exist # ----------------------------------------------------- @@ -219,6 +344,13 @@ def shelve_thickness_property(callback=None): description='Thickness of the shelve', update=callback, ) +def shelve_armature_property(callback=None): + return BoolProperty( + name='Armature', + default=False, + description='Create armature for the shelve door', update=callback, + ) + # ------------------------------------------------------------------ # Define property group class to create or modify a shelves. # ------------------------------------------------------------------ @@ -227,6 +359,7 @@ class ArchLabShelveProperties(PropertyGroup): shelve_width = shelve_width_property(callback=update_shelve) shelve_depth = shelve_depth_property(callback=update_shelve) shelve_thickness = shelve_thickness_property(callback=update_shelve) + shelve_armature = shelve_armature_property(callback=update_shelve) bpy.utils.register_class(ArchLabShelveProperties) Object.ArchLabShelveGenerator = CollectionProperty(type=ArchLabShelveProperties) @@ -254,6 +387,8 @@ def poll(cls, context): return False if act_op is not None and act_op.bl_idname.endswith('archlab_shelve'): return False + if o.ArchLabShelveGenerator[0].shelve_armature: + return False else: return True @@ -298,6 +433,7 @@ class ArchLabShelve(Operator): shelve_width = shelve_width_property() shelve_depth = shelve_depth_property() shelve_thickness = shelve_thickness_property() + shelve_armature = shelve_armature_property() # ----------------------------------------------------- # Draw (create UI interface) @@ -314,6 +450,8 @@ def draw(self, context): row.prop(self, 'shelve_depth') row = layout.row() row.prop(self, 'shelve_thickness') + row = layout.row() + row.prop(self, 'shelve_armature') else: row = layout.row() row.label("Warning: Operator does not work in local view mode", icon='ERROR') diff --git a/archlab_utils.py b/archlab_utils.py index f40b82e..652e95c 100644 --- a/archlab_utils.py +++ b/archlab_utils.py @@ -106,6 +106,17 @@ def set_material(ob, matname, index = 0): ob.data.materials.append(mat) return mat +# -------------------------------------------------------------------- +# Adds armature modifier +# -------------------------------------------------------------------- +def set_modifier_armature(myobject, armatureobject, modname = "Armature ArchLib"): + modid = myobject.modifiers.find(modname) + if (modid == -1): + mod = myobject.modifiers.new(name=modname, type="ARMATURE") + else: + mod = myobject.modifiers[modname] + mod.object = armatureobject + # -------------------------------------------------------------------- # Adds array modifier # -------------------------------------------------------------------- From ff29ea44e8420d5f4f4f571b09f37a0c1b106cd4 Mon Sep 17 00:00:00 2001 From: Maciej Klemarczyk Date: Sun, 12 Aug 2018 19:56:24 +0200 Subject: [PATCH 04/10] Simple bench mesh added --- __init__.py | 5 + archlab_frnt_bench_tool.py | 248 +++++++++++++++++++++++++++++++++++++ data/meshes.json | 8 ++ 3 files changed, 261 insertions(+) create mode 100644 archlab_frnt_bench_tool.py diff --git a/__init__.py b/__init__.py index 8be5fe4..bed0f04 100644 --- a/__init__.py +++ b/__init__.py @@ -52,6 +52,7 @@ importlib.reload(archlab_bldn_wall_tool) importlib.reload(archlab_dcrt_glass_tool) importlib.reload(archlab_dcrt_plate_tool) + importlib.reload(archlab_frnt_bench_tool) importlib.reload(archlab_frnt_shelve_tool) importlib.reload(archlab_mesh_cube_tool) importlib.reload(archlab_mesh_cube_tool) @@ -65,6 +66,7 @@ from . import archlab_bldn_wall_tool from . import archlab_dcrt_glass_tool from . import archlab_dcrt_plate_tool + from . import archlab_frnt_bench_tool from . import archlab_frnt_shelve_tool from . import archlab_mesh_circle_tool from . import archlab_mesh_cube_tool @@ -84,6 +86,8 @@ archlab_dcrt_glass_tool.ArchLabGlassGeneratorPanel, archlab_dcrt_plate_tool.ArchLabPlate, archlab_dcrt_plate_tool.ArchLabPlateGeneratorPanel, + archlab_frnt_bench_tool.ArchLabBench, + archlab_frnt_bench_tool.ArchLabBenchGeneratorPanel, archlab_frnt_shelve_tool.ArchLabShelve, archlab_frnt_shelve_tool.ArchLabShelveGeneratorPanel, archlab_mesh_circle_tool.ArchLabCircle, @@ -128,6 +132,7 @@ class ArchLabMeshFurnituresAdd(Menu): bl_label = "Furnitures" def draw(self, context): + self.layout.operator("mesh.archlab_bench", text="Add Bench") self.layout.operator("mesh.archlab_shelve", text="Add Shelve") # ---------------------------------------------------------- diff --git a/archlab_frnt_bench_tool.py b/archlab_frnt_bench_tool.py new file mode 100644 index 0000000..dec33da --- /dev/null +++ b/archlab_frnt_bench_tool.py @@ -0,0 +1,248 @@ +# ##### BEGIN MIT LICENSE BLOCK ##### +# MIT License +# +# Copyright (c) 2018 Insma Software +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ##### END MIT LICENSE BLOCK ##### + +# ---------------------------------------------------------- +# Author: Maciej Klemarczyk (mklemarczyk) +# ---------------------------------------------------------- +import bpy +from bpy.types import Operator, PropertyGroup, Object, Panel +from bpy.props import FloatProperty, CollectionProperty +from .archlab_utils import * +from .archlab_utils_mesh_generator import * + +# ------------------------------------------------------------------------------ +# Create main object for the bench. +# ------------------------------------------------------------------------------ +def create_bench(self, context): + # deselect all objects + for o in bpy.data.objects: + o.select = False + + # we create main object and mesh for bench + benchmesh = bpy.data.meshes.new("Bench") + benchobject = bpy.data.objects.new("Bench", benchmesh) + benchobject.location = bpy.context.scene.cursor_location + bpy.context.scene.objects.link(benchobject) + benchobject.ArchLabBenchGenerator.add() + + benchobject.ArchLabBenchGenerator[0].bench_height = self.bench_height + benchobject.ArchLabBenchGenerator[0].bench_width = self.bench_width + benchobject.ArchLabBenchGenerator[0].bench_depth = self.bench_depth + + # we shape the mesh. + shape_bench_mesh(benchobject, benchmesh) + + # we select, and activate, main object for the bench. + benchobject.select = True + bpy.context.scene.objects.active = benchobject + +# ------------------------------------------------------------------------------ +# Shapes mesh and creates modifier solidify (the modifier, only the first time). +# ------------------------------------------------------------------------------ +def shape_bench_mesh(mybench, tmp_mesh, update=False): + sp = mybench.ArchLabBenchGenerator[0] # "sp" means "bench properties". + # Create bench mesh data + update_bench_mesh_data(tmp_mesh, sp.bench_width, sp.bench_height, sp.bench_depth) + mybench.data = tmp_mesh + + remove_doubles(mybench) + set_normals(mybench) + + # deactivate others + for o in bpy.data.objects: + if o.select is True and o.name != mybench.name: + o.select = False + +# ------------------------------------------------------------------------------ +# Creates bench mesh data. +# ------------------------------------------------------------------------------ +def update_bench_mesh_data(mymesh, width, height, depth): + (myvertices, myedges, myfaces) = generate_mesh_from_library( + 'BenchN', + size=(width, depth, height) + ) + + mymesh.from_pydata(myvertices, myedges, myfaces) + mymesh.update(calc_edges=True) + +# ------------------------------------------------------------------------------ +# Update bench mesh. +# ------------------------------------------------------------------------------ +def update_bench(self, context): + # When we update, the active object is the main object of the bench. + o = bpy.context.active_object + oldmesh = o.data + oldname = o.data.name + # Now we deselect that bench object to not delete it. + o.select = False + # and we create a new mesh for the bench: + tmp_mesh = bpy.data.meshes.new("temp") + # deselect all objects + for obj in bpy.data.objects: + obj.select = False + # Finally we shape the main mesh again, + shape_bench_mesh(o, tmp_mesh, True) + o.data = tmp_mesh + # Remove data (mesh of active object), + bpy.data.meshes.remove(oldmesh) + tmp_mesh.name = oldname + # and select, and activate, the main object of the bench. + o.select = True + bpy.context.scene.objects.active = o + +# ----------------------------------------------------- +# Property definition creator +# ----------------------------------------------------- +def bench_height_property(callback=None): + return FloatProperty( + name='Height', + soft_min=0.001, + default=0.45, precision=3, unit = 'LENGTH', + description='Bench height', update=callback, + ) + +def bench_width_property(callback=None): + return FloatProperty( + name='Width', + soft_min=0.001, + default=1.20, precision=3, unit = 'LENGTH', + description='Bench width', update=callback, + ) + +def bench_depth_property(callback=None): + return FloatProperty( + name='Depth', + soft_min=0.001, + default=0.34, precision=3, unit = 'LENGTH', + description='Bench depth', update=callback, + ) + +# ------------------------------------------------------------------ +# Define property group class to create or modify a benchs. +# ------------------------------------------------------------------ +class ArchLabBenchProperties(PropertyGroup): + bench_height = bench_height_property(callback=update_bench) + bench_width = bench_width_property(callback=update_bench) + bench_depth = bench_depth_property(callback=update_bench) + +bpy.utils.register_class(ArchLabBenchProperties) +Object.ArchLabBenchGenerator = CollectionProperty(type=ArchLabBenchProperties) + +# ------------------------------------------------------------------ +# Define panel class to modify benchs. +# ------------------------------------------------------------------ +class ArchLabBenchGeneratorPanel(Panel): + bl_idname = "OBJECT_PT_bench_generator" + bl_label = "Bench" + bl_space_type = 'VIEW_3D' + bl_region_type = 'TOOLS' + bl_category = 'ArchLab' + + # ----------------------------------------------------- + # Verify if visible + # ----------------------------------------------------- + @classmethod + def poll(cls, context): + o = context.object + act_op = context.active_operator + if o is None: + return False + if 'ArchLabBenchGenerator' not in o: + return False + if act_op is not None and act_op.bl_idname.endswith('archlab_bench'): + return False + else: + return True + + # ----------------------------------------------------- + # Draw (create UI interface) + # ----------------------------------------------------- + def draw(self, context): + o = context.object + # If the selected object didn't be created with the group 'ArchLabBenchGenerator', this panel is not created. + try: + if 'ArchLabBenchGenerator' not in o: + return + except: + return + + layout = self.layout + if bpy.context.mode == 'EDIT_MESH': + layout.label('Warning: Operator does not work in edit mode.', icon='ERROR') + else: + bench = o.ArchLabBenchGenerator[0] + row = layout.row() + row.prop(bench, 'bench_width') + row = layout.row() + row.prop(bench, 'bench_height') + row = layout.row() + row.prop(bench, 'bench_depth') + +# ------------------------------------------------------------------ +# Define operator class to create benchs +# ------------------------------------------------------------------ +class ArchLabBench(Operator): + bl_idname = "mesh.archlab_bench" + bl_label = "Add Bench" + bl_description = "Generate bench mesh" + bl_category = 'ArchLab' + bl_options = {'REGISTER', 'UNDO'} + + # preset + bench_height = bench_height_property() + bench_width = bench_width_property() + bench_depth = bench_depth_property() + + # ----------------------------------------------------- + # Draw (create UI interface) + # ----------------------------------------------------- + def draw(self, context): + layout = self.layout + space = bpy.context.space_data + if not space.local_view: + row = layout.row() + row.prop(self, 'bench_width') + row = layout.row() + row.prop(self, 'bench_height') + row = layout.row() + row.prop(self, 'bench_depth') + else: + row = layout.row() + row.label("Warning: Operator does not work in local view mode", icon='ERROR') + + # ----------------------------------------------------- + # Execute + # ----------------------------------------------------- + def execute(self, context): + if bpy.context.mode == "OBJECT": + space = bpy.context.space_data + if not space.local_view: + create_bench(self, context) + return {'FINISHED'} + else: + self.report({'WARNING'}, "ArchLab: Option only valid in global view mode") + return {'CANCELLED'} + else: + self.report({'WARNING'}, "ArchLab: Option only valid in Object mode") + return {'CANCELLED'} diff --git a/data/meshes.json b/data/meshes.json index 206f52d..2b72948 100644 --- a/data/meshes.json +++ b/data/meshes.json @@ -95,6 +95,14 @@ "Vertices": [[0.0076, 0.0000, 0.0025],[0.0076, 0.0000, 0.0051],[0.0925, 0.0000, 0.0170],[0.0668, 0.0000, 0.0025],[0.0904, 0.0000, 0.0170],[0.0925, 0.0000, 0.0153],[0.0702, 0.0000, 0.0051],[0.0698, 0.0000, 0.0000],[0.0713, 0.0000, 0.0000],[0.0668, 0.0000, 0.0051],[0.0686, 0.0000, 0.0025]], "Edges": [[10,3],[4,2],[3,0],[6,4],[2,5],[8,7],[5,8],[1,9],[7,10],[9,6]], "Faces": [] + }, + "BenchN": { + "Name": "Bench", + "ConstructMethod": "VEF", + "RealSize": [1.20, 0.34, 0.45], + "Vertices": [[-0.6000, -0.1700, 0.4500],[-0.6000, 0.1700, 0.4500],[0.6000, -0.1700, 0.4500],[0.6000, 0.1700, 0.4500],[-0.6000, -0.1700, 0.4250],[-0.6000, 0.1700, 0.4250],[0.6000, 0.1700, 0.4250],[0.6000, -0.1700, 0.4250],[-0.4000, -0.1700, 0.4500],[-0.4000, -0.1700, 0.4250],[-0.4000, 0.1700, 0.4500],[-0.4000, 0.1700, 0.4250],[0.4000, 0.1700, 0.4500],[0.4000, 0.1700, 0.4250],[0.4000, -0.1700, 0.4500],[0.4000, -0.1700, 0.4250],[-0.6000, -0.0300, 0.4500],[0.6000, -0.0300, 0.4500],[0.6000, -0.0300, 0.4250],[-0.6000, -0.0300, 0.4250],[-0.4000, -0.0300, 0.4500],[0.4000, -0.0300, 0.4500],[-0.6000, 0.0300, 0.4500],[-0.6000, 0.0300, 0.4250],[0.6000, 0.0300, 0.4500],[0.6000, 0.0300, 0.4250],[-0.4000, 0.0300, 0.0000],[-0.4000, 0.0300, 0.4500],[0.4000, 0.0300, 0.4500],[-0.6000, 0.1000, 0.4500],[-0.6000, 0.1000, 0.4250],[0.6000, 0.1000, 0.4500],[0.6000, 0.1000, 0.4250],[-0.4000, 0.1000, 0.4500],[0.4000, 0.1000, 0.4500],[0.4000, 0.1000, 0.0000],[0.6000, -0.1000, 0.4500],[0.6000, -0.1000, 0.4250],[-0.4000, -0.1000, 0.4500],[0.4000, -0.1000, 0.4500],[0.4000, -0.1000, 0.0000],[-0.6000, -0.1000, 0.4500],[-0.6000, -0.1000, 0.4250],[-0.3000, 0.1700, 0.4500],[-0.3000, 0.1700, 0.4250],[-0.3000, -0.1700, 0.4500],[-0.3000, -0.1700, 0.4250],[-0.3000, -0.0300, 0.4500],[-0.3000, -0.0300, 0.0000],[-0.3000, 0.0300, 0.0000],[-0.3000, 0.0300, 0.4500],[-0.3000, 0.1000, 0.4500],[-0.3000, -0.1000, 0.4500],[0.3000, -0.1700, 0.4500],[0.3000, -0.1700, 0.4250],[0.3000, 0.1700, 0.4500],[0.3000, 0.1700, 0.4250],[0.3000, -0.0300, 0.0000],[0.3000, -0.0300, 0.4500],[0.3000, 0.0300, 0.4500],[0.3000, 0.0300, 0.0000],[0.3000, 0.1000, 0.4500],[0.3000, -0.1000, 0.0000],[0.3000, -0.1000, 0.4500],[-0.3000, -0.1000, 0.4250],[-0.4000, -0.1000, 0.0000],[-0.3000, -0.1000, 0.0000],[-0.3000, 0.1000, 0.0000],[-0.4000, 0.1000, 0.0000],[-0.3000, 0.1000, 0.4250],[-0.4000, -0.1000, 0.4250],[-0.4000, -0.0300, 0.4250],[-0.4000, -0.0300, 0.0000],[-0.4000, 0.0300, 0.4250],[-0.4000, 0.1000, 0.4250],[0.3000, -0.1000, 0.4250],[0.4000, -0.0300, 0.0000],[0.4000, -0.1000, 0.4250],[0.4000, 0.1000, 0.4250],[0.4000, 0.0300, 0.0000],[0.3000, 0.1000, 0.4250],[0.3000, 0.1000, 0.0000],[-0.3000, -0.0300, 0.4250],[-0.3000, 0.0300, 0.4250],[0.4000, 0.0300, 0.4250],[0.4000, -0.0300, 0.4250],[0.3000, -0.0300, 0.4250],[0.3000, 0.0300, 0.4250]], + "Edges": [], + "Faces": [[30,29,1,5],[13,12,3,6],[37,36,2,7],[9,8,0,4],[38,41,0,8],[53,45,46,54],[43,55,56,44],[50,47,58,59],[5,1,10,11],[52,38,8,45],[46,45,8,9],[7,2,14,15],[36,39,14,2],[64,66,48,82],[56,55,12,13],[24,28,21,17],[50,27,20,47],[51,50,59,61],[42,19,71,70],[27,22,16,20],[25,24,17,18],[42,41,16,19],[32,31,24,25],[33,29,22,27],[32,25,84,78],[43,51,61,55],[51,33,27,50],[31,34,28,24],[81,35,79,60],[19,16,22,23],[83,49,67,69],[3,12,34,31],[43,10,33,51],[47,52,63,58],[10,1,29,33],[6,3,31,32],[23,22,29,30],[4,0,41,42],[57,76,40,62],[17,21,39,36],[47,20,38,52],[69,44,56,80],[18,37,77,85],[20,16,41,38],[18,17,36,37],[72,48,66,65],[87,80,81,60],[75,86,57,62],[83,69,80,87],[68,67,49,26],[82,83,87,86],[75,54,46,64],[11,10,43,44],[11,44,69,74],[21,58,63,39],[12,55,61,34],[34,61,59,28],[28,59,58,21],[75,64,82,86],[15,14,53,54],[39,63,53,14],[15,54,75,77],[66,64,70,65],[46,9,70,64],[68,74,69,67],[65,70,71,72],[26,73,74,68],[23,30,74,73],[40,77,75,62],[76,85,77,40],[35,78,84,79],[81,80,78,35],[56,13,78,80],[73,83,82,71],[26,49,83,73],[48,72,71,82],[87,84,85,86],[76,57,86,85],[60,79,84,87],[78,13,6,32],[77,37,7,15],[25,18,85,84],[70,9,4,42],[71,19,23,73],[74,30,5,11],[52,45,53,63]] } } } From c9cbfef2eba26cb4e51f056286b5680e3f9b1e8b Mon Sep 17 00:00:00 2001 From: Maciej Klemarczyk Date: Sun, 12 Aug 2018 19:59:23 +0200 Subject: [PATCH 05/10] Operators property order was changed, width should be first one. --- archlab_bldn_wall_tool.py | 4 ++-- archlab_frnt_shelve_tool.py | 4 ++-- archlab_mesh_cube_tool.py | 4 ++-- archlab_mesh_plane_tool.py | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/archlab_bldn_wall_tool.py b/archlab_bldn_wall_tool.py index a7a06b5..2f1f1a1 100644 --- a/archlab_bldn_wall_tool.py +++ b/archlab_bldn_wall_tool.py @@ -273,11 +273,11 @@ def draw(self, context): layout = self.layout space = bpy.context.space_data if not space.local_view: - row = layout.row() - row.prop(self, 'wall_height') row = layout.row() row.prop(self, 'wall_width') row = layout.row() + row.prop(self, 'wall_height') + row = layout.row() row.prop(self, 'wall_depth') else: row = layout.row() diff --git a/archlab_frnt_shelve_tool.py b/archlab_frnt_shelve_tool.py index c790473..2f10691 100644 --- a/archlab_frnt_shelve_tool.py +++ b/archlab_frnt_shelve_tool.py @@ -442,11 +442,11 @@ def draw(self, context): layout = self.layout space = bpy.context.space_data if not space.local_view: - row = layout.row() - row.prop(self, 'shelve_height') row = layout.row() row.prop(self, 'shelve_width') row = layout.row() + row.prop(self, 'shelve_height') + row = layout.row() row.prop(self, 'shelve_depth') row = layout.row() row.prop(self, 'shelve_thickness') diff --git a/archlab_mesh_cube_tool.py b/archlab_mesh_cube_tool.py index cd57039..d9d9192 100644 --- a/archlab_mesh_cube_tool.py +++ b/archlab_mesh_cube_tool.py @@ -218,11 +218,11 @@ def draw(self, context): layout = self.layout space = bpy.context.space_data if not space.local_view: - row = layout.row() - row.prop(self, 'cube_height') row = layout.row() row.prop(self, 'cube_width') row = layout.row() + row.prop(self, 'cube_height') + row = layout.row() row.prop(self, 'cube_depth') else: row = layout.row() diff --git a/archlab_mesh_plane_tool.py b/archlab_mesh_plane_tool.py index a6ea77c..3ed365c 100644 --- a/archlab_mesh_plane_tool.py +++ b/archlab_mesh_plane_tool.py @@ -267,11 +267,11 @@ def draw(self, context): layout = self.layout space = bpy.context.space_data if not space.local_view: - row = layout.row() - row.prop(self, 'plane_height') row = layout.row() row.prop(self, 'plane_width') row = layout.row() + row.prop(self, 'plane_height') + row = layout.row() row.prop(self, 'plane_depth') else: row = layout.row() From 9c419865cb413fe3bd92e8ded8252cc0adf0bcc4 Mon Sep 17 00:00:00 2001 From: Maciej Klemarczyk Date: Sun, 12 Aug 2018 20:00:16 +0200 Subject: [PATCH 06/10] Utils extract_vertices method renamed to extract_edges as the two methods can not have the same name. --- archlab_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archlab_utils.py b/archlab_utils.py index 652e95c..1a51e51 100644 --- a/archlab_utils.py +++ b/archlab_utils.py @@ -300,7 +300,7 @@ def extract_vertices(): # -------------------------------------------------------------------- # Extracts edges from selected object # -------------------------------------------------------------------- -def extract_vertices(): +def extract_edges(): print("".join(["[(", "),(".join(",".join(str(v) for v in e.vertices) for e in bpy.context.object.data.edges), ")]"])) # -------------------------------------------------------------------- From 17ef773c66489d72f53ce2d0cb8c54431723924f Mon Sep 17 00:00:00 2001 From: Maciej Klemarczyk Date: Thu, 16 Aug 2018 14:33:58 +0200 Subject: [PATCH 07/10] Individual wall depth was added, each wall can have diffrent depht. --- archlab_bldn_room_tool.py | 111 ++++++++++++++++++++++++-------------- 1 file changed, 71 insertions(+), 40 deletions(-) diff --git a/archlab_bldn_room_tool.py b/archlab_bldn_room_tool.py index 507ee85..053fdee 100644 --- a/archlab_bldn_room_tool.py +++ b/archlab_bldn_room_tool.py @@ -28,6 +28,7 @@ import bpy from bpy.types import Operator, PropertyGroup, Object, Panel from bpy.props import IntProperty, FloatProperty, CollectionProperty +from math import sin from .archlab_utils import * # ------------------------------------------------------------------------------ @@ -50,6 +51,7 @@ def create_room(self, context): for wall in self.room_walls: wallprop = roomobject.ArchLabRoomGenerator[0].room_walls.add() wallprop.wall_width = wall.wall_width + wallprop.wall_depth = wall.wall_depth wallprop.wall_angle = wall.wall_angle # we shape the mesh. @@ -83,22 +85,6 @@ def shape_room_mesh(myroom, tmp_mesh, update=False): remove_doubles(myroom) set_normals(myroom) - if rp.room_wall_depth > 0.0: - if update is False or is_solidify(myroom) is False: - set_modifier_solidify(myroom, rp.room_wall_depth) - else: - for mod in myroom.modifiers: - if mod.type == 'SOLIDIFY': - mod.thickness = rp.room_wall_depth - mod.use_even_offset = True # The solidify have a problem with some wall angles - # Move to Top SOLIDIFY - movetotopsolidify(myroom) - - else: # clear not used SOLIDIFY - for mod in myroom.modifiers: - if mod.type == 'SOLIDIFY': - myroom.modifiers.remove(mod) - # deactivate others for o in bpy.data.objects: if o.select is True and o.name != myroom.name: @@ -108,14 +94,13 @@ def shape_room_mesh(myroom, tmp_mesh, update=False): # Creates room mesh data. # ------------------------------------------------------------------------------ def update_room_mesh_data(mymesh, height, walls): - myvertices = [] + myvertices = None myfaces = [] - - if len(walls) > 0: - myvertices = [(0.0, 0.0, 0.0), (0.0, 0.0, height)] + lwalls = len(walls) lastwi = 0 - lastp = [0.0, 0.0, 0.0] - lastpnorm = [1.0, 0.0, 0.0] + lastdepth = 0 + lastp = (0.0, 0.0, 0.0) + lastpnorm = (1.0, 0.0, 0.0) for wall in walls: pnorm = rotate_point3d_rad(lastpnorm, anglez=wall.wall_angle) p1 = [ @@ -123,11 +108,58 @@ def update_room_mesh_data(mymesh, height, walls): lastp[1] + pnorm[1] * wall.wall_width, lastp[2] + pnorm[2] * wall.wall_width ] - myvertices.extend([(p1[0], p1[1], 0.0), (p1[0], p1[1], height)]) - myfaces.append((lastwi * 2 + 0, lastwi * 2 + 1, lastwi * 2 + 3, lastwi * 2 + 2)) + wdepth = wall.wall_depth /2 + wdp = (-pnorm[1] * wdepth, pnorm[0] * wdepth, 0.0) + if myvertices is None: # First wall + myvertices = [ + (-wdp[0], -wdp[1], 0.0), + (-wdp[0], -wdp[1], height), + ( wdp[0], wdp[1], 0.0), + ( wdp[0], wdp[1], height) + ] + lastdepth = wdepth + myfaces.extend([ + [0, 1, 3, 2] + ]) + myfaces.extend([ + [lastwi * 4 + 0, lastwi * 4 + 1, lastwi * 4 + 5, lastwi * 4 + 4], + [lastwi * 4 + 0, lastwi * 4 + 2, lastwi * 4 + 6, lastwi * 4 + 4], + [lastwi * 4 + 1, lastwi * 4 + 3, lastwi * 4 + 7, lastwi * 4 + 5], + [lastwi * 4 + 2, lastwi * 4 + 3, lastwi * 4 + 7, lastwi * 4 + 6] + ]) + else: # Wall not first + sinwa = sin(wall.wall_angle) + crosswdp = (wdp[0], wdp[1], 0.0) + if not sinwa == 0: # angle = 0 + h1 = -lastpnorm * wdepth + h2 = pnorm * lastdepth + crosswdp = (h1 + h2) / sinwa + myvertices.extend([ + (lastp[0]-crosswdp[0], lastp[1]-crosswdp[1], 0.0), + (lastp[0]-crosswdp[0], lastp[1]-crosswdp[1], height), + (lastp[0]+crosswdp[0], lastp[1]+crosswdp[1], 0.0), + (lastp[0]+crosswdp[0], lastp[1]+crosswdp[1], height) + ]) + myfaces.extend([ + [lastwi * 4 + 0, lastwi * 4 + 1, lastwi * 4 + 5, lastwi * 4 + 4], + [lastwi * 4 + 0, lastwi * 4 + 2, lastwi * 4 + 6, lastwi * 4 + 4], + [lastwi * 4 + 1, lastwi * 4 + 3, lastwi * 4 + 7, lastwi * 4 + 5], + [lastwi * 4 + 2, lastwi * 4 + 3, lastwi * 4 + 7, lastwi * 4 + 6] + ]) + lastdepth == wdepth + if lwalls == lastwi +1: #Last wall + myvertices.extend([ + (p1[0]-wdp[0], p1[1]-wdp[1], 0.0), + (p1[0]-wdp[0], p1[1]-wdp[1], height), + (p1[0]+wdp[0], p1[1]+wdp[1], 0.0), + (p1[0]+wdp[0], p1[1]+wdp[1], height) + ]) + myfaces.extend([ + [lastwi * 4 + 4, lastwi * 4 + 5, lastwi * 4 + 7, lastwi * 4 + 6] + ]) lastwi = lastwi + 1 - lastp = p1 lastpnorm = pnorm + lastp = p1 mymesh.from_pydata(myvertices, [], myfaces) mymesh.update(calc_edges=True) @@ -202,10 +234,18 @@ def wall_width_property(callback=None): description='Wall width', update=callback, ) +def wall_depth_property(callback=None): + return FloatProperty( + name='Thickness', + soft_min=0.001, + default=0.025, precision=4, unit = 'LENGTH', + description='Thickness of the walls', update=callback, + ) + def wall_angle_property(callback=None): return FloatProperty( name='Angle', - soft_min=-3.14159, soft_max=3.14159, + soft_min=-2.79232, soft_max=2.79232, default=3.14159/2, precision=3, step=50, description='Angle of this wall with previous', update=callback, subtype='ANGLE', @@ -216,6 +256,7 @@ def wall_angle_property(callback=None): # ------------------------------------------------------------------ class ArchLabWallProperties(PropertyGroup): wall_width = wall_width_property(callback=update_room) + wall_depth = wall_depth_property(callback=update_room) wall_angle = wall_angle_property(callback=update_room) # ----------------------------------------------------- @@ -237,14 +278,6 @@ def room_wall_count_property(callback=None): description='Number of walls in the room', update=callback, ) -def room_wall_depth_property(callback=None): - return FloatProperty( - name='Thickness', - soft_min=0.001, - default=0.025, precision=4, unit = 'LENGTH', - description='Thickness of the walls', update=callback, - ) - def room_walls_property(callback=None): return CollectionProperty(type=ArchLabWallProperties) @@ -254,7 +287,6 @@ def room_walls_property(callback=None): class ArchLabRoomProperties(PropertyGroup): room_height = room_height_property(callback=update_room) room_wall_count = room_wall_count_property(callback=update_room) - room_wall_depth = room_wall_depth_property(callback=update_room) room_walls = room_walls_property(callback=update_room) bpy.utils.register_class(ArchLabWallProperties) @@ -307,8 +339,6 @@ def draw(self, context): row = layout.row() row.prop(room, 'room_height') row = layout.row() - row.prop(room, 'room_wall_depth') - row = layout.row() row.prop(room, 'room_wall_count') for wt in range(len(room.room_walls)): box = layout.box() @@ -316,6 +346,8 @@ def draw(self, context): row = box.row() row.prop(room.room_walls[wt], 'wall_width') row = box.row() + row.prop(room.room_walls[wt], 'wall_depth') + row = box.row() row.prop(room.room_walls[wt], 'wall_angle') # ------------------------------------------------------------------ @@ -331,7 +363,6 @@ class ArchLabRoom(Operator): # preset room_height = room_height_property() room_wall_count = room_wall_count_property() - room_wall_depth = room_wall_depth_property() room_walls = CollectionProperty(type=ArchLabWallProperties) # ----------------------------------------------------- @@ -344,8 +375,6 @@ def draw(self, context): row = layout.row() row.prop(self, 'room_height') row = layout.row() - row.prop(self, 'room_wall_depth') - row = layout.row() row.prop(self, 'room_wall_count') for wt in range(len(self.room_walls)): box = layout.box() @@ -353,6 +382,8 @@ def draw(self, context): row = box.row() row.prop(self.room_walls[wt], 'wall_width') row = box.row() + row.prop(self.room_walls[wt], 'wall_depth') + row = box.row() row.prop(self.room_walls[wt], 'wall_angle') else: row = layout.row() From 97163f23d71214a6f59b4f075433149a0a315dd5 Mon Sep 17 00:00:00 2001 From: Maciej Klemarczyk Date: Thu, 16 Aug 2018 14:52:22 +0200 Subject: [PATCH 08/10] Storing last depth was fixed, next walls were generated with wrong depth. --- archlab_bldn_room_tool.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/archlab_bldn_room_tool.py b/archlab_bldn_room_tool.py index 053fdee..9c52dd0 100644 --- a/archlab_bldn_room_tool.py +++ b/archlab_bldn_room_tool.py @@ -117,7 +117,6 @@ def update_room_mesh_data(mymesh, height, walls): ( wdp[0], wdp[1], 0.0), ( wdp[0], wdp[1], height) ] - lastdepth = wdepth myfaces.extend([ [0, 1, 3, 2] ]) @@ -146,7 +145,6 @@ def update_room_mesh_data(mymesh, height, walls): [lastwi * 4 + 1, lastwi * 4 + 3, lastwi * 4 + 7, lastwi * 4 + 5], [lastwi * 4 + 2, lastwi * 4 + 3, lastwi * 4 + 7, lastwi * 4 + 6] ]) - lastdepth == wdepth if lwalls == lastwi +1: #Last wall myvertices.extend([ (p1[0]-wdp[0], p1[1]-wdp[1], 0.0), @@ -160,6 +158,7 @@ def update_room_mesh_data(mymesh, height, walls): lastwi = lastwi + 1 lastpnorm = pnorm lastp = p1 + lastdepth = wdepth mymesh.from_pydata(myvertices, [], myfaces) mymesh.update(calc_edges=True) From 4b38965d6cf86a17aaee66fc6ba37e7b6a8202f3 Mon Sep 17 00:00:00 2001 From: Maciej Klemarczyk Date: Thu, 16 Aug 2018 15:30:42 +0200 Subject: [PATCH 09/10] Room ceiling and floor properties were implemented to complete room mesh. --- archlab_bldn_room_tool.py | 52 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/archlab_bldn_room_tool.py b/archlab_bldn_room_tool.py index 9c52dd0..05eb20a 100644 --- a/archlab_bldn_room_tool.py +++ b/archlab_bldn_room_tool.py @@ -27,7 +27,7 @@ # ---------------------------------------------------------- import bpy from bpy.types import Operator, PropertyGroup, Object, Panel -from bpy.props import IntProperty, FloatProperty, CollectionProperty +from bpy.props import BoolProperty, IntProperty, FloatProperty, CollectionProperty from math import sin from .archlab_utils import * @@ -47,6 +47,8 @@ def create_room(self, context): roomobject.ArchLabRoomGenerator.add() roomobject.ArchLabRoomGenerator[0].room_height = self.room_height + roomobject.ArchLabRoomGenerator[0].room_floor = self.room_floor + roomobject.ArchLabRoomGenerator[0].room_ceiling = self.room_ceiling roomobject.ArchLabRoomGenerator[0].room_wall_count = self.room_wall_count for wall in self.room_walls: wallprop = roomobject.ArchLabRoomGenerator[0].room_walls.add() @@ -79,11 +81,11 @@ def shape_room_mesh(myroom, tmp_mesh, update=False): rp.room_walls.remove(prwc) # Create room mesh data - update_room_mesh_data(tmp_mesh, rp.room_height, rp.room_walls) + update_room_mesh_data(tmp_mesh, rp.room_height, rp.room_walls, rp.room_floor, rp.room_ceiling) myroom.data = tmp_mesh remove_doubles(myroom) - set_normals(myroom) + #set_normals(myroom) # deactivate others for o in bpy.data.objects: @@ -93,9 +95,10 @@ def shape_room_mesh(myroom, tmp_mesh, update=False): # ------------------------------------------------------------------------------ # Creates room mesh data. # ------------------------------------------------------------------------------ -def update_room_mesh_data(mymesh, height, walls): +def update_room_mesh_data(mymesh, height, walls, has_floor, has_ceiling): myvertices = None myfaces = [] + lwalls = len(walls) lastwi = 0 lastdepth = 0 @@ -160,6 +163,20 @@ def update_room_mesh_data(mymesh, height, walls): lastp = p1 lastdepth = wdepth + if has_floor and lwalls > 1: + floorverts = [] + for wno in range(lwalls): + floorverts.append(wno * 4 + 2) + floorverts.append(lwalls * 4 + 2) + myfaces.append(floorverts) + + if has_ceiling and lwalls > 1: + ceilingverts = [] + for wno in range(lwalls, 0, -1): + ceilingverts.append(wno * 4 + 3) + ceilingverts.append(0 * 4 + 3) + myfaces.append(ceilingverts) + mymesh.from_pydata(myvertices, [], myfaces) mymesh.update(calc_edges=True) @@ -277,6 +294,20 @@ def room_wall_count_property(callback=None): description='Number of walls in the room', update=callback, ) +def room_floor_property(callback=None): + return BoolProperty( + name='Floor', + default=True, + description='Generates floor for the room', update=callback, + ) + +def room_ceiling_property(callback=None): + return BoolProperty( + name='Ceiling', + default=False, + description='Generates ceiling for the room', update=callback, + ) + def room_walls_property(callback=None): return CollectionProperty(type=ArchLabWallProperties) @@ -285,6 +316,9 @@ def room_walls_property(callback=None): # ------------------------------------------------------------------ class ArchLabRoomProperties(PropertyGroup): room_height = room_height_property(callback=update_room) + room_floor = room_floor_property(callback=update_room) + room_ceiling = room_ceiling_property(callback=update_room) + room_wall_count = room_wall_count_property(callback=update_room) room_wall_count = room_wall_count_property(callback=update_room) room_walls = room_walls_property(callback=update_room) @@ -338,6 +372,10 @@ def draw(self, context): row = layout.row() row.prop(room, 'room_height') row = layout.row() + row.prop(room, 'room_floor') + row = layout.row() + row.prop(room, 'room_ceiling') + row = layout.row() row.prop(room, 'room_wall_count') for wt in range(len(room.room_walls)): box = layout.box() @@ -361,6 +399,8 @@ class ArchLabRoom(Operator): # preset room_height = room_height_property() + room_floor = room_floor_property(callback=update_room) + room_ceiling = room_ceiling_property(callback=update_room) room_wall_count = room_wall_count_property() room_walls = CollectionProperty(type=ArchLabWallProperties) @@ -374,6 +414,10 @@ def draw(self, context): row = layout.row() row.prop(self, 'room_height') row = layout.row() + row.prop(self, 'room_floor') + row = layout.row() + row.prop(self, 'room_ceiling') + row = layout.row() row.prop(self, 'room_wall_count') for wt in range(len(self.room_walls)): box = layout.box() From f7c928784d1383faf065ae7914f16604b4fcc642 Mon Sep 17 00:00:00 2001 From: Maciej Klemarczyk Date: Thu, 16 Aug 2018 15:31:27 +0200 Subject: [PATCH 10/10] Walls normal vectors were fixed by proper order of vertices in faces without calling for set_normals method. --- archlab_bldn_room_tool.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/archlab_bldn_room_tool.py b/archlab_bldn_room_tool.py index 05eb20a..a9aaeea 100644 --- a/archlab_bldn_room_tool.py +++ b/archlab_bldn_room_tool.py @@ -124,10 +124,10 @@ def update_room_mesh_data(mymesh, height, walls, has_floor, has_ceiling): [0, 1, 3, 2] ]) myfaces.extend([ - [lastwi * 4 + 0, lastwi * 4 + 1, lastwi * 4 + 5, lastwi * 4 + 4], - [lastwi * 4 + 0, lastwi * 4 + 2, lastwi * 4 + 6, lastwi * 4 + 4], - [lastwi * 4 + 1, lastwi * 4 + 3, lastwi * 4 + 7, lastwi * 4 + 5], - [lastwi * 4 + 2, lastwi * 4 + 3, lastwi * 4 + 7, lastwi * 4 + 6] + [lastwi * 4 + 0, lastwi * 4 + 2, lastwi * 4 + 6, lastwi * 4 + 4], # bottom + [lastwi * 4 + 0, lastwi * 4 + 4, lastwi * 4 + 5, lastwi * 4 + 1], # outer + [lastwi * 4 + 1, lastwi * 4 + 5, lastwi * 4 + 7, lastwi * 4 + 3], # top + [lastwi * 4 + 2, lastwi * 4 + 3, lastwi * 4 + 7, lastwi * 4 + 6] # inner ]) else: # Wall not first sinwa = sin(wall.wall_angle) @@ -143,10 +143,10 @@ def update_room_mesh_data(mymesh, height, walls, has_floor, has_ceiling): (lastp[0]+crosswdp[0], lastp[1]+crosswdp[1], height) ]) myfaces.extend([ - [lastwi * 4 + 0, lastwi * 4 + 1, lastwi * 4 + 5, lastwi * 4 + 4], - [lastwi * 4 + 0, lastwi * 4 + 2, lastwi * 4 + 6, lastwi * 4 + 4], - [lastwi * 4 + 1, lastwi * 4 + 3, lastwi * 4 + 7, lastwi * 4 + 5], - [lastwi * 4 + 2, lastwi * 4 + 3, lastwi * 4 + 7, lastwi * 4 + 6] + [lastwi * 4 + 0, lastwi * 4 + 2, lastwi * 4 + 6, lastwi * 4 + 4], # bottom + [lastwi * 4 + 0, lastwi * 4 + 4, lastwi * 4 + 5, lastwi * 4 + 1], # outer + [lastwi * 4 + 1, lastwi * 4 + 5, lastwi * 4 + 7, lastwi * 4 + 3], # top + [lastwi * 4 + 2, lastwi * 4 + 3, lastwi * 4 + 7, lastwi * 4 + 6] # inner ]) if lwalls == lastwi +1: #Last wall myvertices.extend([ @@ -156,7 +156,7 @@ def update_room_mesh_data(mymesh, height, walls, has_floor, has_ceiling): (p1[0]+wdp[0], p1[1]+wdp[1], height) ]) myfaces.extend([ - [lastwi * 4 + 4, lastwi * 4 + 5, lastwi * 4 + 7, lastwi * 4 + 6] + [lastwi * 4 + 5, lastwi * 4 + 4, lastwi * 4 + 6, lastwi * 4 + 7] ]) lastwi = lastwi + 1 lastpnorm = pnorm