Load spatial tree after new / open project

This commit is contained in:
Dion Moult
2024-06-05 15:47:55 +10:00
parent 18b68353b1
commit 1565575e8b
12 changed files with 83 additions and 49 deletions
+1 -1
View File
@@ -142,7 +142,7 @@ classes = [
ui.BIM_PT_tabs, ui.BIM_PT_tabs,
# Project overview # Project overview
ui.BIM_PT_tab_project_info, ui.BIM_PT_tab_project_info,
ui.BIM_PT_tab_project_tree, ui.BIM_PT_tab_spatial_decomposition,
ui.BIM_PT_tab_project_setup, ui.BIM_PT_tab_project_setup,
ui.BIM_PT_tab_geometry, ui.BIM_PT_tab_geometry,
ui.BIM_PT_tab_stakeholders, ui.BIM_PT_tab_stakeholders,
@@ -37,6 +37,7 @@ import ifcopenshell.util.placement
import ifcopenshell.util.representation import ifcopenshell.util.representation
import ifcopenshell.util.shape import ifcopenshell.util.shape
import blenderbim.tool as tool import blenderbim.tool as tool
import blenderbim.core.spatial
import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper
from itertools import chain, accumulate from itertools import chain, accumulate
from blenderbim.bim.ifc import IfcStore, IFC_CONNECTED_TYPE from blenderbim.bim.ifc import IfcStore, IFC_CONNECTED_TYPE
@@ -301,6 +302,7 @@ class IfcImporter:
self.setup_viewport_camera() self.setup_viewport_camera()
self.setup_arrays() self.setup_arrays()
self.profile_code("Setup arrays") self.profile_code("Setup arrays")
blenderbim.core.spatial.import_spatial_decomposition(tool.Spatial)
self.update_progress(100) self.update_progress(100)
bpy.context.window_manager.progress_end() bpy.context.window_manager.progress_end()
@@ -36,6 +36,7 @@ import blenderbim.tool as tool
import blenderbim.core.project as core import blenderbim.core.project as core
import blenderbim.core.context import blenderbim.core.context
import blenderbim.core.owner import blenderbim.core.owner
import blenderbim.core.spatial
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.ui import IFCFileSelector from blenderbim.bim.ui import IFCFileSelector
from blenderbim.bim import import_ifc from blenderbim.bim import import_ifc
@@ -122,6 +123,7 @@ class CreateProject(bpy.types.Operator):
for mat in bpy.data.materials: for mat in bpy.data.materials:
bpy.data.materials.remove(mat) bpy.data.materials.remove(mat)
core.create_project(tool.Ifc, tool.Project, schema=props.export_schema, template=template) core.create_project(tool.Ifc, tool.Project, schema=props.export_schema, template=template)
blenderbim.core.spatial.import_spatial_decomposition(tool.Spatial)
tool.Blender.register_toolbar() tool.Blender.register_toolbar()
def rollback(self, data): def rollback(self, data):
@@ -30,7 +30,7 @@ classes = (
operator.EditContainerAttributes, operator.EditContainerAttributes,
operator.EnableEditingContainer, operator.EnableEditingContainer,
operator.ExpandContainer, operator.ExpandContainer,
operator.LoadContainerManager, operator.ImportSpatialDecomposition,
operator.ReferenceStructure, operator.ReferenceStructure,
operator.RemoveContainer, operator.RemoveContainer,
operator.SelectContainer, operator.SelectContainer,
@@ -42,12 +42,12 @@ classes = (
prop.BIMSpatialProperties, prop.BIMSpatialProperties,
prop.BIMObjectSpatialProperties, prop.BIMObjectSpatialProperties,
prop.BIMContainer, prop.BIMContainer,
prop.BIMProjectTreeProperties, prop.BIMSpatialDecompositionProperties,
ui.BIM_PT_spatial, ui.BIM_PT_spatial,
ui.BIM_UL_containers, ui.BIM_UL_containers,
ui.BIM_UL_containers_manager, ui.BIM_UL_containers_manager,
ui.BIM_UL_elements, ui.BIM_UL_elements,
ui.BIM_PT_project_tree, ui.BIM_PT_spatial_decomposition,
workspace.Hotkey, workspace.Hotkey,
) )
@@ -57,7 +57,7 @@ def register():
bpy.utils.register_tool(workspace.SpatialTool, after={"bim.annotation_tool"}, separator=False, group=False) bpy.utils.register_tool(workspace.SpatialTool, after={"bim.annotation_tool"}, separator=False, group=False)
bpy.types.Scene.BIMSpatialProperties = bpy.props.PointerProperty(type=prop.BIMSpatialProperties) bpy.types.Scene.BIMSpatialProperties = bpy.props.PointerProperty(type=prop.BIMSpatialProperties)
bpy.types.Object.BIMObjectSpatialProperties = bpy.props.PointerProperty(type=prop.BIMObjectSpatialProperties) bpy.types.Object.BIMObjectSpatialProperties = bpy.props.PointerProperty(type=prop.BIMObjectSpatialProperties)
bpy.types.Scene.BIMProjectTreeProperties = bpy.props.PointerProperty(type=prop.BIMProjectTreeProperties) bpy.types.Scene.BIMSpatialDecompositionProperties = bpy.props.PointerProperty(type=prop.BIMSpatialDecompositionProperties)
def unregister(): def unregister():
@@ -65,4 +65,4 @@ def unregister():
bpy.utils.unregister_tool(workspace.SpatialTool) bpy.utils.unregister_tool(workspace.SpatialTool)
del bpy.types.Scene.BIMSpatialProperties del bpy.types.Scene.BIMSpatialProperties
del bpy.types.Object.BIMObjectSpatialProperties del bpy.types.Object.BIMObjectSpatialProperties
del bpy.types.Scene.BIMProjectTreeProperties del bpy.types.Scene.BIMSpatialDecompositionProperties
@@ -23,7 +23,7 @@ import ifcopenshell.util.element
def refresh(): def refresh():
SpatialData.is_loaded = False SpatialData.is_loaded = False
ProjectTreeData.is_loaded = False SpatialDecompositionData.is_loaded = False
class SpatialData: class SpatialData:
@@ -84,7 +84,7 @@ class SpatialData:
return bool(getattr(tool.Ifc.get_entity(bpy.context.active_object), "ContainedInStructure", False)) return bool(getattr(tool.Ifc.get_entity(bpy.context.active_object), "ContainedInStructure", False))
class ProjectTreeData: class SpatialDecompositionData:
data = {} data = {}
is_loaded = False is_loaded = False
@@ -98,7 +98,7 @@ class ProjectTreeData:
@classmethod @classmethod
def subelement_class(cls): def subelement_class(cls):
results = [] results = []
props = bpy.context.scene.BIMProjectTreeProperties props = bpy.context.scene.BIMSpatialDecompositionProperties
if not (container := props.active_container): if not (container := props.active_container):
return results return results
container_class = tool.Ifc.get().by_id(container.ifc_definition_id).is_a() container_class = tool.Ifc.get().by_id(container.ifc_definition_id).is_a()
@@ -175,13 +175,13 @@ class SelectProduct(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class LoadContainerManager(bpy.types.Operator): class ImportSpatialDecomposition(bpy.types.Operator):
bl_idname = "bim.load_container_manager" bl_idname = "bim.import_spatial_decomposition"
bl_label = "Load Container Manager" bl_label = "Load Container Manager"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context): def execute(self, context):
core.load_container_manager(tool.Spatial) core.import_spatial_decomposition(tool.Spatial)
return {"FINISHED"} return {"FINISHED"}
@@ -18,7 +18,7 @@
import bpy import bpy
from blenderbim.bim.prop import StrProperty, Attribute from blenderbim.bim.prop import StrProperty, Attribute
from blenderbim.bim.module.spatial.data import ProjectTreeData from blenderbim.bim.module.spatial.data import SpatialDecompositionData
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
from bpy.props import ( from bpy.props import (
PointerProperty, PointerProperty,
@@ -35,9 +35,9 @@ import ifcopenshell
def get_subelement_class(self, context): def get_subelement_class(self, context):
if not ProjectTreeData.is_loaded: if not SpatialDecompositionData.is_loaded:
ProjectTreeData.load() SpatialDecompositionData.load()
return ProjectTreeData.data["subelement_class"] return SpatialDecompositionData.data["subelement_class"]
def update_elevation(self, context): def update_elevation(self, context):
@@ -55,7 +55,7 @@ def update_name(self, context):
def update_active_container_index(self, context): def update_active_container_index(self, context):
ProjectTreeData.data["subelement_class"] = ProjectTreeData.subelement_class() SpatialDecompositionData.data["subelement_class"] = SpatialDecompositionData.subelement_class()
tool.Spatial.load_contained_elements() tool.Spatial.load_contained_elements()
@@ -122,7 +122,7 @@ class Element(PropertyGroup):
total: IntProperty(name="Total") total: IntProperty(name="Total")
class BIMProjectTreeProperties(PropertyGroup): class BIMSpatialDecompositionProperties(PropertyGroup):
containers: CollectionProperty(name="Containers", type=BIMContainer) containers: CollectionProperty(name="Containers", type=BIMContainer)
contracted_containers: StringProperty(name="Contracted containers", default="[]") contracted_containers: StringProperty(name="Contracted containers", default="[]")
expanded_containers: StringProperty(name="Expanded containers", default="[]") expanded_containers: StringProperty(name="Expanded containers", default="[]")
@@ -17,7 +17,7 @@
# 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/>.
from bpy.types import Panel, UIList from bpy.types import Panel, UIList
from blenderbim.bim.module.spatial.data import SpatialData, ProjectTreeData from blenderbim.bim.module.spatial.data import SpatialData, SpatialDecompositionData
import blenderbim.tool as tool import blenderbim.tool as tool
@@ -91,13 +91,13 @@ class BIM_UL_containers(UIList):
) )
class BIM_PT_project_tree(Panel): class BIM_PT_spatial_decomposition(Panel):
bl_label = "Project Tree" bl_label = "Spatial Decomposition"
bl_idname = "BIM_PT_project_tree" bl_idname = "BIM_PT_spatial_decomposition"
bl_space_type = "PROPERTIES" bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW" bl_region_type = "WINDOW"
bl_context = "scene" bl_context = "scene"
bl_parent_id = "BIM_PT_tab_project_tree" bl_parent_id = "BIM_PT_tab_spatial_decomposition"
bl_options = {"HIDE_HEADER"} bl_options = {"HIDE_HEADER"}
@classmethod @classmethod
@@ -105,9 +105,9 @@ class BIM_PT_project_tree(Panel):
return tool.Ifc.get() return tool.Ifc.get()
def draw(self, context): def draw(self, context):
if not ProjectTreeData.is_loaded: if not SpatialDecompositionData.is_loaded:
ProjectTreeData.load() SpatialDecompositionData.load()
self.props = context.scene.BIMProjectTreeProperties self.props = context.scene.BIMSpatialDecompositionProperties
if self.props.active_container: if self.props.active_container:
row = self.layout.row(align=True) row = self.layout.row(align=True)
@@ -115,7 +115,7 @@ class BIM_PT_project_tree(Panel):
text=f"Active: {self.props.active_container.name}", text=f"Active: {self.props.active_container.name}",
icon="OUTLINER_COLLECTION", icon="OUTLINER_COLLECTION",
) )
row.operator("bim.load_container_manager", icon="FILE_REFRESH", text="") row.operator("bim.import_spatial_decomposition", icon="FILE_REFRESH", text="")
if self.props.active_container.ifc_class != "IfcProject": if self.props.active_container.ifc_class != "IfcProject":
row = self.layout.row(align=True) row = self.layout.row(align=True)
@@ -132,7 +132,7 @@ class BIM_PT_project_tree(Panel):
else: else:
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.label(text="Warning: No Active Container", icon="ERROR") row.label(text="Warning: No Active Container", icon="ERROR")
row.operator("bim.load_container_manager", icon="FILE_REFRESH", text="") row.operator("bim.import_spatial_decomposition", icon="FILE_REFRESH", text="")
self.layout.template_list( self.layout.template_list(
"BIM_UL_containers_manager", "BIM_UL_containers_manager",
+3 -3
View File
@@ -440,15 +440,15 @@ class BIM_PT_tab_project_info(Panel):
pass pass
class BIM_PT_tab_project_tree(Panel): class BIM_PT_tab_spatial_decomposition(Panel):
bl_label = "Project Tree" bl_label = "Spatial Decomposition"
bl_space_type = "PROPERTIES" bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW" bl_region_type = "WINDOW"
bl_context = "scene" bl_context = "scene"
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return tool.Blender.is_tab(context, "PROJECT") return tool.Blender.is_tab(context, "PROJECT") and tool.Ifc.get()
def draw(self, context): def draw(self, context):
pass pass
+6 -6
View File
@@ -120,28 +120,28 @@ def select_product(spatial, product):
spatial.select_products([product]) spatial.select_products([product])
def load_container_manager(spatial): def import_spatial_decomposition(spatial):
spatial.load_container_manager() spatial.import_spatial_decomposition()
def edit_container_attributes(spatial, entity=None): def edit_container_attributes(spatial, entity=None):
spatial.edit_container_attributes(entity) spatial.edit_container_attributes(entity)
spatial.load_container_manager() spatial.import_spatial_decomposition()
def contract_container(spatial, container=None): def contract_container(spatial, container=None):
spatial.contract_container(container) spatial.contract_container(container)
spatial.load_container_manager() spatial.import_spatial_decomposition()
def expand_container(spatial, container=None): def expand_container(spatial, container=None):
spatial.expand_container(container) spatial.expand_container(container)
spatial.load_container_manager() spatial.import_spatial_decomposition()
def delete_container(ifc, spatial, geometry, container=None): def delete_container(ifc, spatial, geometry, container=None):
geometry.delete_ifc_object(ifc.get_object(container)) geometry.delete_ifc_object(ifc.get_object(container))
spatial.load_container_manager() spatial.import_spatial_decomposition()
def select_decomposed_elements(spatial): def select_decomposed_elements(spatial):
+1 -1
View File
@@ -848,7 +848,7 @@ class Spatial:
def get_selected_product_types(cls): pass def get_selected_product_types(cls): pass
def get_selected_products(cls): pass def get_selected_products(cls): pass
def import_containers(cls, parent=None): pass def import_containers(cls, parent=None): pass
def load_container_manager(cls): pass def import_spatial_decomposition(cls): pass
def run_root_copy_class(cls, obj=None): pass def run_root_copy_class(cls, obj=None): pass
def run_spatial_assign_container(cls, structure_obj=None, element_obj=None): pass def run_spatial_assign_container(cls, structure_obj=None, element_obj=None): pass
def select_object(cls, obj): pass def select_object(cls, obj): pass
+41 -11
View File
@@ -208,7 +208,7 @@ class Spatial(blenderbim.core.tool.Spatial):
@classmethod @classmethod
def load_contained_elements(cls): def load_contained_elements(cls):
props = bpy.context.scene.BIMProjectTreeProperties props = bpy.context.scene.BIMSpatialDecompositionProperties
props.elements.clear() props.elements.clear()
if not (container := props.active_container): if not (container := props.active_container):
return return
@@ -241,17 +241,17 @@ class Spatial(blenderbim.core.tool.Spatial):
props.total_elements = total_elements props.total_elements = total_elements
@classmethod @classmethod
def load_container_manager(cls): def import_spatial_decomposition(cls):
props = bpy.context.scene.BIMProjectTreeProperties props = bpy.context.scene.BIMSpatialDecompositionProperties
previous_container_index = props.active_container_index previous_container_index = props.active_container_index
props.containers.clear() props.containers.clear()
cls.contracted_containers = json.loads(props.contracted_containers) cls.contracted_containers = json.loads(props.contracted_containers)
cls.import_spatial_structure(tool.Ifc.get().by_type("IfcProject")[0], 0) cls.import_spatial_element(tool.Ifc.get().by_type("IfcProject")[0], 0)
props.active_container_index = min(previous_container_index, len(props.containers) - 1) props.active_container_index = min(previous_container_index, len(props.containers) - 1)
@classmethod @classmethod
def import_spatial_structure(cls, element, level_index): def import_spatial_element(cls, element, level_index):
props = bpy.context.scene.BIMProjectTreeProperties props = bpy.context.scene.BIMSpatialDecompositionProperties
new = props.containers.add() new = props.containers.add()
new.ifc_class = element.is_a() new.ifc_class = element.is_a()
new.name = element.Name or "Unnamed" new.name = element.Name or "Unnamed"
@@ -266,14 +266,14 @@ class Spatial(blenderbim.core.tool.Spatial):
new.ifc_definition_id = element.id() new.ifc_definition_id = element.id()
if new.is_expanded: if new.is_expanded:
for child in children or []: for child in children or []:
cls.import_spatial_structure(child, level_index + 1) cls.import_spatial_element(child, level_index + 1)
@classmethod @classmethod
def edit_container_attributes(cls, entity): def edit_container_attributes(cls, entity):
# TODO # TODO
obj = tool.Ifc.get_object(entity) obj = tool.Ifc.get_object(entity)
blenderbim.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj) blenderbim.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj)
name = bpy.context.scene.BIMProjectTreeProperties.container_name name = bpy.context.scene.BIMSpatialDecompositionProperties.container_name
if name != entity.Name: if name != entity.Name:
cls.edit_container_name(entity, name) cls.edit_container_name(entity, name)
@@ -283,21 +283,21 @@ class Spatial(blenderbim.core.tool.Spatial):
@classmethod @classmethod
def get_active_container(cls): def get_active_container(cls):
props = bpy.context.scene.BIMProjectTreeProperties props = bpy.context.scene.BIMSpatialDecompositionProperties
if props.active_container_index < len(props.containers): if props.active_container_index < len(props.containers):
container = tool.Ifc.get().by_id(props.containers[props.active_container_index].ifc_definition_id) container = tool.Ifc.get().by_id(props.containers[props.active_container_index].ifc_definition_id)
return container return container
@classmethod @classmethod
def contract_container(cls, container): def contract_container(cls, container):
props = bpy.context.scene.BIMProjectTreeProperties props = bpy.context.scene.BIMSpatialDecompositionProperties
contracted_containers = json.loads(props.contracted_containers) contracted_containers = json.loads(props.contracted_containers)
contracted_containers.append(container.id()) contracted_containers.append(container.id())
props.contracted_containers = json.dumps(contracted_containers) props.contracted_containers = json.dumps(contracted_containers)
@classmethod @classmethod
def expand_container(cls, container): def expand_container(cls, container):
props = bpy.context.scene.BIMProjectTreeProperties props = bpy.context.scene.BIMSpatialDecompositionProperties
contracted_containers = json.loads(props.contracted_containers) contracted_containers = json.loads(props.contracted_containers)
contracted_containers.remove(container.id()) contracted_containers.remove(container.id())
props.contracted_containers = json.dumps(contracted_containers) props.contracted_containers = json.dumps(contracted_containers)
@@ -322,6 +322,36 @@ class Spatial(blenderbim.core.tool.Spatial):
space_polygon = shapely.force_3d(polygon) space_polygon = shapely.force_3d(polygon)
return space_polygon return space_polygon
@classmethod
def debug_shape(cls, foo):
coords = [(p[0], p[1], 0) for p in foo.exterior.coords]
mesh = bpy.data.meshes.new(name="NewMesh")
bm = bmesh.new()
for coord in coords:
bm.verts.new(coord)
bm.verts.ensure_lookup_table()
bm.faces.new(bm.verts)
bm.to_mesh(mesh)
bm.free()
obj = bpy.data.objects.new("NewObject", mesh)
bpy.context.collection.objects.link(obj)
bpy.context.view_layer.update()
@classmethod
def debug_line(cls, start, end):
coords = [start, end]
mesh = bpy.data.meshes.new(name="NewMesh")
bm = bmesh.new()
for coord in coords:
bm.verts.new(coord)
bm.verts.ensure_lookup_table()
bm.edges.new(bm.verts)
bm.to_mesh(mesh)
bm.free()
obj = bpy.data.objects.new("NewLine", mesh)
bpy.context.collection.objects.link(obj)
bpy.context.view_layer.update()
@classmethod @classmethod
def get_boundary_lines_from_context_visible_objects(cls): def get_boundary_lines_from_context_visible_objects(cls):
calculation_rl = bpy.context.scene.BIMModelProperties.rl3 calculation_rl = bpy.context.scene.BIMModelProperties.rl3