mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-21 08:35:14 +00:00
Refactor create_space operator and better UI for covering tool
This commit is contained in:
@@ -42,13 +42,14 @@ class CoveringTool(WorkSpaceTool):
|
|||||||
bl_description = "Create and edit coverings"
|
bl_description = "Create and edit coverings"
|
||||||
bl_icon = os.path.join(os.path.dirname(__file__), "ops.authoring.covering")
|
bl_icon = os.path.join(os.path.dirname(__file__), "ops.authoring.covering")
|
||||||
bl_widget = None
|
bl_widget = None
|
||||||
|
ifc_element_type = "IfcCoveringType"
|
||||||
bl_keymap = tool.Blender.get_default_selection_keypmap() + (
|
bl_keymap = tool.Blender.get_default_selection_keypmap() + (
|
||||||
("bim.covering_hotkey", {"type": "A", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_A")]}),
|
("bim.covering_hotkey", {"type": "A", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_A")]}),
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def draw_settings(cls, context, layout, ws_tool):
|
def draw_settings(cls, context, layout, ws_tool):
|
||||||
CoveringToolUI.draw(context, layout, ifc_element_type="IfcCoveringType")
|
CoveringToolUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
|
||||||
|
|
||||||
def add_layout_hotkey(layout, text, hotkey, description):
|
def add_layout_hotkey(layout, text, hotkey, description):
|
||||||
args = ["covering", layout, text, hotkey, description]
|
args = ["covering", layout, text, hotkey, description]
|
||||||
@@ -71,7 +72,6 @@ class CoveringToolUI:
|
|||||||
elif AuthoringData.data["ifc_element_type"] != ifc_element_type:
|
elif AuthoringData.data["ifc_element_type"] != ifc_element_type:
|
||||||
AuthoringData.load(ifc_element_type)
|
AuthoringData.load(ifc_element_type)
|
||||||
|
|
||||||
|
|
||||||
if context.region.type == "TOOL_HEADER":
|
if context.region.type == "TOOL_HEADER":
|
||||||
cls.draw_header_interface()
|
cls.draw_header_interface()
|
||||||
elif context.region.type in ("UI", "WINDOW"):
|
elif context.region.type in ("UI", "WINDOW"):
|
||||||
@@ -97,6 +97,7 @@ class CoveringToolUI:
|
|||||||
if AuthoringData.data["predefined_type"] == "FLOORING":
|
if AuthoringData.data["predefined_type"] == "FLOORING":
|
||||||
if element and bpy.context.selected_objects and element.is_a("IfcWall"):
|
if element and bpy.context.selected_objects and element.is_a("IfcWall"):
|
||||||
op = row.operator("bim.add_instance_flooring_coverings_from_walls")
|
op = row.operator("bim.add_instance_flooring_coverings_from_walls")
|
||||||
|
# PLEASE KEEP COMMENTS AS A REMINDER
|
||||||
# elif element and bpy.context.selected_objects and element.is_a("IfcSpace"):
|
# elif element and bpy.context.selected_objects and element.is_a("IfcSpace"):
|
||||||
# op. = row.operator("bim.add_istance_flooring_from_spaces"):
|
# op. = row.operator("bim.add_istance_flooring_from_spaces"):
|
||||||
else:
|
else:
|
||||||
@@ -183,8 +184,11 @@ class Hotkey(bpy.types.Operator, Operator):
|
|||||||
def hotkey_S_A(self):
|
def hotkey_S_A(self):
|
||||||
active_obj = bpy.context.active_object
|
active_obj = bpy.context.active_object
|
||||||
element = tool.Ifc.get_entity(active_obj)
|
element = tool.Ifc.get_entity(active_obj)
|
||||||
if element and bpy.context.selected_objects and element.is_a("IfcWall"):
|
if AuthoringData.data["predefined_type"] == "FLOORING":
|
||||||
bpy.ops.bim.add_instance_flooring_coverings_from_walls()
|
if element and bpy.context.selected_objects and element.is_a("IfcWall"):
|
||||||
|
bpy.ops.bim.add_instance_flooring_coverings_from_walls()
|
||||||
|
else:
|
||||||
|
bpy.ops.bim.add_constr_type_instance()
|
||||||
else:
|
else:
|
||||||
bpy.ops.bim.add_constr_type_instance()
|
bpy.ops.bim.add_constr_type_instance()
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import blenderbim.core.covering as core
|
|||||||
|
|
||||||
class AddInstanceFlooringCoveringsFromWalls(bpy.types.Operator, tool.Ifc.Operator):
|
class AddInstanceFlooringCoveringsFromWalls(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.add_instance_flooring_coverings_from_walls"
|
bl_idname = "bim.add_instance_flooring_coverings_from_walls"
|
||||||
bl_label = "Add Covering From Walls"
|
bl_label = "Add Flooring From Walls"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
bl_description = "Add instance flooring coverings from selected walls. The active object must be a wall and layered vertically"
|
bl_description = "Add instance flooring coverings from selected walls. The active object must be a wall and layered vertically"
|
||||||
|
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ def update_type_class(self, context):
|
|||||||
def update_relating_type_id(self, context):
|
def update_relating_type_id(self, context):
|
||||||
AuthoringData.data["relating_type_id"] = AuthoringData.relating_type_id()
|
AuthoringData.data["relating_type_id"] = AuthoringData.relating_type_id()
|
||||||
AuthoringData.data["type_thumbnail"] = AuthoringData.type_thumbnail()
|
AuthoringData.data["type_thumbnail"] = AuthoringData.type_thumbnail()
|
||||||
|
AuthoringData.data["predefined_type"] = AuthoringData.predefined_type()
|
||||||
|
|
||||||
|
|
||||||
def update_type_page(self, context):
|
def update_type_page(self, context):
|
||||||
|
|||||||
@@ -50,13 +50,7 @@ class GenerateSpace(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
def msg(self, context):
|
def msg(self, context):
|
||||||
self.layout.label(text="NO ACTIVE STOREY")
|
self.layout.label(text="NO ACTIVE STOREY")
|
||||||
|
|
||||||
props = context.scene.BIMModelProperties
|
# props = context.scene.BIMModelProperties
|
||||||
relating_type_id = props.relating_type_id
|
|
||||||
relating_type = None
|
|
||||||
if relating_type_id:
|
|
||||||
relating_type = tool.Ifc.get().by_id(int(relating_type_id))
|
|
||||||
if not relating_type.is_a("IfcSpaceType"):
|
|
||||||
relating_type = None
|
|
||||||
|
|
||||||
collection = context.view_layer.active_layer_collection.collection
|
collection = context.view_layer.active_layer_collection.collection
|
||||||
collection_obj = collection.BIMCollectionProperties.obj
|
collection_obj = collection.BIMCollectionProperties.obj
|
||||||
@@ -68,158 +62,7 @@ class GenerateSpace(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
bpy.context.window_manager.popup_menu(msg, title="Error", icon="ERROR")
|
bpy.context.window_manager.popup_menu(msg, title="Error", icon="ERROR")
|
||||||
return
|
return
|
||||||
|
|
||||||
# core.generate_space(tool.Ifc, tool.Spatial)
|
core.generate_space(tool.Ifc, tool.Spatial, tool.Model)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
active_obj = bpy.context.active_object
|
|
||||||
element = None
|
|
||||||
if bpy.context.selected_objects and active_obj:
|
|
||||||
element = tool.Ifc.get_entity(active_obj)
|
|
||||||
mat = active_obj.matrix_world
|
|
||||||
local_bbox_center = 0.125 * sum((Vector(b) for b in active_obj.bound_box), Vector())
|
|
||||||
global_bbox_center = mat @ local_bbox_center
|
|
||||||
x = global_bbox_center.x
|
|
||||||
y = global_bbox_center.y
|
|
||||||
z = (mat @ Vector(active_obj.bound_box[0])).z
|
|
||||||
|
|
||||||
h = active_obj.dimensions.z
|
|
||||||
else:
|
|
||||||
x, y = context.scene.cursor.location.xy
|
|
||||||
z = collection_obj.matrix_world.translation.z
|
|
||||||
mat = Matrix()
|
|
||||||
mat.translation = (x, y, z)
|
|
||||||
h = 3
|
|
||||||
|
|
||||||
calculation_rl = context.scene.BIMModelProperties.rl3
|
|
||||||
self.cut_point = collection_obj.matrix_world.translation.copy() + Vector((0, 0, calculation_rl))
|
|
||||||
self.cut_normal = Vector((0, 0, 1))
|
|
||||||
boundary_lines = []
|
|
||||||
|
|
||||||
gross_settings = ifcopenshell.geom.settings()
|
|
||||||
gross_settings.set(gross_settings.DISABLE_OPENING_SUBTRACTIONS, True)
|
|
||||||
|
|
||||||
for obj in bpy.context.visible_objects:
|
|
||||||
visible_element = tool.Ifc.get_entity(obj)
|
|
||||||
|
|
||||||
if (
|
|
||||||
not visible_element
|
|
||||||
or obj.type != "MESH"
|
|
||||||
or not self.is_bounding_class(visible_element)
|
|
||||||
or not tool.Drawing.is_intersecting_plane(obj, self.cut_point, self.cut_normal)
|
|
||||||
):
|
|
||||||
continue
|
|
||||||
|
|
||||||
old_mesh = None
|
|
||||||
if visible_element.HasOpenings:
|
|
||||||
new_mesh = self.create_mesh(ifcopenshell.geom.create_shape(gross_settings, visible_element))
|
|
||||||
old_mesh = obj.data
|
|
||||||
obj.data = new_mesh
|
|
||||||
|
|
||||||
local_cut_point = obj.matrix_world.inverted() @ self.cut_point
|
|
||||||
local_cut_normal = obj.matrix_world.inverted().to_quaternion() @ self.cut_normal
|
|
||||||
verts, edges = tool.Drawing.bisect_mesh_with_plane(obj, local_cut_point, local_cut_normal)
|
|
||||||
|
|
||||||
if old_mesh:
|
|
||||||
obj.data = old_mesh
|
|
||||||
bpy.data.meshes.remove(new_mesh)
|
|
||||||
|
|
||||||
for edge in edges or []:
|
|
||||||
boundary_lines.append(
|
|
||||||
shapely.LineString(
|
|
||||||
[Vector((round(x, 3) for x in verts[edge[0]])), Vector((round(x, 3) for x in verts[edge[1]]))]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
unioned_boundaries = shapely.union_all(shapely.GeometryCollection(boundary_lines))
|
|
||||||
closed_polygons = shapely.polygonize(unioned_boundaries.geoms)
|
|
||||||
|
|
||||||
space_polygon = None
|
|
||||||
for polygon in closed_polygons.geoms:
|
|
||||||
if shapely.contains_xy(polygon, x, y):
|
|
||||||
space_polygon = shapely.force_3d(polygon)
|
|
||||||
|
|
||||||
if not space_polygon:
|
|
||||||
return
|
|
||||||
|
|
||||||
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], z])) for v in space_polygon.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]))
|
|
||||||
|
|
||||||
for interior in space_polygon.interiors:
|
|
||||||
new_verts = [bm.verts.new(mat_invert @ Vector([v[0], v[1], z])) for v in interior.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)
|
|
||||||
|
|
||||||
mesh = bpy.data.meshes.new(name="Space")
|
|
||||||
bm.to_mesh(mesh)
|
|
||||||
bm.free()
|
|
||||||
|
|
||||||
if element and element.is_a("IfcSpace"):
|
|
||||||
mesh.name = active_obj.data.name
|
|
||||||
mesh.BIMMeshProperties.ifc_definition_id = active_obj.data.BIMMeshProperties.ifc_definition_id
|
|
||||||
tool.Geometry.change_object_data(active_obj, mesh, is_global=True)
|
|
||||||
tool.Ifc.edit(active_obj)
|
|
||||||
else:
|
|
||||||
if relating_type:
|
|
||||||
name = tool.Model.generate_occurrence_name(relating_type, "IfcSpace")
|
|
||||||
else:
|
|
||||||
name = "Space"
|
|
||||||
obj = bpy.data.objects.new("Space", mesh)
|
|
||||||
obj.matrix_world = mat
|
|
||||||
collection.objects.link(obj)
|
|
||||||
bpy.ops.bim.assign_class(obj=obj.name, ifc_class="IfcSpace")
|
|
||||||
element = tool.Ifc.get_entity(obj)
|
|
||||||
if relating_type:
|
|
||||||
blenderbim.core.type.assign_type(tool.Ifc, tool.Type, element=element, type=relating_type)
|
|
||||||
|
|
||||||
def is_bounding_class(self, element):
|
|
||||||
for ifc_class in ["IfcWall", "IfcColumn", "IfcMember", "IfcVirtualElement", "IfcPlate"]:
|
|
||||||
if element.is_a(ifc_class):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def create_mesh(self, shape):
|
|
||||||
geometry = shape.geometry
|
|
||||||
mesh = bpy.data.meshes.new("tmp")
|
|
||||||
verts = geometry.verts
|
|
||||||
if geometry.faces:
|
|
||||||
num_vertices = len(verts) // 3
|
|
||||||
total_faces = len(geometry.faces)
|
|
||||||
loop_start = range(0, total_faces, 3)
|
|
||||||
num_loops = total_faces // 3
|
|
||||||
loop_total = [3] * num_loops
|
|
||||||
num_vertex_indices = len(geometry.faces)
|
|
||||||
|
|
||||||
mesh.vertices.add(num_vertices)
|
|
||||||
mesh.vertices.foreach_set("co", verts)
|
|
||||||
mesh.loops.add(num_vertex_indices)
|
|
||||||
mesh.loops.foreach_set("vertex_index", geometry.faces)
|
|
||||||
mesh.polygons.add(num_loops)
|
|
||||||
mesh.polygons.foreach_set("loop_start", loop_start)
|
|
||||||
mesh.polygons.foreach_set("loop_total", loop_total)
|
|
||||||
mesh.polygons.foreach_set("use_smooth", [0] * total_faces)
|
|
||||||
mesh.update()
|
|
||||||
return mesh
|
|
||||||
|
|
||||||
|
|
||||||
class GenerateSpacesFromWalls(bpy.types.Operator, tool.Ifc.Operator):
|
class GenerateSpacesFromWalls(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
|
|||||||
@@ -16,8 +16,7 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import blenderbim.core
|
import blenderbim.core.type
|
||||||
|
|
||||||
|
|
||||||
def reference_structure(ifc, spatial, structure=None, element=None):
|
def reference_structure(ifc, spatial, structure=None, element=None):
|
||||||
if spatial.can_reference(structure, element):
|
if spatial.can_reference(structure, element):
|
||||||
@@ -128,8 +127,51 @@ def select_decomposed_elements(spatial):
|
|||||||
spatial.select_products(spatial.get_decomposed_elements(container))
|
spatial.select_products(spatial.get_decomposed_elements(container))
|
||||||
|
|
||||||
#HERE STARTS SPATIAL TOOL
|
#HERE STARTS SPATIAL TOOL
|
||||||
def generate_space(ifc, spatial):
|
def generate_space(ifc, spatial, model):
|
||||||
pass
|
active_obj = spatial.get_active_obj()
|
||||||
|
selected_objects = spatial.get_selected_objects()
|
||||||
|
element = None
|
||||||
|
relating_type_id = spatial.get_relating_type_id()
|
||||||
|
|
||||||
|
relating_type = None
|
||||||
|
if relating_type_id:
|
||||||
|
relating_type = ifc.get().by_id(int(relating_type_id))
|
||||||
|
if not relating_type.is_a("IfcSpaceType"):
|
||||||
|
relating_type = None
|
||||||
|
|
||||||
|
if selected_objects and active_obj:
|
||||||
|
x, y, z, h, mat = spatial.get_x_y_z_h_mat_from_active_obj(active_obj) ##mat
|
||||||
|
element = ifc.get_entity(active_obj)
|
||||||
|
|
||||||
|
else:
|
||||||
|
x, y, z, h, mat = spatial.get_x_y_z_h_mat_from_cursor() ##mat
|
||||||
|
|
||||||
|
space_polygon = spatial.get_space_polygon_from_context_visible_objects(x, y)
|
||||||
|
|
||||||
|
if not space_polygon:
|
||||||
|
return
|
||||||
|
|
||||||
|
bm = spatial.get_bmesh_from_polygon(space_polygon, h=h) ##mat
|
||||||
|
|
||||||
|
mesh = spatial.get_named_mesh_from_bmesh(name = "Space", bmesh = bm)
|
||||||
|
|
||||||
|
if element and element.is_a("IfcSpace"):
|
||||||
|
spatial.edit_active_space_obj_from_mesh(mesh)
|
||||||
|
else:
|
||||||
|
if relating_type:
|
||||||
|
name = model.generate_occurrence_name(relating_type, "IfcSpace")
|
||||||
|
else:
|
||||||
|
name = "Space"
|
||||||
|
|
||||||
|
obj = spatial.get_named_obj_from_mesh(name, mesh) ##mat
|
||||||
|
spatial.set_obj_origin_to_cursor_position(obj)
|
||||||
|
spatial.link_obj_to_active_collection(obj)
|
||||||
|
spatial.assign_ifcspace_class_to_obj(obj)
|
||||||
|
|
||||||
|
element = ifc.get_entity(obj)
|
||||||
|
|
||||||
|
if relating_type:
|
||||||
|
blenderbim.core.type.assign_type(tool.Ifc, tool.Type, element=element, type=relating_type)
|
||||||
|
|
||||||
|
|
||||||
def generate_spaces_from_walls(ifc, spatial, collector):
|
def generate_spaces_from_walls(ifc, spatial, collector):
|
||||||
|
|||||||
@@ -809,6 +809,13 @@ class Spatial:
|
|||||||
def set_relative_object_matrix(cls, target_obj, relative_to_obj, matrix): pass
|
def set_relative_object_matrix(cls, target_obj, relative_to_obj, matrix): pass
|
||||||
def show_scene_objects(cls): pass
|
def show_scene_objects(cls): pass
|
||||||
#HERE STARTS SPATIAL TOOL
|
#HERE STARTS SPATIAL TOOL
|
||||||
|
def is_bounding_class(cls, visible_element): pass
|
||||||
|
def get_space_polygon_from_context_visible_objects(cls, x, y): pass
|
||||||
|
def get_boundary_lines_from_context_visible_objects(cls, visible_objects): pass
|
||||||
|
def get_gross_mesh_from_element(cls, visible_element): pass
|
||||||
|
def create_mesh_from_shape(cls, shape): pass
|
||||||
|
def get_x_y_z_h_mat_from_active_obj(cls, active_obj): pass
|
||||||
|
def get_x_y_z_h_mat_from_cursor(cls): pass
|
||||||
def get_union_shape_from_selected_objects(cls): pass
|
def get_union_shape_from_selected_objects(cls): pass
|
||||||
def get_boundary_elements(cls, selected_objects): pass
|
def get_boundary_elements(cls, selected_objects): pass
|
||||||
def get_polygons(cls, boundary_elements): pass
|
def get_polygons(cls, boundary_elements): pass
|
||||||
@@ -819,9 +826,16 @@ class Spatial:
|
|||||||
def get_buffered_poly_from_linear_ring(cls, linear_ring): pass
|
def get_buffered_poly_from_linear_ring(cls, linear_ring): pass
|
||||||
def get_bmesh_from_polygon(cls, poly, h): pass
|
def get_bmesh_from_polygon(cls, poly, h): pass
|
||||||
def get_named_obj_from_bmesh(cls, name, bmesh): pass
|
def get_named_obj_from_bmesh(cls, name, bmesh): pass
|
||||||
|
def get_named_obj_from_mesh(cls, name, mesh): pass
|
||||||
|
def get_named_mesh_from_bmesh(cls, name, bmesh): pass
|
||||||
|
def edit_active_space_obj_from_mesh(cls, mesh): pass
|
||||||
def set_obj_origin_to_bboxcenter(cls, obj): pass
|
def set_obj_origin_to_bboxcenter(cls, obj): pass
|
||||||
|
def set_obj_origin_to_cursor_position(cls, obj): pass
|
||||||
|
def get_selected_objects(cls): pass
|
||||||
|
def get_active_obj(cls): pass
|
||||||
def get_active_obj_z(cls): pass
|
def get_active_obj_z(cls): pass
|
||||||
def get_active_obj_height(cls): pass
|
def get_active_obj_height(cls): pass
|
||||||
|
def get_relating_type_id(cls): pass
|
||||||
def traslate_obj_to_z_location(cls, obj): pass
|
def traslate_obj_to_z_location(cls, obj): pass
|
||||||
def link_obj_to_active_collection(cls, obj): pass
|
def link_obj_to_active_collection(cls, obj): pass
|
||||||
def get_2d_vertices_from_obj(cls, obj): pass
|
def get_2d_vertices_from_obj(cls, obj): pass
|
||||||
|
|||||||
@@ -270,6 +270,123 @@ class Spatial(blenderbim.core.tool.Spatial):
|
|||||||
|
|
||||||
#HERE STARTS SPATIAL TOOL
|
#HERE STARTS SPATIAL TOOL
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_bounding_class(cls, visible_element):
|
||||||
|
for ifc_class in ["IfcWall", "IfcColumn", "IfcMember", "IfcVirtualElement", "IfcPlate"]:
|
||||||
|
if visible_element.is_a(ifc_class):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_space_polygon_from_context_visible_objects(cls, x, y):
|
||||||
|
boundary_lines = cls.get_boundary_lines_from_context_visible_objects()
|
||||||
|
unioned_boundaries = shapely.union_all(shapely.GeometryCollection(boundary_lines))
|
||||||
|
closed_polygons = shapely.polygonize(unioned_boundaries.geoms)
|
||||||
|
space_polygon = None
|
||||||
|
for polygon in closed_polygons.geoms:
|
||||||
|
if shapely.contains_xy(polygon, x, y):
|
||||||
|
space_polygon = shapely.force_3d(polygon)
|
||||||
|
return space_polygon
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_boundary_lines_from_context_visible_objects(cls):
|
||||||
|
calculation_rl = bpy.context.scene.BIMModelProperties.rl3
|
||||||
|
collection = bpy.context.view_layer.active_layer_collection.collection
|
||||||
|
collection_obj = collection.BIMCollectionProperties.obj
|
||||||
|
cut_point = collection_obj.matrix_world.translation.copy() + Vector((0, 0, calculation_rl))
|
||||||
|
cut_normal = Vector((0, 0, 1))
|
||||||
|
boundary_lines = []
|
||||||
|
|
||||||
|
for obj in bpy.context.visible_objects:
|
||||||
|
|
||||||
|
|
||||||
|
visible_element = tool.Ifc.get_entity(obj)
|
||||||
|
|
||||||
|
if (
|
||||||
|
not visible_element
|
||||||
|
or obj.type != "MESH"
|
||||||
|
or not cls.is_bounding_class(visible_element)
|
||||||
|
or not tool.Drawing.is_intersecting_plane(obj, cut_point, cut_normal)
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
|
old_mesh = None
|
||||||
|
if visible_element.HasOpenings:
|
||||||
|
new_mesh = cls.get_gross_mesh_from_element(visible_element)
|
||||||
|
old_mesh = obj.data
|
||||||
|
obj.data = new_mesh
|
||||||
|
|
||||||
|
local_cut_point = obj.matrix_world.inverted() @ cut_point
|
||||||
|
local_cut_normal = obj.matrix_world.inverted().to_quaternion() @ cut_normal
|
||||||
|
verts, edges = tool.Drawing.bisect_mesh_with_plane(obj, local_cut_point, local_cut_normal)
|
||||||
|
|
||||||
|
if old_mesh:
|
||||||
|
obj.data = old_mesh
|
||||||
|
bpy.data.meshes.remove(new_mesh)
|
||||||
|
|
||||||
|
for edge in edges or []:
|
||||||
|
boundary_lines.append(
|
||||||
|
shapely.LineString(
|
||||||
|
[Vector((round(x, 3) for x in verts[edge[0]])), Vector((round(x, 3) for x in verts[edge[1]]))]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return boundary_lines
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_gross_mesh_from_element(cls, visible_element):
|
||||||
|
gross_settings = ifcopenshell.geom.settings()
|
||||||
|
gross_settings.set(gross_settings.DISABLE_OPENING_SUBTRACTIONS, True)
|
||||||
|
new_mesh = cls.create_mesh_from_shape(ifcopenshell.geom.create_shape(gross_settings, visible_element))
|
||||||
|
return new_mesh
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_mesh_from_shape(cls, shape):
|
||||||
|
geometry = shape.geometry
|
||||||
|
mesh = bpy.data.meshes.new("tmp")
|
||||||
|
verts = geometry.verts
|
||||||
|
if geometry.faces:
|
||||||
|
num_vertices = len(verts) // 3
|
||||||
|
total_faces = len(geometry.faces)
|
||||||
|
loop_start = range(0, total_faces, 3)
|
||||||
|
num_loops = total_faces // 3
|
||||||
|
loop_total = [3] * num_loops
|
||||||
|
num_vertex_indices = len(geometry.faces)
|
||||||
|
|
||||||
|
mesh.vertices.add(num_vertices)
|
||||||
|
mesh.vertices.foreach_set("co", verts)
|
||||||
|
mesh.loops.add(num_vertex_indices)
|
||||||
|
mesh.loops.foreach_set("vertex_index", geometry.faces)
|
||||||
|
mesh.polygons.add(num_loops)
|
||||||
|
mesh.polygons.foreach_set("loop_start", loop_start)
|
||||||
|
mesh.polygons.foreach_set("loop_total", loop_total)
|
||||||
|
mesh.polygons.foreach_set("use_smooth", [0] * total_faces)
|
||||||
|
mesh.update()
|
||||||
|
return mesh
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_x_y_z_h_mat_from_active_obj(cls, active_obj):
|
||||||
|
element = tool.Ifc.get_entity(active_obj)
|
||||||
|
mat = active_obj.matrix_world
|
||||||
|
local_bbox_center = 0.125 * sum((Vector(b) for b in active_obj.bound_box), Vector())
|
||||||
|
global_bbox_center = mat @ local_bbox_center
|
||||||
|
x = global_bbox_center.x
|
||||||
|
y = global_bbox_center.y
|
||||||
|
z = (mat @ Vector(active_obj.bound_box[0])).z
|
||||||
|
|
||||||
|
h = active_obj.dimensions.z
|
||||||
|
return x, y, z, h, mat
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_x_y_z_h_mat_from_cursor(cls):
|
||||||
|
collection = bpy.context.view_layer.active_layer_collection.collection
|
||||||
|
collection_obj = collection.BIMCollectionProperties.obj
|
||||||
|
x, y = bpy.context.scene.cursor.location.xy
|
||||||
|
z = collection_obj.matrix_world.translation.z
|
||||||
|
mat = Matrix()
|
||||||
|
h = 3
|
||||||
|
return x, y, z, h, mat
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_union_shape_from_selected_objects(cls):
|
def get_union_shape_from_selected_objects(cls):
|
||||||
selected_objects = bpy.context.selected_objects
|
selected_objects = bpy.context.selected_objects
|
||||||
@@ -369,7 +486,11 @@ class Spatial(blenderbim.core.tool.Spatial):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_bmesh_from_polygon(cls, poly, h):
|
def get_bmesh_from_polygon(cls, poly, h):
|
||||||
mat = bpy.context.active_object.matrix_world
|
if bpy.context.selected_objects and bpy.context.active_object:
|
||||||
|
mat = bpy.context.active_object.matrix_world
|
||||||
|
else:
|
||||||
|
mat = Matrix()
|
||||||
|
|
||||||
bm = bmesh.new()
|
bm = bmesh.new()
|
||||||
bm.verts.index_update()
|
bm.verts.index_update()
|
||||||
bm.edges.index_update()
|
bm.edges.index_update()
|
||||||
@@ -398,13 +519,32 @@ class Spatial(blenderbim.core.tool.Spatial):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_named_obj_from_bmesh(cls, name, bmesh):
|
def get_named_obj_from_bmesh(cls, name, bmesh):
|
||||||
|
mesh = cls.get_named_mesh_from_bmesh(name, bmesh)
|
||||||
|
obj = cls.get_named_obj_from_mesh(name, mesh)
|
||||||
|
return obj
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_named_obj_from_mesh(cls, name, mesh):
|
||||||
|
obj = bpy.data.objects.new(name, mesh)
|
||||||
|
if bpy.context.active_object:
|
||||||
|
mat = bpy.context.active_object.matrix_world
|
||||||
|
obj.matrix_world = mat
|
||||||
|
return obj
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_named_mesh_from_bmesh(cls, name, bmesh):
|
||||||
mesh = bpy.data.meshes.new(name=name)
|
mesh = bpy.data.meshes.new(name=name)
|
||||||
bmesh.to_mesh(mesh)
|
bmesh.to_mesh(mesh)
|
||||||
bmesh.free()
|
bmesh.free()
|
||||||
obj = bpy.data.objects.new(name, mesh)
|
return mesh
|
||||||
mat = bpy.context.active_object.matrix_world
|
|
||||||
obj.matrix_world = mat
|
@classmethod
|
||||||
return obj
|
def edit_active_space_obj_from_mesh(cls, mesh):
|
||||||
|
active_obj = bpy.context.active_object
|
||||||
|
mesh.name = active_obj.data.name
|
||||||
|
mesh.BIMMeshProperties.ifc_definition_id = active_obj.data.BIMMeshProperties.ifc_definition_id
|
||||||
|
tool.Geometry.change_object_data(active_obj, mesh, is_global=True)
|
||||||
|
tool.Ifc.edit(active_obj)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def set_obj_origin_to_bboxcenter(cls, obj):
|
def set_obj_origin_to_bboxcenter(cls, obj):
|
||||||
@@ -422,6 +562,34 @@ class Spatial(blenderbim.core.tool.Spatial):
|
|||||||
vert.co = inverted @ aux_vector
|
vert.co = inverted @ aux_vector
|
||||||
obj.location = newLoc
|
obj.location = newLoc
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def set_obj_origin_to_cursor_position(cls, obj):
|
||||||
|
mat = obj.matrix_world
|
||||||
|
inverted = mat.inverted()
|
||||||
|
|
||||||
|
|
||||||
|
collection = bpy.context.view_layer.active_layer_collection.collection
|
||||||
|
collection_obj = collection.BIMCollectionProperties.obj
|
||||||
|
x, y = bpy.context.scene.cursor.location.xy
|
||||||
|
z = collection_obj.matrix_world.translation.z
|
||||||
|
|
||||||
|
oldLoc = obj.location
|
||||||
|
newLoc = Vector((x,y,z))
|
||||||
|
diff = newLoc - oldLoc
|
||||||
|
for vert in obj.data.vertices:
|
||||||
|
aux_vector = mat @ vert.co
|
||||||
|
aux_vector = aux_vector - diff
|
||||||
|
vert.co = inverted @ aux_vector
|
||||||
|
obj.location = newLoc
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_selected_objects(cls):
|
||||||
|
return bpy.context.selected_objects
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_active_obj(cls):
|
||||||
|
return bpy.context.active_object
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_active_obj_z(cls):
|
def get_active_obj_z(cls):
|
||||||
x, y, z = bpy.context.active_object.matrix_world.translation.xyz
|
x, y, z = bpy.context.active_object.matrix_world.translation.xyz
|
||||||
@@ -432,6 +600,12 @@ class Spatial(blenderbim.core.tool.Spatial):
|
|||||||
height = bpy.context.active_object.dimensions.z
|
height = bpy.context.active_object.dimensions.z
|
||||||
return height
|
return height
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_relating_type_id(cls):
|
||||||
|
props = bpy.context.scene.BIMModelProperties
|
||||||
|
relating_type_id = props.relating_type_id
|
||||||
|
return relating_type_id
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def traslate_obj_to_z_location(cls, obj, z):
|
def traslate_obj_to_z_location(cls, obj, z):
|
||||||
if z != 0:
|
if z != 0:
|
||||||
|
|||||||
Reference in New Issue
Block a user