mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 17:58:20 +00:00
Now it's possible to create spaces automatically from selected walls
This commit is contained in:
@@ -96,6 +96,7 @@ classes = (
|
||||
slab.ResetVertex,
|
||||
slab.SetArcIndex,
|
||||
space.GenerateSpace,
|
||||
space.GenerateSpacesFromWalls,
|
||||
prop.BIMModelProperties,
|
||||
prop.BIMArrayProperties,
|
||||
prop.BIMStairProperties,
|
||||
|
||||
@@ -26,6 +26,7 @@ import blenderbim.tool as tool
|
||||
import blenderbim.core.type
|
||||
from math import pi
|
||||
from mathutils import Vector, Matrix
|
||||
from shapely import Polygon
|
||||
|
||||
|
||||
class GenerateSpace(bpy.types.Operator, tool.Ifc.Operator):
|
||||
@@ -166,3 +167,140 @@ class GenerateSpace(bpy.types.Operator, tool.Ifc.Operator):
|
||||
(obj.matrix_world @ Vector((max_x, max_y, 0.0))).to_2d(),
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
class GenerateSpacesFromWalls(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.generate_spaces_from_walls"
|
||||
bl_label = "Generate Spaces From Walls"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Generate spaces from selected walls. The active object must be a wall."
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.selected_objects
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMModelProperties
|
||||
|
||||
active_obj = bpy.context.active_object
|
||||
if not active_obj:
|
||||
self.report({'ERROR'}, "No active object. Please select a wall")
|
||||
return
|
||||
|
||||
element = None
|
||||
element = tool.Ifc.get_entity(active_obj)
|
||||
if not element.is_a("IfcWall"):
|
||||
self.report({'ERROR'}, "The active object is not a wall. Please select a wall.")
|
||||
return
|
||||
|
||||
collection = active_obj.users_collection[0]
|
||||
collection_obj = bpy.data.objects.get(collection.name)
|
||||
if not collection_obj:
|
||||
self.report({'ERROR'}, "No collection found. Please insert one.")
|
||||
return
|
||||
|
||||
spatial_element = tool.Ifc.get_entity(collection_obj)
|
||||
if not spatial_element:
|
||||
self.report({'ERROR'}, "The collection hasn't an ifc space entity. Please provide one.")
|
||||
return
|
||||
|
||||
if not bpy.context.selected_objects:
|
||||
self.report({'ERROR'}, "No selected objects found. Please select walls.")
|
||||
return
|
||||
|
||||
x, y, z = active_obj.matrix_world.translation.xyz
|
||||
mat = active_obj.matrix_world
|
||||
h = active_obj.dimensions.z
|
||||
|
||||
boundary_elements = []
|
||||
for obj in bpy.context.selected_objects:
|
||||
subelement = tool.Ifc.get_entity(obj)
|
||||
if subelement.is_a("IfcWall"):
|
||||
boundary_elements.append(subelement)
|
||||
|
||||
polys = []
|
||||
for boundary_element in boundary_elements:
|
||||
obj = tool.Ifc.get_object(boundary_element)
|
||||
if not obj:
|
||||
continue
|
||||
points = []
|
||||
base = self.get_obj_base_points(obj)
|
||||
for index in ["low_left", "low_right", "high_right", "high_left"]:
|
||||
point = base[index]
|
||||
points.append(point)
|
||||
|
||||
polys.append(Polygon(points))
|
||||
|
||||
model = tool.Ifc.get()
|
||||
|
||||
project_unit = ifcopenshell.util.unit.get_project_unit(model, "LENGTHUNIT")
|
||||
prefix=getattr(project_unit, "Prefix", None)
|
||||
|
||||
tolerance = 0.03
|
||||
|
||||
converted_tolerance = ifcopenshell.util.unit.convert(
|
||||
value = tolerance,
|
||||
from_prefix = None,
|
||||
from_unit = "METRE",
|
||||
to_prefix = prefix,
|
||||
to_unit = project_unit.Name,
|
||||
)
|
||||
|
||||
|
||||
union = shapely.ops.unary_union(polys).buffer(converted_tolerance, cap_style = 2, join_style = 2)
|
||||
|
||||
i=0
|
||||
for linear_ring in union.interiors:
|
||||
poly = Polygon(linear_ring)
|
||||
|
||||
poly = poly.buffer(converted_tolerance, single_sided=True, cap_style = 2, join_style = 2)
|
||||
|
||||
bm = bmesh.new()
|
||||
bm.verts.index_update()
|
||||
bm.edges.index_update()
|
||||
|
||||
mat_invert = mat.inverted()
|
||||
|
||||
new_verts = [bm.verts.new(mat_invert @ Vector([v[0], v[1], 0])) for v in poly.exterior.coords[0:-1]]
|
||||
[bm.edges.new((new_verts[i], new_verts[i + 1])) for i in range(len(new_verts) - 1)]
|
||||
bm.edges.new((new_verts[len(new_verts) - 1], new_verts[0]))
|
||||
|
||||
bm.verts.index_update()
|
||||
bm.edges.index_update()
|
||||
|
||||
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=1e-5)
|
||||
bmesh.ops.triangle_fill(bm, edges=bm.edges)
|
||||
bmesh.ops.dissolve_limit(bm, angle_limit=pi / 180 * 5, verts=bm.verts, edges=bm.edges)
|
||||
|
||||
extrusion = bmesh.ops.extrude_face_region(bm, geom=bm.faces)
|
||||
extruded_verts = [g for g in extrusion["geom"] if isinstance(g, bmesh.types.BMVert)]
|
||||
bmesh.ops.translate(bm, vec=[0.0, 0.0, h], verts=extruded_verts)
|
||||
|
||||
bmesh.ops.recalc_face_normals(bm, faces = bm.faces)
|
||||
|
||||
name = "Space" + str(i)
|
||||
mesh = bpy.data.meshes.new(name = name)
|
||||
bm.to_mesh(mesh)
|
||||
bm.free()
|
||||
|
||||
obj = bpy.data.objects.new(name, mesh)
|
||||
obj.matrix_world = mat
|
||||
collection.objects.link(obj)
|
||||
|
||||
bpy.ops.bim.assign_class(obj=obj.name, ifc_class="IfcSpace")
|
||||
i+=1
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
def get_obj_base_points(self, obj):
|
||||
x_values = [(obj.matrix_world @ Vector(v)).x for v in obj.bound_box]
|
||||
y_values = [(obj.matrix_world @ Vector(v)).y for v in obj.bound_box]
|
||||
return {
|
||||
"low_left": (x_values[0], y_values[0]),
|
||||
"high_left": (x_values[3], y_values[3]),
|
||||
"low_right": (x_values[4], y_values[4]),
|
||||
"high_right": (x_values[7], y_values[7]),
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -135,6 +135,8 @@ class BIM_PT_authoring(Panel):
|
||||
row.operator("bim.align_wall", icon="ANCHOR_TOP", text="Ext.").align_type = "EXTERIOR"
|
||||
row.operator("bim.align_wall", icon="ANCHOR_CENTER", text="C/L").align_type = "CENTERLINE"
|
||||
row.operator("bim.align_wall", icon="ANCHOR_BOTTOM", text="Int.").align_type = "INTERIOR"
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.generate_spaces_from_walls")
|
||||
|
||||
|
||||
class BIM_PT_array(bpy.types.Panel):
|
||||
|
||||
Reference in New Issue
Block a user