diff options
author | meta-androcto <meta.androcto1@gmail.com> | 2016-08-03 03:10:18 +0300 |
---|---|---|
committer | meta-androcto <meta.androcto1@gmail.com> | 2016-08-03 03:10:18 +0300 |
commit | 5cd9040c995effc4c6bf233e820f741cbaf083ca (patch) | |
tree | 52571f0ec0726b6ea067db4a2eba14e939188f27 /archimesh/achm_stairs_maker.py | |
parent | 867ce6317b64a342ed0658702bed687fd3d087d7 (diff) |
move archimesh to release re: T37230
Diffstat (limited to 'archimesh/achm_stairs_maker.py')
-rw-r--r-- | archimesh/achm_stairs_maker.py | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/archimesh/achm_stairs_maker.py b/archimesh/achm_stairs_maker.py new file mode 100644 index 00000000..92558dc5 --- /dev/null +++ b/archimesh/achm_stairs_maker.py @@ -0,0 +1,434 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# <pep8 compliant> + +# ---------------------------------------------------------- +# Automatic generation of stairs +# Author: Antonio Vazquez (antonioya) +# +# ---------------------------------------------------------- +# noinspection PyUnresolvedReferences +import bpy +import math +from achm_tools import * + + +# ------------------------------------------------------------------ +# Define UI class +# Stairs +# ------------------------------------------------------------------ +class AchmStairs(bpy.types.Operator): + bl_idname = "mesh.archimesh_stairs" + bl_label = "Stairs" + bl_description = "Stairs Generator" + bl_category = 'Archimesh' + bl_options = {'REGISTER', 'UNDO'} + + # Define properties + model = bpy.props.EnumProperty( + items=( + ('1', "Rectangular", ""), + ('2', "Rounded", ""), + ), + name="Model", + description="Type of steps", + ) + radio = bpy.props.FloatProperty( + name='', + min=0.001, max=0.500, + default=0.20, precision=3, + description='Radius factor for rounded', + ) + curve = bpy.props.BoolProperty( + name="Include deformation handles", + description="Include a curve to modify the stairs curve", + default=False, + ) + + step_num = bpy.props.IntProperty( + name='Number of steps', + min=1, max=1000, + default=3, + description='Number total of steps', + ) + max_width = bpy.props.FloatProperty( + name='Width', + min=0.001, max=10, + default=1, precision=3, + description='Step maximum width', + ) + depth = bpy.props.FloatProperty( + name='Depth', + min=0.001, max=10, + default=0.30, precision=3, + description='Depth of the step', + ) + shift = bpy.props.FloatProperty( + name='Shift', + min=0.001, max=1, + default=1, precision=3, + description='Step shift in Y axis', + ) + thickness = bpy.props.FloatProperty( + name='Thickness', + min=0.001, max=10, + default=0.03, precision=3, + description='Step thickness', + ) + sizev = bpy.props.BoolProperty( + name="Variable width", + description="Steps are not equal in width", + default=False, + ) + back = bpy.props.BoolProperty( + name="Close sides", + description="Close all steps side to make a solid structure", + default=False, + ) + min_width = bpy.props.FloatProperty( + name='', + min=0.001, max=10, + default=1, precision=3, + description='Step minimum width', + ) + + height = bpy.props.FloatProperty( + name='height', + min=0.001, max=10, + default=0.14, precision=3, + description='Step height', + ) + front_gap = bpy.props.FloatProperty( + name='Front', + min=0, max=10, + default=0.03, + precision=3, + description='Front gap', + ) + side_gap = bpy.props.FloatProperty( + name='Side', + min=0, max=10, + default=0, precision=3, + description='Side gap', + ) + crt_mat = bpy.props.BoolProperty( + name="Create default Cycles materials", + description="Create default materials for Cycles render", + default=True, + ) + + # ----------------------------------------------------- + # Draw (create UI interface) + # ----------------------------------------------------- + # noinspection PyUnusedLocal + def draw(self, context): + layout = self.layout + space = bpy.context.space_data + if not space.local_view: + # Imperial units warning + if bpy.context.scene.unit_settings.system == "IMPERIAL": + row = layout.row() + row.label("Warning: Imperial units not supported", icon='COLOR_RED') + + box = layout.box() + row = box.row() + row.prop(self, 'model') + if self.model == "2": + row.prop(self, 'radio') + + box.prop(self, 'step_num') + row = box.row() + row.prop(self, 'max_width') + row.prop(self, 'depth') + row.prop(self, 'shift') + row = box.row() + row.prop(self, 'back') + row.prop(self, 'sizev') + row = box.row() + row.prop(self, 'curve') + # all equal + if self.sizev is True: + row.prop(self, 'min_width') + + box = layout.box() + row = box.row() + row.prop(self, 'thickness') + row.prop(self, 'height') + row = box.row() + row.prop(self, 'front_gap') + if self.model == "1": + row.prop(self, 'side_gap') + + box = layout.box() + box.prop(self, 'crt_mat') + else: + row = layout.row() + row.label("Warning: Operator does not work in local view mode", icon='ERROR') + + # ----------------------------------------------------- + # Execute + # ----------------------------------------------------- + # noinspection PyUnusedLocal + def execute(self, context): + if bpy.context.mode == "OBJECT": + create_stairs_mesh(self) + return {'FINISHED'} + else: + self.report({'WARNING'}, "Archimesh: Option only valid in Object mode") + return {'CANCELLED'} + + +# ------------------------------------------------------------------------------ +# Generate mesh data +# All custom values are passed using self container (self.myvariable) +# ------------------------------------------------------------------------------ +def create_stairs_mesh(self): + + # deactivate others + for o in bpy.data.objects: + if o.select is True: + o.select = False + + bpy.ops.object.select_all(False) + + # ------------------------ + # Create stairs + # ------------------------ + mydata = create_stairs(self, "Stairs") + mystairs = mydata[0] + mystairs.select = True + bpy.context.scene.objects.active = mystairs + remove_doubles(mystairs) + set_normals(mystairs) + set_modifier_mirror(mystairs, "X") + # ------------------------ + # Create curve handles + # ------------------------ + if self.curve: + x = mystairs.location.x + y = mystairs.location.y + z = mystairs.location.z + + last = mydata[1] + x1 = last[1] # use y + + myp = [((0, 0, 0), (- 0.25, 0, 0), (0.25, 0, 0)), + ((x1, 0, 0), (x1 - 0.25, 0, 0), (x1 + 0.25, 0, 0))] # double element + mycurve = create_bezier("Stairs_handle", myp, (x, y, z)) + set_modifier_curve(mystairs, mycurve) + + # ------------------------ + # Create materials + # ------------------------ + if self.crt_mat: + # Stairs material + mat = create_diffuse_material("Stairs_material", False, 0.8, 0.8, 0.8) + set_material(mystairs, mat) + + bpy.ops.object.select_all(False) + mystairs.select = True + bpy.context.scene.objects.active = mystairs + + return + + +# ------------------------------------------------------------------------------ +# Create rectangular Stairs +# ------------------------------------------------------------------------------ +def create_stairs(self, objname): + + myvertex = [] + myfaces = [] + index = 0 + + lastpoint = (0, 0, 0) + for s in range(0, self.step_num): + if self.model == "1": + mydata = create_rect_step(self, lastpoint, myvertex, myfaces, index, s) + if self.model == "2": + mydata = create_round_step(self, lastpoint, myvertex, myfaces, index, s) + index = mydata[0] + lastpoint = mydata[1] + + mesh = bpy.data.meshes.new(objname) + myobject = bpy.data.objects.new(objname, mesh) + + myobject.location = bpy.context.scene.cursor_location + bpy.context.scene.objects.link(myobject) + + mesh.from_pydata(myvertex, [], myfaces) + mesh.update(calc_edges=True) + + return myobject, lastpoint + + +# ------------------------------------------------------------------------------ +# Create rectangular step +# ------------------------------------------------------------------------------ +def create_rect_step(self, origin, myvertex, myfaces, index, step): + x = origin[0] + y = origin[1] + z = origin[2] + i = index + max_depth = y + self.depth + if self.back is True: + max_depth = self.depth * self.step_num + + # calculate width (no side gap) + if self.sizev is False: + width = self.max_width / 2 + else: + width = (self.max_width / 2) - (step * (((self.max_width - self.min_width) / 2) / self.step_num)) + + # Vertical Rectangle + myvertex.extend([(x, y, z), (x, y, z + self.height), (x + width, y, z + self.height), (x + width, y, z)]) + val = y + self.thickness + myvertex.extend([(x, val, z), (x, val, z + self.height), (x + width, val, z + self.height), (x + width, val, z)]) + + myfaces.extend([(i + 0, i + 1, i + 2, i + 3), (i + 4, i + 5, i + 6, i + 7), (i + 0, i + 3, i + 7, i + 4), + (i + 1, i + 2, i + 6, i + 5), (i + 0, i + 1, i + 5, i + 4), (i + 3, i + 2, i + 6, i + 7)]) + # Side plane + myvertex.extend([(x + width, max_depth, z + self.height), (x + width, max_depth, z)]) + myfaces.extend([(i + 7, i + 6, i + 8, i + 9)]) + i += 10 + # calculate width (side gap) + width = width + self.side_gap + + # Horizontal Rectangle + z = z + self.height + myvertex.extend([(x, y - self.front_gap, z), (x, max_depth, z), (x + width, max_depth, z), + (x + width, y - self.front_gap, z)]) + z = z + self.thickness + myvertex.extend([(x, y - self.front_gap, z), (x, max_depth, z), (x + width, max_depth, z), + (x + width, y - self.front_gap, z)]) + myfaces.extend([(i + 0, i + 1, i + 2, i + 3), (i + 4, i + 5, i + 6, i + 7), (i + 0, i + 3, i + 7, i + 4), + (i + 1, i + 2, i + 6, i + 5), (i + 3, i + 2, i + 6, i + 7)]) + i += 8 + # remap origin + y = y + (self.depth * self.shift) + + return i, (x, y, z) + + +# ------------------------------------------------------------------------------ +# Create rounded step +# ------------------------------------------------------------------------------ +def create_round_step(self, origin, myvertex, myfaces, index, step): + x = origin[0] + y = origin[1] + z = origin[2] + pos_x = None + i = index + li = [math.radians(270), math.radians(288), math.radians(306), math.radians(324), math.radians(342), + math.radians(0)] + + max_width = self.max_width + max_depth = y + self.depth + if self.back is True: + max_depth = self.depth * self.step_num + + # Resize for width + if self.sizev is True: + max_width = max_width - (step * ((self.max_width - self.min_width) / self.step_num)) + + half = max_width / 2 + # ------------------------------------ + # Vertical + # ------------------------------------ + # calculate width + width = half - (half * self.radio) + myradio = half - width + + myvertex.extend([(x, y, z), (x, y, z + self.height)]) + # Round + for e in li: + pos_x = (math.cos(e) * myradio) + x + width - myradio + pos_y = (math.sin(e) * myradio) + y + myradio + + myvertex.extend([(pos_x, pos_y, z), (pos_x, pos_y, z + self.height)]) + + # back point + myvertex.extend([(x + width, max_depth, z), (x + width, max_depth, z + self.height)]) + + myfaces.extend([(i, i + 1, i + 3, i + 2), (i + 2, i + 3, i + 5, i + 4), (i + 4, i + 5, i + 7, i + 6), + (i + 6, i + 7, i + 9, i + 8), + (i + 8, i + 9, i + 11, i + 10), (i + 10, i + 11, i + 13, i + 12), (i + 12, i + 13, i + 15, i + 14)]) + + i += 16 + # ------------------------------------ + # Horizontal + # ------------------------------------ + # calculate width gap + width = half + self.front_gap - (half * self.radio) + + z = z + self.height + # Vertical + myvertex.extend([(x, y - self.front_gap, z), (x, y - self.front_gap, z + self.thickness)]) + # Round + for e in li: + pos_x = (math.cos(e) * myradio) + x + width - myradio + pos_y = (math.sin(e) * myradio) + y + myradio - self.front_gap + + myvertex.extend([(pos_x, pos_y, z), (pos_x, pos_y, z + self.thickness)]) + + # back points + myvertex.extend([(pos_x, max_depth, z), (pos_x, max_depth, z + self.thickness), + (x, max_depth, z), (x, max_depth, z + self.thickness)]) + + myfaces.extend([(i, i + 1, i + 3, i + 2), (i + 2, i + 3, i + 5, i + 4), (i + 4, i + 5, i + 7, i + 6), + (i + 6, i + 7, i + 9, i + 8), + (i + 8, i + 9, i + 11, i + 10), (i + 10, i + 11, i + 13, i + 12), (i + 12, i + 13, i + 15, i + 14), + (i, i + 2, i + 4, i + 6, i + 8, i + 10, i + 12, i + 14, i + 16), + (i + 1, i + 3, i + 5, i + 7, i + 9, i + 11, i + 13, i + 15, i + 17), + (i + 14, i + 15, i + 17, i + 16)]) + + i += 18 + z = z + self.thickness + + # remap origin + y = y + (self.depth * self.shift) + + return i, (x, y, z) + + +# ------------------------------------------------------------------------------ +# Create bezier curve +# ------------------------------------------------------------------------------ +def create_bezier(objname, points, origin): + curvedata = bpy.data.curves.new(name=objname, type='CURVE') + curvedata.dimensions = '3D' + + myobject = bpy.data.objects.new(objname, curvedata) + myobject.location = origin + myobject.rotation_euler[2] = math.radians(90) + + bpy.context.scene.objects.link(myobject) + + polyline = curvedata.splines.new('BEZIER') + polyline.bezier_points.add(len(points) - 1) + + for idx, (knot, h1, h2) in enumerate(points): + point = polyline.bezier_points[idx] + point.co = knot + point.handle_left = h1 + point.handle_right = h2 + point.handle_left_type = 'FREE' + point.handle_right_type = 'FREE' + + return myobject |