mirror of
https://github.com/blender/blender-addons.git
synced 2025-08-16 15:35:05 +00:00

Fixes T67048: Adding archimesh stairs object to the scene flips normals of all other objects in scene Reviewers: antoniov, brecht Maniphest Tasks: T67048 Differential Revision: https://developer.blender.org/D5282
802 lines
28 KiB
Python
802 lines
28 KiB
Python
# ##### 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 columns
|
|
# Author: Antonio Vazquez (antonioya)
|
|
#
|
|
# ----------------------------------------------------------
|
|
# noinspection PyUnresolvedReferences
|
|
import bpy
|
|
from math import cos, sin, radians, atan, sqrt
|
|
from bpy.props import BoolProperty, IntProperty, FloatProperty, FloatVectorProperty
|
|
from .achm_tools import *
|
|
|
|
|
|
# ------------------------------------------------------------------
|
|
# Define UI class
|
|
# Columns
|
|
# ------------------------------------------------------------------
|
|
class ARCHIMESH_OT_Column(bpy.types.Operator):
|
|
bl_idname = "mesh.archimesh_column"
|
|
bl_label = "Column"
|
|
bl_description = "Columns Generator"
|
|
bl_category = 'View'
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
# Define properties
|
|
model: bpy.props.EnumProperty(
|
|
name="Model",
|
|
items=(
|
|
('1', "Circular", ""),
|
|
('2', "Rectangular", ""),
|
|
),
|
|
description="Type of column",
|
|
)
|
|
keep_size: BoolProperty(
|
|
name="Keep radius equal",
|
|
description="Keep all radius (top, mid and bottom) to the same size",
|
|
default=True,
|
|
)
|
|
|
|
rad_top: FloatProperty(
|
|
name='Top radius',
|
|
min=0.001, max=10, default=0.15, precision=3,
|
|
description='Radius of the column in the top',
|
|
)
|
|
rad_mid: FloatProperty(
|
|
name='Middle radius',
|
|
min=0.001, max=10, default=0.15, precision=3,
|
|
description='Radius of the column in the middle',
|
|
)
|
|
shift: FloatProperty(
|
|
name='',
|
|
min=-1, max=1, default=0, precision=3,
|
|
description='Middle displacement',
|
|
)
|
|
|
|
rad_bottom: FloatProperty(
|
|
name='Bottom radius',
|
|
min=0.001, max=10, default=0.15, precision=3,
|
|
description='Radius of the column in the bottom',
|
|
)
|
|
|
|
col_height: FloatProperty(
|
|
name='Total height',
|
|
min=0.001, max=10, default=2.4, precision=3,
|
|
description='Total height of column, including bases and tops',
|
|
)
|
|
col_sx: FloatProperty(
|
|
name='X size',
|
|
min=0.001, max=10, default=0.30, precision=3,
|
|
description='Column size for x axis',
|
|
)
|
|
col_sy: FloatProperty(
|
|
name='Y size',
|
|
min=0.001, max=10, default=0.30, precision=3,
|
|
description='Column size for y axis',
|
|
)
|
|
|
|
cir_base: BoolProperty(
|
|
name="Include circular base",
|
|
description="Include a base with circular form",
|
|
default=False,
|
|
)
|
|
cir_base_r: FloatProperty(
|
|
name='Radio',
|
|
min=0.001, max=10, default=0.08, precision=3,
|
|
description='Rise up radio of base',
|
|
)
|
|
cir_base_z: FloatProperty(
|
|
name='Height',
|
|
min=0.001, max=10, default=0.05, precision=3,
|
|
description='Size for z axis',
|
|
)
|
|
|
|
cir_top: BoolProperty(
|
|
name="Include circular top",
|
|
description="Include a top with circular form",
|
|
default=False,
|
|
)
|
|
cir_top_r: FloatProperty(
|
|
name='Radio',
|
|
min=0.001, max=10, default=0.08, precision=3,
|
|
description='Rise up radio of top',
|
|
)
|
|
cir_top_z: FloatProperty(
|
|
name='Height',
|
|
min=0.001, max=10, default=0.05, precision=3,
|
|
description='Size for z axis',
|
|
)
|
|
|
|
box_base: BoolProperty(
|
|
name="Include rectangular base",
|
|
description="Include a base with rectangular form",
|
|
default=True,
|
|
)
|
|
box_base_x: FloatProperty(
|
|
name='X size',
|
|
min=0.001, max=10, default=0.40, precision=3,
|
|
description='Size for x axis',
|
|
)
|
|
box_base_y: FloatProperty(
|
|
name='Y size',
|
|
min=0.001, max=10, default=0.40, precision=3,
|
|
description='Size for y axis',
|
|
)
|
|
box_base_z: FloatProperty(
|
|
name='Height',
|
|
min=0.001, max=10, default=0.05, precision=3,
|
|
description='Size for z axis',
|
|
)
|
|
|
|
box_top: BoolProperty(
|
|
name="Include rectangular top",
|
|
description="Include a top with rectangular form",
|
|
default=True,
|
|
)
|
|
box_top_x: FloatProperty(
|
|
name='X size',
|
|
min=0.001, max=10, default=0.40, precision=3,
|
|
description='Size for x axis',
|
|
)
|
|
box_top_y: FloatProperty(
|
|
name='Y size',
|
|
min=0.001, max=10, default=0.40, precision=3,
|
|
description='Size for y axis',
|
|
)
|
|
box_top_z: FloatProperty(
|
|
name='Height',
|
|
min=0.001, max=10, default=0.05, precision=3,
|
|
description='Size for z axis',
|
|
)
|
|
|
|
arc_top: BoolProperty(
|
|
name="Create top arch",
|
|
description="Include an arch in the top of the column",
|
|
default=False,
|
|
)
|
|
arc_radio: FloatProperty(
|
|
name='Arc Radio',
|
|
min=0.001, max=10, default=1, precision=1,
|
|
description='Radio of the arch',
|
|
)
|
|
arc_width: FloatProperty(
|
|
name='Thickness',
|
|
min=0.01, max=10, default=0.15, precision=2,
|
|
description='Thickness of the arch wall',
|
|
)
|
|
arc_gap: FloatProperty(
|
|
name='Arc gap',
|
|
min=0.01, max=10, default=0.25, precision=2,
|
|
description='Size of the gap in the arch sides',
|
|
)
|
|
|
|
crt_mat: BoolProperty(
|
|
name="Create default Cycles materials",
|
|
description="Create default materials for Cycles render",
|
|
default=True,
|
|
)
|
|
crt_array: BoolProperty(
|
|
name="Create array of elements",
|
|
description="Create a modifier array for all elemnst",
|
|
default=False,
|
|
)
|
|
array_num_x: IntProperty(
|
|
name='Count X',
|
|
min=0, max=100, default=3,
|
|
description='Number of elements in array',
|
|
)
|
|
array_space_x: FloatProperty(
|
|
name='Distance X',
|
|
min=0.000, max=10, default=1, precision=3,
|
|
description='Distance between elements (only arc disabled)',
|
|
)
|
|
array_num_y: IntProperty(
|
|
name='Count Y',
|
|
min=0, max=100, default=0,
|
|
description='Number of elements in array',
|
|
)
|
|
array_space_y: FloatProperty(
|
|
name='Distance Y',
|
|
min=0.000, max=10, default=1, precision=3,
|
|
description='Distance between elements (only arc disabled)',
|
|
)
|
|
array_space_z: FloatProperty(
|
|
name='Distance Z',
|
|
min=-10, max=10, default=0, precision=3,
|
|
description='Combined X/Z distance between elements (only arc disabled)',
|
|
)
|
|
ramp: BoolProperty(
|
|
name="Deform",
|
|
description="Deform top base with Z displacement", default=True,
|
|
)
|
|
array_space_factor: FloatProperty(
|
|
name='Move Y center',
|
|
min=0.00, max=1, default=0.0, precision=3,
|
|
description='Move the center of the arch in Y axis. (0 centered)',
|
|
)
|
|
|
|
# -----------------------------------------------------
|
|
# 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(text="Warning: Imperial units not supported", icon='COLOR_RED')
|
|
box = layout.box()
|
|
box.prop(self, 'model')
|
|
# Circular
|
|
if self.model == "1":
|
|
box.prop(self, 'keep_size')
|
|
box.prop(self, 'rad_top')
|
|
if self.keep_size is False:
|
|
row = box.row()
|
|
row.prop(self, 'rad_mid')
|
|
row.prop(self, 'shift')
|
|
box.prop(self, 'rad_bottom')
|
|
|
|
# Rectangular
|
|
if self.model == "2":
|
|
box.prop(self, 'col_sx')
|
|
box.prop(self, 'col_sy')
|
|
|
|
box.prop(self, 'col_height')
|
|
|
|
box = layout.box()
|
|
box.prop(self, 'box_base')
|
|
if self.box_base is True:
|
|
row = box.row()
|
|
row.prop(self, 'box_base_x')
|
|
row.prop(self, 'box_base_y')
|
|
row.prop(self, 'box_base_z')
|
|
|
|
box = layout.box()
|
|
box.prop(self, 'box_top')
|
|
if self.box_top is True:
|
|
row = box.row()
|
|
row.prop(self, 'box_top_x')
|
|
row.prop(self, 'box_top_y')
|
|
row.prop(self, 'box_top_z')
|
|
|
|
box = layout.box()
|
|
box.prop(self, 'cir_base')
|
|
if self.cir_base is True:
|
|
row = box.row()
|
|
row.prop(self, 'cir_base_r')
|
|
row.prop(self, 'cir_base_z')
|
|
|
|
box = layout.box()
|
|
box.prop(self, 'cir_top')
|
|
if self.cir_top is True:
|
|
row = box.row()
|
|
row.prop(self, 'cir_top_r')
|
|
row.prop(self, 'cir_top_z')
|
|
|
|
box = layout.box()
|
|
box.prop(self, 'arc_top')
|
|
if self.arc_top is True:
|
|
row = box.row()
|
|
row.prop(self, 'arc_radio')
|
|
row.prop(self, 'arc_width')
|
|
row = box.row()
|
|
row.prop(self, 'arc_gap')
|
|
row.prop(self, 'array_space_factor')
|
|
|
|
box = layout.box()
|
|
box.prop(self, 'crt_array')
|
|
if self.crt_array is True:
|
|
row = box.row()
|
|
row.prop(self, 'array_num_x')
|
|
row.prop(self, 'array_num_y')
|
|
if self.arc_top is True:
|
|
box.label(text="Use arch radio and thickness to set distances")
|
|
|
|
if self.arc_top is False:
|
|
row = box.row()
|
|
row.prop(self, 'array_space_x')
|
|
row.prop(self, 'array_space_y')
|
|
row = box.row()
|
|
row.prop(self, 'array_space_z')
|
|
row.prop(self, 'ramp')
|
|
|
|
box = layout.box()
|
|
if not context.scene.render.engine in {'CYCLES', 'BLENDER_EEVEE'}:
|
|
box.enabled = False
|
|
box.prop(self, 'crt_mat')
|
|
else:
|
|
row = layout.row()
|
|
row.label(text="Warning: Operator does not work in local view mode", icon='ERROR')
|
|
|
|
# -----------------------------------------------------
|
|
# Execute
|
|
# -----------------------------------------------------
|
|
# noinspection PyUnusedLocal
|
|
def execute(self, context):
|
|
if bpy.context.mode == "OBJECT":
|
|
create_column_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_column_mesh(self):
|
|
myarc = None
|
|
cir_top = None
|
|
cir_bottom = None
|
|
box_top = None
|
|
box_bottom = None
|
|
mycolumn = None
|
|
# deactivate others
|
|
for o in bpy.data.objects:
|
|
if o.select_get() is True:
|
|
o.select_set(False)
|
|
|
|
bpy.ops.object.select_all(action='DESELECT')
|
|
|
|
radio_top = self.rad_top
|
|
if self.keep_size is True:
|
|
radio_mid = radio_top
|
|
radio_bottom = radio_top
|
|
else:
|
|
radio_mid = self.rad_mid
|
|
radio_bottom = self.rad_bottom
|
|
|
|
# Calculate height
|
|
height = self.col_height
|
|
if self.box_base:
|
|
height = height - self.box_base_z
|
|
if self.box_top:
|
|
height = height - self.box_top_z
|
|
|
|
# ------------------------
|
|
# Create circular column
|
|
# ------------------------
|
|
if self.model == "1":
|
|
bpy.ops.object.select_all(action='DESELECT')
|
|
mycolumn = create_circular_column(self, "Column", radio_top, radio_mid, radio_bottom, height)
|
|
mycolumn.select_set(True)
|
|
bpy.context.view_layer.objects.active = mycolumn
|
|
# Subsurf
|
|
set_smooth(mycolumn)
|
|
set_modifier_subsurf(mycolumn)
|
|
# ------------------------
|
|
# Create rectangular column
|
|
# ------------------------
|
|
if self.model == "2":
|
|
mycolumn = create_rectangular_base(self, "Column", self.col_sx, self.col_sy, height)
|
|
bpy.ops.object.select_all(action='DESELECT')
|
|
mycolumn.select_set(True)
|
|
bpy.context.view_layer.objects.active = mycolumn
|
|
set_normals(mycolumn)
|
|
# ------------------------
|
|
# Circular base
|
|
# ------------------------
|
|
if self.cir_base is True:
|
|
cir_bottom = create_torus("Column_cir_bottom", radio_bottom, self.cir_base_r, self.cir_base_z)
|
|
bpy.ops.object.select_all(action='DESELECT')
|
|
cir_bottom.select_set(True)
|
|
bpy.context.view_layer.objects.active = cir_bottom
|
|
set_modifier_subsurf(cir_bottom)
|
|
set_smooth(cir_bottom)
|
|
cir_bottom.location.x = 0.0
|
|
cir_bottom.location.y = 0.0
|
|
cir_bottom.location.z = self.cir_base_z / 2
|
|
cir_bottom.parent = mycolumn
|
|
|
|
# ------------------------
|
|
# Rectangular base
|
|
# ------------------------
|
|
if self.box_base is True:
|
|
box_bottom = create_rectangular_base(self, "Column_box_bottom", self.box_base_x, self.box_base_y,
|
|
self.box_base_z)
|
|
bpy.ops.object.select_all(action='DESELECT')
|
|
box_bottom.select_set(True)
|
|
bpy.context.view_layer.objects.active = box_bottom
|
|
box_bottom.parent = mycolumn
|
|
set_normals(box_bottom)
|
|
box_bottom.location.x = 0.0
|
|
box_bottom.location.y = 0.0
|
|
box_bottom.location.z = - self.box_base_z
|
|
# move column
|
|
mycolumn.location.z += self.box_base_z
|
|
|
|
# ------------------------
|
|
# Circular top
|
|
# ------------------------
|
|
if self.cir_top is True:
|
|
cir_top = create_torus("Column_cir_top", radio_top, self.cir_top_r, self.cir_top_z)
|
|
bpy.ops.object.select_all(action='DESELECT')
|
|
cir_top.select_set(True)
|
|
bpy.context.view_layer.objects.active = cir_top
|
|
set_modifier_subsurf(cir_top)
|
|
set_smooth(cir_top)
|
|
cir_top.parent = mycolumn
|
|
cir_top.location.x = 0.0
|
|
cir_top.location.y = 0.0
|
|
cir_top.location.z = height - self.cir_top_z / 2
|
|
|
|
# ------------------------
|
|
# Rectangular top
|
|
# ------------------------
|
|
if self.box_top is True:
|
|
box_top = create_rectangular_base(self, "Column_box_top", self.box_top_x, self.box_top_y,
|
|
self.box_top_z, self.ramp)
|
|
bpy.ops.object.select_all(action='DESELECT')
|
|
box_top.select_set(True)
|
|
bpy.context.view_layer.objects.active = box_top
|
|
set_normals(box_top)
|
|
box_top.parent = mycolumn
|
|
box_top.location.x = 0.0
|
|
box_top.location.y = 0.0
|
|
box_top.location.z = height
|
|
|
|
# ------------------------
|
|
# Create arc
|
|
# ------------------------
|
|
if self.arc_top:
|
|
myarc = create_arc("Column_arch", self.arc_radio, self.arc_gap, self.arc_width,
|
|
self.array_space_factor)
|
|
myarc.parent = mycolumn
|
|
bpy.ops.object.select_all(action='DESELECT')
|
|
myarc.select_set(True)
|
|
bpy.context.view_layer.objects.active = myarc
|
|
set_normals(myarc)
|
|
set_modifier_mirror(myarc, "X")
|
|
myarc.location.x = self.arc_radio + self.arc_gap
|
|
myarc.location.y = 0.0
|
|
if self.box_top is True:
|
|
myarc.location.z = height + self.box_top_z
|
|
else:
|
|
myarc.location.z = height
|
|
# ------------------------
|
|
# Create Array X
|
|
# ------------------------
|
|
if self.array_num_x > 0:
|
|
if self.arc_top:
|
|
distance = ((self.arc_radio + self.arc_gap) * 2)
|
|
zmove = 0
|
|
else:
|
|
distance = self.array_space_x
|
|
zmove = self.array_space_z
|
|
|
|
if self.crt_array:
|
|
set_modifier_array(mycolumn, "X", 0, self.array_num_x, True, distance, zmove)
|
|
|
|
if self.box_base is True:
|
|
set_modifier_array(box_bottom, "X", 0, self.array_num_x, True, distance, zmove)
|
|
if self.box_top is True:
|
|
set_modifier_array(box_top, "X", 0, self.array_num_x, True, distance, zmove)
|
|
|
|
if self.cir_base is True:
|
|
set_modifier_array(cir_bottom, "X", 0, self.array_num_x, True, distance, zmove)
|
|
if self.cir_top is True:
|
|
set_modifier_array(cir_top, "X", 0, self.array_num_x, True, distance, zmove)
|
|
|
|
if self.arc_top:
|
|
if self.array_num_x > 1:
|
|
set_modifier_array(myarc, "X", 1, self.array_num_x - 1) # one arc minus
|
|
# ------------------------
|
|
# Create Array Y
|
|
# ------------------------
|
|
if self.array_num_y > 0:
|
|
if self.arc_top:
|
|
distance = self.arc_width
|
|
else:
|
|
distance = self.array_space_y
|
|
|
|
if self.crt_array:
|
|
set_modifier_array(mycolumn, "Y", 0, self.array_num_y, True, distance)
|
|
|
|
if self.box_base is True:
|
|
set_modifier_array(box_bottom, "Y", 0, self.array_num_y, True, distance)
|
|
if self.box_top is True:
|
|
set_modifier_array(box_top, "Y", 0, self.array_num_y, True, distance)
|
|
|
|
if self.cir_base is True:
|
|
set_modifier_array(cir_bottom, "Y", 0, self.array_num_y, True, distance)
|
|
if self.cir_top is True:
|
|
set_modifier_array(cir_top, "Y", 0, self.array_num_y, True, distance)
|
|
|
|
if self.arc_top:
|
|
if self.array_num_y > 1:
|
|
set_modifier_array(myarc, "Y", 1, self.array_num_y - 1) # one less
|
|
|
|
# ------------------------
|
|
# Create materials
|
|
# ------------------------
|
|
if self.crt_mat and bpy.context.scene.render.engine in {'CYCLES', 'BLENDER_EEVEE'}:
|
|
# Column material
|
|
mat = create_diffuse_material("Column_material", False, 0.748, 0.734, 0.392, 0.573, 0.581, 0.318)
|
|
set_material(mycolumn, mat)
|
|
|
|
if self.box_base is True or self.box_top is True:
|
|
mat = create_diffuse_material("Column_rect", False, 0.56, 0.56, 0.56, 0.56, 0.56, 0.56)
|
|
if self.box_base is True:
|
|
set_material(box_bottom, mat)
|
|
if self.box_top is True:
|
|
set_material(box_top, mat)
|
|
|
|
if self.cir_base is True or self.cir_top is True:
|
|
mat = create_diffuse_material("Column_cir", False, 0.65, 0.65, 0.65, 0.65, 0.65, 0.65)
|
|
if self.cir_base is True:
|
|
set_material(cir_bottom, mat)
|
|
if self.cir_top is True:
|
|
set_material(cir_top, mat)
|
|
|
|
if self.arc_top:
|
|
mat = create_diffuse_material("Column_arch", False, 0.8, 0.8, 0.8)
|
|
set_material(myarc, mat)
|
|
|
|
bpy.ops.object.select_all(action='DESELECT')
|
|
mycolumn.select_set(True)
|
|
bpy.context.view_layer.objects.active = mycolumn
|
|
|
|
return
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Create Column
|
|
# ------------------------------------------------------------------------------
|
|
def create_circular_column(self, objname, radio_top, radio_mid, radio_bottom, height):
|
|
myvertex = []
|
|
myfaces = []
|
|
pies = [0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330] # circle
|
|
|
|
# Add bottom circle
|
|
for pie in pies:
|
|
x = cos(radians(pie)) * radio_bottom
|
|
y = sin(radians(pie)) * radio_bottom
|
|
mypoint = [(x, y, 0.0)]
|
|
myvertex.extend(mypoint)
|
|
# Add middle circle
|
|
for pie in pies:
|
|
x = cos(radians(pie)) * radio_mid
|
|
y = sin(radians(pie)) * radio_mid
|
|
mypoint = [(x, y, (height / 2) + ((height / 2) * self.shift))]
|
|
myvertex.extend(mypoint)
|
|
# Add top circle
|
|
for pie in pies:
|
|
x = cos(radians(pie)) * radio_top
|
|
y = sin(radians(pie)) * radio_top
|
|
mypoint = [(x, y, height)]
|
|
myvertex.extend(mypoint)
|
|
# -------------------------------------
|
|
# Faces
|
|
# -------------------------------------
|
|
t = 1
|
|
for n in range(0, len(pies) * 2):
|
|
t += 1
|
|
if t > len(pies):
|
|
t = 1
|
|
myface = [(n, n - len(pies) + 1, n + 1, n + len(pies))]
|
|
myfaces.extend(myface)
|
|
else:
|
|
myface = [(n, n + 1, n + len(pies) + 1, n + len(pies))]
|
|
myfaces.extend(myface)
|
|
|
|
mesh = bpy.data.meshes.new(objname)
|
|
myobject = bpy.data.objects.new(objname, mesh)
|
|
|
|
myobject.location = bpy.context.scene.cursor.location
|
|
bpy.context.collection.objects.link(myobject)
|
|
|
|
mesh.from_pydata(myvertex, [], myfaces)
|
|
mesh.update(calc_edges=True)
|
|
|
|
return myobject
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Create Torus
|
|
# ------------------------------------------------------------------------------
|
|
def create_torus(objname, radio_inside, radio_outside, height):
|
|
myvertex = []
|
|
myfaces = []
|
|
pies = [0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330] # circle
|
|
segments = [80, 60, 30, 0, 330, 300, 280] # section
|
|
|
|
radio_mid = radio_outside + radio_inside - (height / 2)
|
|
# Add internal circles Top
|
|
for pie in pies:
|
|
x = cos(radians(pie)) * radio_inside
|
|
y = sin(radians(pie)) * radio_inside
|
|
mypoint = [(x, y, height / 2)]
|
|
myvertex.extend(mypoint)
|
|
# Add external circles Top
|
|
for pie in pies:
|
|
x = cos(radians(pie)) * radio_mid
|
|
y = sin(radians(pie)) * radio_mid
|
|
mypoint = [(x, y, height / 2)]
|
|
myvertex.extend(mypoint)
|
|
# Add Intermediate lines
|
|
for segment in segments:
|
|
for pie in pies:
|
|
radio_externo = radio_mid + (height * cos(radians(segment)))
|
|
x = cos(radians(pie)) * radio_externo
|
|
y = sin(radians(pie)) * radio_externo
|
|
z = sin(radians(segment)) * (height / 2)
|
|
|
|
mypoint = [(x, y, z)]
|
|
myvertex.extend(mypoint)
|
|
|
|
# Add internal circles Bottom
|
|
for pie in pies:
|
|
x = cos(radians(pie)) * radio_inside
|
|
y = sin(radians(pie)) * radio_inside
|
|
mypoint = [(x, y, height / 2 * -1)]
|
|
myvertex.extend(mypoint)
|
|
# Add external circles bottom
|
|
for pie in pies:
|
|
x = cos(radians(pie)) * radio_mid
|
|
y = sin(radians(pie)) * radio_mid
|
|
mypoint = [(x, y, height / 2 * -1)]
|
|
myvertex.extend(mypoint)
|
|
|
|
# -------------------------------------
|
|
# Faces
|
|
# -------------------------------------
|
|
t = 1
|
|
for n in range(0, len(pies) * len(segments) + (len(pies) * 2)):
|
|
t += 1
|
|
if t > len(pies):
|
|
t = 1
|
|
myface = [(n, n - len(pies) + 1, n + 1, n + len(pies))]
|
|
myfaces.extend(myface)
|
|
else:
|
|
myface = [(n, n + 1, n + len(pies) + 1, n + len(pies))]
|
|
myfaces.extend(myface)
|
|
|
|
mesh = bpy.data.meshes.new(objname)
|
|
myobject = bpy.data.objects.new(objname, mesh)
|
|
|
|
myobject.location = bpy.context.scene.cursor.location
|
|
bpy.context.collection.objects.link(myobject)
|
|
|
|
mesh.from_pydata(myvertex, [], myfaces)
|
|
mesh.update(calc_edges=True)
|
|
|
|
return myobject
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Create rectangular base
|
|
# ------------------------------------------------------------------------------
|
|
def create_rectangular_base(self, objname, x, y, z, ramp=False):
|
|
elements = self.array_num_x - 1
|
|
height = self.array_space_z * elements
|
|
width = self.array_space_x * elements
|
|
if width > 0:
|
|
angle = atan(height / width)
|
|
else:
|
|
angle = 0
|
|
|
|
radio = sqrt((x * x) + (self.array_space_z * self.array_space_z))
|
|
disp = radio * sin(angle)
|
|
|
|
if ramp is False or self.arc_top:
|
|
addz1 = 0
|
|
addz2 = 0
|
|
else:
|
|
if self.array_space_z >= 0:
|
|
addz1 = 0
|
|
addz2 = disp
|
|
else:
|
|
addz1 = disp * -1
|
|
addz2 = 0
|
|
|
|
myvertex = [(-x / 2, -y / 2, 0.0),
|
|
(-x / 2, y / 2, 0.0),
|
|
(x / 2, y / 2, 0.0),
|
|
(x / 2, -y / 2, 0.0),
|
|
(-x / 2, -y / 2, z + addz1),
|
|
(-x / 2, y / 2, z + addz1),
|
|
(x / 2, y / 2, z + addz2),
|
|
(x / 2, -y / 2, z + addz2)]
|
|
|
|
myfaces = [(0, 1, 2, 3), (0, 1, 5, 4), (1, 2, 6, 5), (2, 6, 7, 3), (5, 6, 7, 4), (0, 4, 7, 3)]
|
|
|
|
mesh = bpy.data.meshes.new(objname)
|
|
myobject = bpy.data.objects.new(objname, mesh)
|
|
|
|
myobject.location = bpy.context.scene.cursor.location
|
|
bpy.context.collection.objects.link(myobject)
|
|
|
|
mesh.from_pydata(myvertex, [], myfaces)
|
|
mesh.update(calc_edges=True)
|
|
|
|
return myobject
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Create arc
|
|
# ------------------------------------------------------------------------------
|
|
def create_arc(objname, radio, gap, thickness, center):
|
|
myvertex = []
|
|
|
|
half = (thickness / 2)
|
|
move = half * center
|
|
|
|
listdata = [half + move, -half + move]
|
|
for pos_y in listdata:
|
|
# --------------------------------
|
|
# First vertices
|
|
# --------------------------------
|
|
myvertex.extend([(-radio - gap, pos_y, radio + radio / 10)])
|
|
# Flat cuts
|
|
angle = 13 * (180 / 16)
|
|
for i in range(1, 4):
|
|
z = sin(radians(angle)) * radio
|
|
mypoint = [(-radio - gap, pos_y, z)]
|
|
myvertex.extend(mypoint)
|
|
angle += 180 / 16
|
|
|
|
myvertex.extend([(-radio - gap, pos_y, 0.0)])
|
|
# --------------------------------
|
|
# Arc points
|
|
# --------------------------------
|
|
angle = 180
|
|
for i in range(0, 9):
|
|
x = cos(radians(angle)) * radio
|
|
z = sin(radians(angle)) * radio
|
|
mypoint = [(x, pos_y, z)]
|
|
myvertex.extend(mypoint)
|
|
|
|
angle -= 180 / 16
|
|
# --------------------------------
|
|
# vertical cut points
|
|
# --------------------------------
|
|
angle = 8 * (180 / 16)
|
|
for i in range(1, 5):
|
|
x = cos(radians(angle)) * radio
|
|
mypoint = [(x, pos_y, radio + radio / 10)]
|
|
myvertex.extend(mypoint)
|
|
|
|
angle += 180 / 16
|
|
|
|
myfaces = [(23, 24, 21, 22), (24, 25, 20, 21), (25, 26, 19, 20), (27, 18, 19, 26), (18, 27, 28, 35),
|
|
(28, 29, 34, 35), (29, 30, 33, 34), (30, 31, 32, 33), (12, 13, 31, 30), (29, 11, 12, 30),
|
|
(11, 29, 28, 10), (10, 28, 27, 9), (9, 27, 26, 8), (25, 7, 8, 26), (24, 6, 7, 25),
|
|
(23, 5, 6, 24), (22, 4, 5, 23), (5, 4, 3, 6), (6, 3, 2, 7), (7, 2, 1, 8),
|
|
(8, 1, 0, 9), (9, 0, 17, 10), (10, 17, 16, 11), (11, 16, 15, 12), (14, 13, 12, 15),
|
|
(21, 3, 4, 22), (20, 2, 3, 21), (19, 1, 2, 20), (1, 19, 18, 0), (0, 18, 35, 17),
|
|
(17, 35, 34, 16), (33, 15, 16, 34), (32, 14, 15, 33)]
|
|
|
|
mesh = bpy.data.meshes.new(objname)
|
|
myobject = bpy.data.objects.new(objname, mesh)
|
|
|
|
myobject.location = bpy.context.scene.cursor.location
|
|
bpy.context.collection.objects.link(myobject)
|
|
|
|
mesh.from_pydata(myvertex, [], myfaces)
|
|
mesh.update(calc_edges=True)
|
|
|
|
return myobject
|