Page MenuHome

ArToKi_House_Tools.py

ArToKi_House_Tools.py

# ArToKi-EPB.py (c) 2011 Thierry Maes (tmaes)
#
# ***** 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 LICENCE BLOCK *****
bl_info = {
"name": "ArToKi-House-Tools",
"author": "Thierry Maes (tmaes)",
"version": (0,0,6),
"blender": (2, 64, 0),
"api": 51232,
"location": "Properties > Object > ArToKi House",
"description": "Create houses based on simple 2 point lines.",
"warning": "",
"wiki_url": "",
"tracker_url": "",
"category": "Object"}
"""
This addon is made for mass planification.
It scatters and edit simple house primitives.
"""
import bpy
import math
from mathutils import Vector, Matrix
from bpy.props import *
class OBJECT_PT_ArToKi_House(bpy.types.Panel):
bl_label = "ArToKi - House - Tools"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "object"
# Variables
bpy.types.Scene.atk_width = bpy.props.FloatProperty(
name="House width",
description="House width",
min=0.0, max=500.0,
default=5.0,
)
bpy.types.Scene.atk_length = bpy.props.FloatProperty(
name="House length",
description="House length",
min=0.0, max=500.0,
default=10.0,
)
bpy.types.Scene.atk_foundation_height = bpy.props.FloatProperty(
name="Foundation thickness",
description="Foundation Height",
min=0.0, max=100.0,
default=0.3,
)
bpy.types.Scene.atk_ground_floor_height = bpy.props.FloatProperty(
name="Ground floor height",
description="Ground Floor Height",
min=0.0, max=10.0,
default=2.5,
)
bpy.types.Scene.atk_floors_thickness = bpy.props.FloatProperty(
name="Floors thickness",
description="Floors thickness usually 0.3",
min=0.0, max=10.0,
default=0.3,
)
bpy.types.Scene.atk_first_floor_height = bpy.props.FloatProperty(
name="First floor height",
description="House Height",
min=0.0, max=10.0,
default=0.0,
)
bpy.types.Scene.atk_generic_floor_height = bpy.props.FloatProperty(
name="Generic floor height",
description="Second floor height",
min=0.0, max=10.0,
default=2.5,
)
bpy.types.Scene.atk_floors_number = bpy.props.IntProperty(
name="Number of floors",
description="Number of floors",
min=0, max=300,
default=1,
)
bpy.types.Scene.atk_last_floor_height = bpy.props.FloatProperty(
name="Last floor height",
description="Last floor height",
min=0.0, max=10.0,
default=0.0,
)
bpy.types.Scene.atk_cornice_thickness = bpy.props.FloatProperty(
name="Cornice thickness",
description="Last chance to tune the cornice",
min=0.0, max=10.0,
default=0.0,
)
bpy.types.Scene.atk_ridge_height = bpy.props.FloatProperty(
name="Ridge height",
description="Ridge height",
min=0.0, max=100.0,
default=3.0,
)
bpy.types.Scene.atk_walls_thickness = bpy.props.FloatProperty(
name="Thickness of general exterior walls.",
description="Thickness of general exterior walls.",
min=0.0, max=1.0,
default=0.35,
)
bpy.types.Scene.atk_roof_walls_height = bpy.props.FloatProperty(
name="Height of general exterior walls.",
description="Height of general exterior walls.",
min=0.0, max=1.0,
default=0.5,
)
bpy.types.Scene.atk_road_parallelism = bpy.props.BoolProperty(
name="Parallel to the road.",
description="Is the house parallel to the road.",
default=True,
)
bpy.types.Scene.atk_create_interior = bpy.props.BoolProperty(
name="Create interiors.",
description="Create default ceillings.",
default=False,
)
# Interface Buttons etc...
def draw(self, context):
layout = self.layout
obj = bpy.context.object
scene = bpy.context.scene
row = layout.row()
row.prop(scene,'atk_width',text="House width")
row.prop(scene,'atk_length',text="House length")
row = layout.row()
row.prop(scene,'atk_foundation_height',text="Foundation Height")
row.prop(scene,'atk_ground_floor_height',text="Ground floor height")
row = layout.row()
row.prop(scene,'atk_floors_thickness',text="Floors thickness")
row.prop(scene,'atk_first_floor_height',text="First floor height")
row = layout.row()
row.prop(scene,'atk_generic_floor_height',text="Generic floor height")
row = layout.row()
row.prop(scene,'atk_floors_number',text="Number of floors")
row = layout.row()
row.prop(scene,'atk_last_floor_height',text="Last floor height")
row.prop(scene,'atk_cornice_thickness',text="Cornice thickness")
row = layout.row()
row.prop(scene,'atk_ridge_height',text="Ridge height")
row.prop(scene,'atk_walls_thickness',text="Thickness of general exterior walls")
row = layout.row()
row.prop(scene,'atk_road_parallelism',text="Parallel to the road. (Doesn't impact geometry)")
row = layout.row()
row.prop(scene,'atk_create_interior',text="Create default ceillings")
row = layout.row()
row.operator("object.house_create_houses",text="Create houses from 2 point lines (City Maker)")
row = layout.row()
row.operator("object.house_modify_house_with_settings",text="Modify selected house using parameters")
row = layout.row()
row.operator("object.house_modify_house",text="Modify selected house")
class OBJECT_OT_House_create_houses(bpy.types.Operator):
bl_label = "Create Houses"
bl_idname = "object.house_create_houses"
bl_description = "Transforms 2 point lines to houses."
@classmethod
def poll(cls, context):
return context.active_object is not None
def execute(self, context):
# main(context)
print(64*'=')
### 1- copy the base object in a new temporary one and select it (apply custom properties we will need later, I think)
#bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
scene = bpy.context.scene
obj = bpy.context.object
ver = obj.data.vertices
edg = obj.data.edges
num = len(edg)
scene_properties= bpy.context.scene.keys()
if scene_properties.count('house_id')==0:
scene['house_id']=0 # il y a un truc à mettre en rapport avec atk_id ici...
houses_temp = []
bpy.ops.object.mode_set()
base_object = obj.name
# delete old temporary mesh
scene_objects = scene.objects.keys()
bpy.ops.object.select_all(action='DESELECT')
if scene_objects.count('House_Base') != 0:
scene.objects['House_Base'].select = True
bpy.ops.object.delete(use_global=False)
# cancel sub-object selections in base object
bpy.ops.object.select_all(action='DESELECT')
scene.objects[base_object].select = True
bpy.ops.object.duplicate_move()
bpy.context.active_object.name = 'House_Base'
bpy.ops.object.select_all(action='DESELECT')
scene.objects.active = scene.objects[base_object]
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.select_all(action='DESELECT')
# catch the temporary object
scene.objects['House_Base'].select = True
scene.objects.active = scene.objects['House_Base']
### variables update
obj = bpy.context.active_object
ver = obj.data.vertices
edg = obj.data.edges
num = len(edg)
#### edges selection mode
# print(obj,edg)
bpy.context.tool_settings.mesh_select_mode = [False, True, False]
bpy.ops.object.mode_set()
for e in edg:
e.use_seam = e.select
if e.use_seam:
e.select=False
# print(norm_pos)
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT')
for i in range(num):
obj = bpy.context.active_object
edg = obj.data.edges
ver = obj.data.vertices
for e in edg:
if e.use_seam:
e.select=True
e.use_seam = False
bpy.ops.object.mode_set(mode='EDIT')
print('youhou')
scene['house_id']=scene['house_id']+1
bpy.ops.mesh.separate()
bpy.ops.object.mode_set(mode='OBJECT')
house_new_name='House_Base_'+'%04d'%(scene['house_id'])
bpy.context.scene.objects['House_Base.001'].name = house_new_name
houses_temp.append(house_new_name)
break
#
print(houses_temp)
#
#
bpy.ops.object.mode_set()
bpy.ops.object.select_all(action='DESELECT')
for i in houses_temp:
bpy.ops.object.select_all(action='DESELECT')
bpy.data.objects[i].select=True
scene.objects.active = scene.objects[i]
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN')
bpy.ops.transform.resize(value=(1, 1, 0), constraint_axis=(False, False, True))
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
obj=bpy.data.objects[i]
print(obj)
house_location=(obj.data.vertices[1].co[0],obj.data.vertices[1].co[1],obj.data.vertices[1].co[2])
print(house_location)
house_length=math.hypot(obj.data.vertices[0].co[0]-obj.data.vertices[1].co[0],obj.data.vertices[0].co[1]-obj.data.vertices[1].co[1])
vector=obj.data.vertices[0].co-obj.data.vertices[1].co
print(vector)
house_angle=math.atan2(vector[1],vector[0])
print(house_angle)
bpy.ops.object.delete(use_global=False)
bpy.ops.mesh.primitive_house_add(
True,
atk_width=scene.atk_width, atk_length=house_length,
atk_foundation_height=scene.atk_foundation_height,
atk_ground_floor_height=scene.atk_ground_floor_height,
atk_floors_thickness=scene.atk_floors_thickness,
atk_first_floor_height=scene.atk_first_floor_height,
atk_generic_floor_height=scene.atk_generic_floor_height,
atk_floors_number=scene.atk_floors_number,
atk_last_floor_height=scene.atk_last_floor_height,
atk_cornice_thickness=scene.atk_cornice_thickness,
atk_ridge_height=scene.atk_ridge_height,
atk_walls_thickness=scene.atk_walls_thickness,
atk_roof_walls_height=scene.atk_roof_walls_height,
atk_road_parallelism=scene.atk_road_parallelism,
atk_create_interior=scene.atk_create_interior,
location=house_location,rotation=(0,0,house_angle)
)
bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
# bpy.ops.render.render()
# bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
print(i)
bpy.ops.object.select_all(action='DESELECT')
scene.objects['House_Base'].select = True
bpy.ops.object.delete(use_global=False)
return {'FINISHED'}
class OBJECT_OT_House_modify_house(bpy.types.Operator):
bl_label = "Modify House"
bl_idname = "object.house_modify_house"
bl_description = "Transforms 2 point lines to houses."
@classmethod
def poll(cls, context):
return context.active_object is not None
def execute(self, context):
# main(context)
print(64*'=')
### 1- copy the base object in a new temporary one and select it (apply custom properties we will need later, I think)
scene = bpy.context.scene
obj = bpy.context.object
ver = obj.data.vertices
edg = obj.data.edges
num = len(edg)
house_params=[]
house_params.append(obj['atk_Id'])#0
house_params.append(obj['atk_Width'])#1
house_params.append(obj['atk_Length'])#2
house_params.append(obj['atk_Foundation_Height'])#3
house_params.append(obj['atk_Ground_Floor_Height'])#4
house_params.append(obj['atk_Floors_Thickness'])#5
house_params.append(obj['atk_First_Floor_Height'])#6
house_params.append(obj['atk_Generic_Floor_Height'])#7
house_params.append(obj['atk_Floors_Number'])#8
house_params.append(obj['atk_Last_Floor_Height'])#9
house_params.append(obj['atk_Cornice_Thickness'])#10
house_params.append(obj['atk_Ridge_Height'])#11
house_params.append(obj['atk_Walls_Thickness'])#12
house_params.append(obj['atk_Roof_Walls_Height'])#13
house_params.append(obj['atk_Road_Parallelism '])#14
house_params.append(obj.location[0])#15
house_params.append(obj.location[1])#16
house_params.append(obj.location[2])#17
house_params.append(obj.rotation_euler[2])#18
house_params.append(obj['atk_Create_Interior'])#19
bpy.ops.object.delete()
bpy.ops.ed.undo_push(message="Add an undo step *function may be moved*")
print(house_params)
bpy.ops.mesh.primitive_house_add(
True,
atk_width=house_params[1],
atk_length=house_params[2],
atk_foundation_height=house_params[3],
atk_ground_floor_height=house_params[4],
atk_floors_thickness=house_params[5],
atk_first_floor_height=house_params[6],
atk_generic_floor_height=house_params[7],
atk_floors_number=house_params[8],
atk_last_floor_height=house_params[9],
atk_cornice_thickness=house_params[10],
atk_ridge_height=house_params[11],
atk_walls_thickness=house_params[12],
atk_roof_walls_height=house_params[13],
atk_road_parallelism=house_params[14],
location=(house_params[15],
house_params[16],
house_params[17]),
rotation=(0,0,house_params[18]),
atk_create_interior=house_params[19]
)
return {'FINISHED'}
class OBJECT_OT_House_modify_house_with_settings(bpy.types.Operator):
bl_label = "Modify House with settings"
bl_idname = "object.house_modify_house_with_settings"
bl_description = "Modify a house with parameters"
@classmethod
def poll(cls, context):
return context.active_object is not None
def execute(self, context):
# main(context)
print(64*'=')
### 1- copy the base object in a new temporary one and select it (apply custom properties we will need later, I think)
scene = bpy.context.scene
obj = bpy.context.object
ver = obj.data.vertices
edg = obj.data.edges
num = len(edg)
house_params=[]
house_params.append(obj['atk_Id'])#0
house_params.append(obj['atk_Width'])#1
house_params.append(obj['atk_Length'])#2
house_params.append(obj['atk_Foundation_Height'])#3
house_params.append(obj['atk_Ground_Floor_Height'])#4
house_params.append(obj['atk_Floors_Thickness'])#5
house_params.append(obj['atk_First_Floor_Height'])#6
house_params.append(obj['atk_Generic_Floor_Height'])#7
house_params.append(obj['atk_Floors_Number'])#8
house_params.append(obj['atk_Last_Floor_Height'])#9
house_params.append(obj['atk_Cornice_Thickness'])#10
house_params.append(obj['atk_Ridge_Height'])#11
house_params.append(obj['atk_Walls_Thickness'])#12
house_params.append(obj['atk_Roof_Walls_Height'])#13
house_params.append(obj['atk_Road_Parallelism '])#14
house_params.append(obj.location[0])#15
house_params.append(obj.location[1])#16
house_params.append(obj.location[2])#17
house_params.append(obj.rotation_euler[2])#18
house_params.append(obj['atk_Create_Interior'])#19
bpy.ops.object.delete(use_global=False)
print(house_params)
bpy.ops.mesh.primitive_house_add(
True,
atk_width=scene.atk_width,
atk_length=scene.atk_length,
atk_foundation_height=scene.atk_foundation_height,
atk_ground_floor_height=scene.atk_ground_floor_height,
atk_floors_thickness=scene.atk_floors_thickness,
atk_first_floor_height=scene.atk_first_floor_height,
atk_generic_floor_height=scene.atk_generic_floor_height,
atk_floors_number=scene.atk_floors_number,
atk_last_floor_height=scene.atk_last_floor_height,
atk_cornice_thickness=scene.atk_cornice_thickness,
atk_ridge_height=scene.atk_ridge_height,
atk_walls_thickness=scene.atk_walls_thickness,
atk_roof_walls_height=scene.atk_roof_walls_height,
atk_road_parallelism=scene.atk_road_parallelism,
location=(house_params[15],
house_params[16],
house_params[17]),
rotation=(0,0,house_params[18]),
atk_create_interior=house_params[19]
)
return {'FINISHED'}
# registering and menu integration
def register():
bpy.utils.register_class(OBJECT_PT_ArToKi_House)
bpy.utils.register_class(OBJECT_OT_House_create_houses)
bpy.utils.register_class(OBJECT_OT_House_modify_house)
bpy.utils.register_class(OBJECT_OT_House_modify_house_with_settings)
# unregistering and removing menus
def unregister():
bpy.utils.unregister_class(OBJECT_PT_ArToKi_House)
bpy.utils.unregister_class(OBJECT_OT_House_create_houses)
bpy.utils.unregister_class(OBJECT_OT_House_modify_house)
bpy.utils.unregister_class(OBJECT_OT_House_modify_house_with_settings)
if __name__ == "__main__":
register()

File Metadata

Mime Type
text/x-python
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
60/d7/e5acf71c861bdea5e34a99e7176f

Event Timeline