mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-15 13:48:09 +00:00
See #1848. Refactor boundary data class.
This commit is contained in:
@@ -0,0 +1,46 @@
|
|||||||
|
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||||
|
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
|
||||||
|
#
|
||||||
|
# This file is part of BlenderBIM Add-on.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on 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 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on 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 BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import bpy
|
||||||
|
import ifcopenshell
|
||||||
|
import ifcopenshell.util.schema
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
|
||||||
|
|
||||||
|
def refresh():
|
||||||
|
SpaceBoundariesData.is_loaded = False
|
||||||
|
|
||||||
|
|
||||||
|
class SpaceBoundariesData:
|
||||||
|
data = {}
|
||||||
|
is_loaded = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(cls):
|
||||||
|
cls.data = {"boundaries": cls.boundaries()}
|
||||||
|
cls.is_loaded = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def boundaries(cls):
|
||||||
|
results = []
|
||||||
|
element = tool.Ifc.get_entity(bpy.context.active_object)
|
||||||
|
for rel in element.BoundedBy or []:
|
||||||
|
description = f"{rel.id()} > {rel.RelatedBuildingElement.is_a()}/{rel.RelatedBuildingElement.Name}"
|
||||||
|
results.append({"id": rel.id(), "description": description})
|
||||||
|
return results
|
||||||
@@ -21,7 +21,6 @@ import logging
|
|||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from ifcopenshell.api.boundary.data import Data
|
|
||||||
import blenderbim.bim.import_ifc as import_ifc
|
import blenderbim.bim.import_ifc as import_ifc
|
||||||
|
|
||||||
|
|
||||||
@@ -49,7 +48,7 @@ class Loader:
|
|||||||
if not boundary.ConnectionGeometry:
|
if not boundary.ConnectionGeometry:
|
||||||
return None
|
return None
|
||||||
surface = boundary.ConnectionGeometry.SurfaceOnRelatingElement
|
surface = boundary.ConnectionGeometry.SurfaceOnRelatingElement
|
||||||
# workaround for invalid geometry provided by Revit. See https://github.com/IfcOpenShell/IfcOpenShell/issues/635#issuecomment-770366838
|
# Workaround for invalid geometry provided by Revit. See https://github.com/Autodesk/revit-ifc/issues/270
|
||||||
if surface.is_a("IfcCurveBoundedPlane") and not getattr(surface, "InnerBoundaries", None):
|
if surface.is_a("IfcCurveBoundedPlane") and not getattr(surface, "InnerBoundaries", None):
|
||||||
surface.InnerBoundaries = ()
|
surface.InnerBoundaries = ()
|
||||||
shape = ifcopenshell.geom.create_shape(self.settings, surface)
|
shape = ifcopenshell.geom.create_shape(self.settings, surface)
|
||||||
@@ -69,8 +68,7 @@ class Loader:
|
|||||||
self.ifc_importer = import_ifc.IfcImporter(ifc_import_settings)
|
self.ifc_importer = import_ifc.IfcImporter(ifc_import_settings)
|
||||||
self.ifc_importer.file = self.ifc_file
|
self.ifc_importer.file = self.ifc_file
|
||||||
|
|
||||||
def load_boundary(self, boundary_id, blender_space):
|
def load_boundary(self, boundary, blender_space):
|
||||||
boundary = self.ifc_file.by_id(boundary_id)
|
|
||||||
obj = tool.Ifc.get_object(boundary)
|
obj = tool.Ifc.get_object(boundary)
|
||||||
if obj:
|
if obj:
|
||||||
return obj
|
return obj
|
||||||
@@ -90,12 +88,8 @@ class LoadProjectSpaceBoundaries(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
loader = Loader()
|
loader = Loader()
|
||||||
if not Data.is_loaded:
|
for rel in tool.Ifc.get().by_type("IfcRelSpaceBoundary"):
|
||||||
Data.load(tool.Ifc.get())
|
loader.load_boundary(rel, tool.Ifc.get_object(rel.RelatingSpace))
|
||||||
for space_id, boundaries_id in Data.spaces.items():
|
|
||||||
blender_space = tool.Ifc.get_object(tool.Ifc.get().by_id(space_id))
|
|
||||||
for boundary_id in boundaries_id:
|
|
||||||
loader.load_boundary(boundary_id, blender_space)
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -107,10 +101,9 @@ class LoadBoundary(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
loader = Loader()
|
loader = Loader()
|
||||||
blender_space = context.active_object
|
|
||||||
for obj in context.visible_objects:
|
for obj in context.visible_objects:
|
||||||
obj.select_set(False)
|
obj.select_set(False)
|
||||||
obj = loader.load_boundary(self.boundary_id, blender_space)
|
obj = loader.load_boundary(tool.Ifc.get().by_id(self.boundary_id), context.active_object)
|
||||||
obj.select_set(True)
|
obj.select_set(True)
|
||||||
bpy.context.view_layer.objects.active = obj
|
bpy.context.view_layer.objects.active = obj
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
@@ -122,13 +115,10 @@ class LoadSpaceBoundaries(bpy.types.Operator):
|
|||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
blender_space = context.active_object
|
|
||||||
oprops = context.active_object.BIMObjectProperties
|
|
||||||
loader = Loader()
|
loader = Loader()
|
||||||
if not Data.is_loaded:
|
element = tool.Ifc.get_entity(context.active_object)
|
||||||
Data.load(tool.Ifc.get())
|
for rel in element.BoundedBy or []:
|
||||||
for boundary_id in Data.spaces.get(oprops.ifc_definition_id, []):
|
loader.load_boundary(rel, context.active_object)
|
||||||
loader.load_boundary(boundary_id, blender_space)
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -140,10 +130,8 @@ class SelectProjectBoundaries(bpy.types.Operator):
|
|||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
for obj in context.visible_objects:
|
for obj in context.visible_objects:
|
||||||
obj.select_set(False)
|
obj.select_set(False)
|
||||||
ifc_file = tool.Ifc.get()
|
for rel in tool.Ifc.get().by_type("IfcRelSpaceBoundary"):
|
||||||
for boundary_id in Data.boundaries:
|
obj = tool.Ifc.get_object(rel)
|
||||||
boundary = ifc_file.by_id(boundary_id)
|
|
||||||
obj = tool.Ifc.get_object(boundary)
|
|
||||||
if obj:
|
if obj:
|
||||||
obj.select_set(True)
|
obj.select_set(True)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import blenderbim.bim.helper
|
|||||||
from bpy.types import Panel, UIList
|
from bpy.types import Panel, UIList
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
from ifcopenshell.api.boundary.data import Data
|
from blenderbim.bim.module.boundary.data import SpaceBoundariesData
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_SceneBoundaries(Panel):
|
class BIM_PT_SceneBoundaries(Panel):
|
||||||
@@ -129,28 +129,22 @@ class BIM_PT_SpaceBoundaries(Panel):
|
|||||||
return False
|
return False
|
||||||
if not IfcStore.get_element(props.ifc_definition_id):
|
if not IfcStore.get_element(props.ifc_definition_id):
|
||||||
return False
|
return False
|
||||||
valid_classes = ("IfcSpace", "IfcExternalSpatialElement")
|
element = tool.Ifc.get_entity(context.active_object)
|
||||||
entity = IfcStore.get_file().by_id(props.ifc_definition_id)
|
for ifc_class in ("IfcSpace", "IfcExternalSpatialElement"):
|
||||||
for ifc_class in valid_classes:
|
if element.is_a(ifc_class):
|
||||||
if entity.is_a(ifc_class):
|
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
|
if not SpaceBoundariesData.is_loaded:
|
||||||
|
SpaceBoundariesData.load()
|
||||||
|
|
||||||
self.props = context.active_object.BIMObjectProperties
|
self.props = context.active_object.BIMObjectProperties
|
||||||
self.ifc_file = tool.Ifc.get()
|
self.ifc_file = tool.Ifc.get()
|
||||||
row = self.layout.row()
|
row = self.layout.row()
|
||||||
row.operator("bim.load_space_boundaries")
|
row.operator("bim.load_space_boundaries")
|
||||||
if not Data.is_loaded:
|
for boundary in SpaceBoundariesData.data["boundaries"]:
|
||||||
Data.load(self.ifc_file)
|
|
||||||
for boundary_id in Data.spaces.get(self.props.ifc_definition_id, []):
|
|
||||||
boundary_data = Data.boundaries[boundary_id]
|
|
||||||
building_element = self.ifc_file.by_id(boundary_data["RelatedBuildingElement"])
|
|
||||||
row = self.layout.row()
|
row = self.layout.row()
|
||||||
if building_element:
|
row.label(text=boundary["description"], icon="GHOST_ENABLED")
|
||||||
bld_el_description = f"{building_element.is_a()}/{building_element.Name}"
|
|
||||||
else:
|
|
||||||
bld_el_description = None
|
|
||||||
row.label(text=f"{boundary_id} > {bld_el_description}", icon="GHOST_ENABLED")
|
|
||||||
op = row.operator("bim.load_boundary", text="", icon="RESTRICT_SELECT_OFF")
|
op = row.operator("bim.load_boundary", text="", icon="RESTRICT_SELECT_OFF")
|
||||||
op.boundary_id = boundary_id
|
op.boundary_id = boundary["id"]
|
||||||
|
|||||||
@@ -261,4 +261,4 @@ def sync_references(ifc, collector, drawing_tool, drawing=None):
|
|||||||
drawing_tool.sync_object_representation(reference_obj)
|
drawing_tool.sync_object_representation(reference_obj)
|
||||||
|
|
||||||
def select_assigned_product(drawing):
|
def select_assigned_product(drawing):
|
||||||
drawing.select_assigned_product()
|
drawing.select_assigned_product()
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Scenario: Execute IFC Patch
|
|||||||
And I set "scene.BIMPatchProperties.ifc_patch_input" to "{cwd}/test/files/basic.ifc"
|
And I set "scene.BIMPatchProperties.ifc_patch_input" to "{cwd}/test/files/basic.ifc"
|
||||||
And I set "scene.BIMPatchProperties.ifc_patch_output" to "{cwd}/test/files/basic-patched.ifc"
|
And I set "scene.BIMPatchProperties.ifc_patch_output" to "{cwd}/test/files/basic-patched.ifc"
|
||||||
And I set "scene.BIMPatchProperties.ifc_patch_args" to "[123454321,0,0,0]"
|
And I set "scene.BIMPatchProperties.ifc_patch_args" to "[123454321,0,0,0]"
|
||||||
When I press "bim.execute_ifc_patch"
|
When I press "bim.execute_ifc_patch(use_json_for_args=True)"
|
||||||
Then the file "{cwd}/test/files/basic-patched.ifc" should contain "123454321"
|
Then the file "{cwd}/test/files/basic-patched.ifc" should contain "123454321"
|
||||||
|
|
||||||
Scenario: Run migrate patch
|
Scenario: Run migrate patch
|
||||||
|
|||||||
@@ -33,7 +33,9 @@ class TestImplementsTool(NewFile):
|
|||||||
|
|
||||||
class TestAddSchemaIdentifier(NewFile):
|
class TestAddSchemaIdentifier(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
subject.add_schema_identifier(TestLoadExpress().test_run())
|
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
schema = subject.load_express(os.path.join(cwd, "..", "files", "test.exp"))
|
||||||
|
subject.add_schema_identifier(schema)
|
||||||
assert IfcStore.schema_identifiers[-1] == "IFCROGUE"
|
assert IfcStore.schema_identifiers[-1] == "IFCROGUE"
|
||||||
|
|
||||||
|
|
||||||
@@ -42,7 +44,6 @@ class TestLoadExpress(NewFile):
|
|||||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||||
schema = subject.load_express(os.path.join(cwd, "..", "files", "test.exp"))
|
schema = subject.load_express(os.path.join(cwd, "..", "files", "test.exp"))
|
||||||
assert schema.schema_name == "IFCROGUE"
|
assert schema.schema_name == "IFCROGUE"
|
||||||
return schema
|
|
||||||
|
|
||||||
|
|
||||||
class TestPurgeHdf5Cache(NewFile):
|
class TestPurgeHdf5Cache(NewFile):
|
||||||
|
|||||||
Reference in New Issue
Block a user