New interface to show, select, and remove path connections

This commit is contained in:
Dion Moult
2022-09-20 16:25:52 +10:00
parent de2ada1141
commit e179070978
9 changed files with 164 additions and 4 deletions
@@ -25,17 +25,20 @@ classes = (
operator.EditObjectPlacement,
operator.GetRepresentationIfcParameters,
operator.OverrideDelete,
operator.OverrideOutlinerDelete,
operator.OverrideDuplicateMove,
operator.OverrideDuplicateMoveLinked,
operator.OverrideOutlinerDelete,
operator.OverridePasteBuffer,
operator.RemoveConnection,
operator.RemoveRepresentation,
operator.SelectConnection,
operator.SwitchRepresentation,
operator.UpdateParametricRepresentation,
operator.UpdateRepresentation,
prop.BIMGeometryProperties,
ui.BIM_PT_derived_placements,
ui.BIM_PT_representations,
ui.BIM_PT_connections,
ui.BIM_PT_mesh,
ui.BIM_PT_workarounds,
)
@@ -25,6 +25,7 @@ from mathutils import Vector
def refresh():
DerivedPlacementsData.is_loaded = False
RepresentationsData.is_loaded = False
ConnectionsData.is_loaded = False
class RepresentationsData:
@@ -64,6 +65,36 @@ class RepresentationsData:
return results
class ConnectionsData:
data = {}
is_loaded = False
@classmethod
def load(cls):
cls.data = {"connections": cls.connections()}
cls.is_loaded = True
@classmethod
def connections(cls):
results = []
element = tool.Ifc.get_entity(bpy.context.active_object)
for rel in getattr(element, "ConnectedTo", []):
results.append({
"id": rel.id(),
"is_relating": True,
"Name": rel.RelatedElement.Name or "Unnamed",
"ConnectionType": rel.RelatingConnectionType,
})
for rel in getattr(element, "ConnectedFrom", []):
results.append({
"id": rel.id(),
"is_relating": False,
"Name": rel.RelatingElement.Name or "Unnamed",
"ConnectionType": rel.RelatedConnectionType,
})
return results
class DerivedPlacementsData:
data = {}
is_loaded = False
@@ -86,6 +86,26 @@ class AddRepresentation(bpy.types.Operator, Operator):
)
class SelectConnection(bpy.types.Operator, Operator):
bl_idname = "bim.select_connection"
bl_label = "Select Connection"
bl_options = {"REGISTER", "UNDO"}
connection: bpy.props.IntProperty()
def _execute(self, context):
core.select_connection(tool.Geometry, connection=tool.Ifc.get().by_id(self.connection))
class RemoveConnection(bpy.types.Operator, Operator):
bl_idname = "bim.remove_connection"
bl_label = "Remove Connection"
bl_options = {"REGISTER", "UNDO"}
connection: bpy.props.IntProperty()
def _execute(self, context):
core.remove_connection(tool.Geometry, connection=tool.Ifc.get().by_id(self.connection))
class SwitchRepresentation(bpy.types.Operator, Operator):
bl_idname = "bim.switch_representation"
bl_label = "Switch Representation"
@@ -20,7 +20,7 @@ import bpy
from bpy.types import Panel
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.helper import prop_with_search
from blenderbim.bim.module.geometry.data import RepresentationsData, DerivedPlacementsData
from blenderbim.bim.module.geometry.data import RepresentationsData, ConnectionsData, DerivedPlacementsData
class BIM_PT_representations(Panel):
@@ -68,6 +68,43 @@ class BIM_PT_representations(Panel):
row.operator("bim.remove_representation", icon="X", text="").representation_id = representation["id"]
class BIM_PT_connections(Panel):
bl_label = "IFC Connections"
bl_idname = "BIM_PT_connections"
bl_options = {"DEFAULT_CLOSED"}
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "object"
bl_parent_id = "BIM_PT_geometry_object"
@classmethod
def poll(cls, context):
if not context.active_object:
return False
if not IfcStore.get_element(context.active_object.BIMObjectProperties.ifc_definition_id):
return False
return IfcStore.get_file()
def draw(self, context):
if not ConnectionsData.is_loaded:
ConnectionsData.load()
layout = self.layout
props = context.active_object.BIMObjectProperties
if not ConnectionsData.data["connections"]:
layout.label(text="No connections found")
for connection in ConnectionsData.data["connections"]:
row = self.layout.row(align=True)
row.label(text=connection["Name"], icon="SNAP_ON" if connection["is_relating"] else "SNAP_OFF")
row.label(text=connection["ConnectionType"])
op = row.operator("bim.select_connection", icon="RESTRICT_SELECT_OFF", text="")
op.connection = connection["id"]
op = row.operator("bim.remove_connection", icon="X", text="")
op.connection = connection["id"]
class BIM_PT_mesh(Panel):
bl_label = "IFC Representation"
bl_idname = "BIM_PT_mesh"
@@ -140,3 +140,11 @@ def remove_representation(ifc, geometry, obj=None, representation=None):
geometry.replace_object_with_empty(obj)
ifc.run("geometry.unassign_representation", product=element, representation=representation)
ifc.run("geometry.remove_representation", representation=representation)
def select_connection(geometry, connection=None):
geometry.select_connection(connection)
def remove_connection(geometry, connection=None):
geometry.remove_connection(connection)
+5 -2
View File
@@ -237,11 +237,13 @@ class Geometry:
def link(cls, element, obj): pass
def record_object_materials(cls, obj): pass
def record_object_position(cls, obj): pass
def remove_connection(cls, connection): pass
def rename_object(cls, obj, name): pass
def replace_object_with_empty(cls, obj): pass
def resolve_mapped_representation(cls, representation): pass
def run_geometry_update_representation(cls, obj=None): pass
def run_style_add_style(cls, obj=None): pass
def select_connection(cls, connection): pass
def should_force_faceted_brep(cls): pass
def should_force_triangulation(cls): pass
def should_generate_uvs(cls, obj): pass
@@ -428,7 +430,8 @@ class Resource:
def expand_resource(cls, resource): pass
def contract_resource(cls, resource): pass
def import_resources(cls, file_path): pass
@interface
class Root:
def add_dynamic_opening_voids(cls, element, obj): pass
@@ -483,7 +486,7 @@ class Sequence:
def disable_editing_task(cls): pass
def get_task_time_attributes(cls): pass
def load_task_resources(cls,resources): pass
def load_resources(cls): pass
def load_resources(cls): pass
def get_task_inputs(cls, task): pass
def load_task_inputs(cls, inputs): pass
def load_task_outputs(cls, outputs): pass
@@ -261,6 +261,10 @@ class Geometry(blenderbim.core.tool.Geometry):
obj.BIMObjectProperties.location_checksum = repr(np.array(obj.matrix_world.translation).tobytes())
obj.BIMObjectProperties.rotation_checksum = repr(np.array(obj.matrix_world.to_3x3()).tobytes())
@classmethod
def remove_connection(cls, connection):
tool.Ifc.get().remove(connection)
@classmethod
def rename_object(cls, obj, name):
obj.name = name
@@ -293,6 +297,15 @@ class Geometry(blenderbim.core.tool.Geometry):
def run_style_add_style(cls, obj=None):
return blenderbim.core.style.add_style(tool.Ifc, tool.Style, obj=obj)
@classmethod
def select_connection(cls, connection):
obj = tool.Ifc.get_object(connection.RelatingElement)
if obj:
obj.select_set(True)
obj = tool.Ifc.get_object(connection.RelatedElement)
if obj:
obj.select_set(True)
@classmethod
def should_force_faceted_brep(cls):
return bpy.context.scene.BIMGeometryProperties.should_force_faceted_brep
+12
View File
@@ -382,3 +382,15 @@ class TestRemoveRepresentation:
).should_be_called()
ifc.run("geometry.remove_representation", representation="representation").should_be_called()
subject.remove_representation(ifc, geometry, obj="obj", representation="representation")
class TestSelectConnection:
def test_run(self, geometry):
geometry.select_connection("connection").should_be_called()
subject.select_connection(geometry, connection="connection")
class TestRemoveConnection:
def test_run(self, geometry):
geometry.remove_connection("connection").should_be_called()
subject.remove_connection(geometry, connection="connection")
+33
View File
@@ -379,6 +379,17 @@ class TestRecordObjectPosition(NewFile):
assert obj.BIMObjectProperties.rotation_checksum == repr(np.array(obj.matrix_world.to_3x3()).tobytes())
class TestRemoveConnection(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
tool.Ifc().set(ifc)
element1 = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
element2 = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
rel = ifcopenshell.api.run("geometry.connect_path", ifc, relating_element=element1, related_element=element2)
subject.remove_connection(rel)
assert not tool.Ifc.get().by_type("IfcRelConnectsPathElements")
class TestRenameObject(NewFile):
def test_run(self):
obj = bpy.data.meshes.new("Mesh")
@@ -431,6 +442,28 @@ class TestRunStyleAddStyle(NewFile):
pass
class TestSelectConnection(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
tool.Ifc().set(ifc)
element1 = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
obj1 = bpy.data.objects.new("Object", None)
bpy.context.scene.collection.objects.link(obj1)
tool.Ifc.link(element1, obj1)
element2 = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
obj2 = bpy.data.objects.new("Object", None)
bpy.context.scene.collection.objects.link(obj2)
tool.Ifc.link(element2, obj2)
rel = ifcopenshell.api.run("geometry.connect_path", ifc, relating_element=element1, related_element=element2)
subject.select_connection(rel)
assert obj1 in bpy.context.selected_objects
assert obj2 in bpy.context.selected_objects
class TestShouldForceFacetedBrep(NewFile):
def test_run(self):
result = bpy.context.scene.BIMGeometryProperties.should_force_faceted_brep