mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
Optimise object placement change checking, so medium sized project exports are 5 seconds faster at minimum, but can be much higher since false positives are culled.
This commit is contained in:
@@ -132,6 +132,8 @@ class IfcExporter:
|
||||
return results
|
||||
|
||||
def sync_object_placement(self, obj):
|
||||
if not self.has_object_moved(obj):
|
||||
return
|
||||
blender_matrix = np.array(obj.matrix_world)
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
if (obj.scale - Vector((1.0, 1.0, 1.0))).length > 1e-4:
|
||||
@@ -141,24 +143,19 @@ class IfcExporter:
|
||||
return self.sync_grid_axis_object_placement(obj, element)
|
||||
if not hasattr(element, "ObjectPlacement"):
|
||||
return
|
||||
ifc_matrix = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement)
|
||||
ifc_matrix[0][3] *= self.unit_scale
|
||||
ifc_matrix[1][3] *= self.unit_scale
|
||||
ifc_matrix[2][3] *= self.unit_scale
|
||||
blenderbim.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj)
|
||||
return element
|
||||
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
if props.has_blender_offset and obj.BIMObjectProperties.blender_offset_type == "OBJECT_PLACEMENT":
|
||||
ifc_matrix = ifcopenshell.util.geolocation.global2local(
|
||||
ifc_matrix,
|
||||
float(props.blender_eastings) * self.unit_scale,
|
||||
float(props.blender_northings) * self.unit_scale,
|
||||
float(props.blender_orthogonal_height) * self.unit_scale,
|
||||
float(props.blender_x_axis_abscissa),
|
||||
float(props.blender_x_axis_ordinate),
|
||||
)
|
||||
if not np.allclose(ifc_matrix, blender_matrix, atol=0.0001):
|
||||
blenderbim.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj)
|
||||
return element
|
||||
def has_object_moved(self, obj):
|
||||
if not obj.BIMObjectProperties.location_checksum:
|
||||
return True # Let's be conservative
|
||||
loc_check = np.frombuffer(eval(obj.BIMObjectProperties.location_checksum))
|
||||
rot_check = np.frombuffer(eval(obj.BIMObjectProperties.rotation_checksum))
|
||||
loc_real = np.array(obj.matrix_world.translation).flatten()
|
||||
rot_real = np.array(obj.matrix_world.to_3x3()).flatten()
|
||||
if np.allclose(loc_check, loc_real, atol=1e-4) and np.allclose(rot_check, rot_real, atol=1e-2):
|
||||
return False
|
||||
return True
|
||||
|
||||
def sync_grid_axis_object_placement(self, obj, element):
|
||||
grid = (element.PartOfU or element.PartOfV or element.PartOfW)[0]
|
||||
|
||||
@@ -31,6 +31,7 @@ import ifcopenshell.util.unit
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.selector
|
||||
import ifcopenshell.util.geolocation
|
||||
import blenderbim.tool as tool
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.module.drawing.prop import get_diagram_scales
|
||||
|
||||
@@ -509,7 +510,7 @@ class IfcImporter:
|
||||
mesh = self.create_mesh(axis, shape)
|
||||
obj = bpy.data.objects.new(f"IfcGridAxis/{axis.AxisTag}", mesh)
|
||||
self.link_element(axis, obj)
|
||||
obj.matrix_world = grid_obj.matrix_world
|
||||
self.set_matrix_world(obj, grid_obj.matrix_world)
|
||||
grid_collection.objects.link(obj)
|
||||
|
||||
def create_type_products(self):
|
||||
@@ -700,7 +701,7 @@ class IfcImporter:
|
||||
mesh.from_pydata([mathutils.Vector(vertex) * self.unit_scale], [], [])
|
||||
|
||||
obj = bpy.data.objects.new("{}/{}".format(product.is_a(), product.Name), mesh)
|
||||
obj.matrix_world = self.apply_blender_offset_to_matrix_world(obj, placement_matrix)
|
||||
self.set_matrix_world(obj, self.apply_blender_offset_to_matrix_world(obj, placement_matrix))
|
||||
self.link_element(product, obj)
|
||||
|
||||
def get_pointcloud_representation(self, product):
|
||||
@@ -759,7 +760,7 @@ class IfcImporter:
|
||||
mesh.from_pydata(vertex_list, [], [])
|
||||
|
||||
obj = bpy.data.objects.new("{}/{}".format(product.is_a(), product.Name), mesh)
|
||||
obj.matrix_world = self.apply_blender_offset_to_matrix_world(obj, placement_matrix)
|
||||
self.set_matrix_world(obj, self.apply_blender_offset_to_matrix_world(obj, placement_matrix))
|
||||
self.link_element(product, obj)
|
||||
return product
|
||||
|
||||
@@ -826,13 +827,13 @@ class IfcImporter:
|
||||
mat = np.array(
|
||||
([m[0], m[3], m[6], m[9]], [m[1], m[4], m[7], m[10]], [m[2], m[5], m[8], m[11]], [0, 0, 0, 1])
|
||||
)
|
||||
obj.matrix_world = self.apply_blender_offset_to_matrix_world(obj, mat)
|
||||
self.set_matrix_world(obj, self.apply_blender_offset_to_matrix_world(obj, mat))
|
||||
self.material_creator.create(element, obj, mesh)
|
||||
elif mesh:
|
||||
obj.matrix_world = self.apply_blender_offset_to_matrix_world(obj, self.get_element_matrix(element))
|
||||
self.set_matrix_world(obj, self.apply_blender_offset_to_matrix_world(obj, self.get_element_matrix(element)))
|
||||
self.material_creator.create(element, obj, mesh)
|
||||
elif hasattr(element, "ObjectPlacement"):
|
||||
obj.matrix_world = self.apply_blender_offset_to_matrix_world(obj, self.get_element_matrix(element))
|
||||
self.set_matrix_world(obj, self.apply_blender_offset_to_matrix_world(obj, self.get_element_matrix(element)))
|
||||
|
||||
self.add_opening_relation(element, obj)
|
||||
|
||||
@@ -1518,6 +1519,10 @@ class IfcImporter:
|
||||
else:
|
||||
mesh.BIMMeshProperties.ifc_definition_id = int(geometry.id)
|
||||
|
||||
def set_matrix_world(self, obj, matrix_world):
|
||||
obj.matrix_world = matrix_world
|
||||
tool.Geometry.record_object_position(obj)
|
||||
|
||||
|
||||
class IfcImportSettings:
|
||||
def __init__(self):
|
||||
|
||||
@@ -318,9 +318,8 @@ class BIMObjectProperties(PropertyGroup):
|
||||
default="NONE",
|
||||
)
|
||||
is_reassigning_class: BoolProperty(name="Is Reassigning Class")
|
||||
global_ids: CollectionProperty(name="GlobalIds", type=GlobalId)
|
||||
psets: CollectionProperty(name="Psets", type=PsetQto)
|
||||
qtos: CollectionProperty(name="Qtos", type=PsetQto)
|
||||
location_checksum: StringProperty(name="Location Checksum")
|
||||
rotation_checksum: StringProperty(name="Rotation Checksum")
|
||||
|
||||
|
||||
class BIMMaterialProperties(PropertyGroup):
|
||||
|
||||
@@ -25,6 +25,7 @@ def edit_object_placement(ifc, geometry, surveyor, obj=None):
|
||||
geometry.clear_cache(element)
|
||||
geometry.clear_scale(obj)
|
||||
ifc.run("geometry.edit_object_placement", product=element, matrix=surveyor.get_absolute_matrix(obj))
|
||||
geometry.record_object_position(obj)
|
||||
|
||||
|
||||
def add_representation(
|
||||
|
||||
@@ -100,6 +100,7 @@ class Geometry:
|
||||
def is_mapped_representation(cls, representation): pass
|
||||
def is_type_product(cls, element): pass
|
||||
def link(cls, element, obj): pass
|
||||
def record_object_position(cls, obj): pass
|
||||
def rename_object(cls, obj, name): pass
|
||||
def replace_object_with_empty(cls, obj): pass
|
||||
def resolve_mapped_representation(cls, representation): pass
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
import bpy
|
||||
import logging
|
||||
import numpy as np
|
||||
import ifcopenshell
|
||||
import blenderbim.core.tool
|
||||
import blenderbim.core.style
|
||||
@@ -223,6 +224,12 @@ class Geometry(blenderbim.core.tool.Geometry):
|
||||
def link(cls, element, obj):
|
||||
obj.BIMMeshProperties.ifc_definition_id = element.id()
|
||||
|
||||
@classmethod
|
||||
def record_object_position(cls, obj):
|
||||
# These are recorded separately because they have different numerical tolerances
|
||||
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 rename_object(cls, obj, name):
|
||||
obj.name = name
|
||||
|
||||
@@ -28,6 +28,7 @@ class TestEditObjectPlacement:
|
||||
geometry.clear_scale("obj").should_be_called()
|
||||
surveyor.get_absolute_matrix("obj").should_be_called().will_return("matrix")
|
||||
ifc.run("geometry.edit_object_placement", product="element", matrix="matrix").should_be_called()
|
||||
geometry.record_object_position("obj").should_be_called()
|
||||
|
||||
def test_run(self, ifc, geometry, surveyor):
|
||||
self.predict(ifc, geometry, surveyor)
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
import bpy
|
||||
import math
|
||||
import numpy
|
||||
import numpy as np
|
||||
import ifcopenshell
|
||||
import blenderbim.core.tool
|
||||
import blenderbim.tool as tool
|
||||
@@ -352,6 +352,14 @@ class TestLink(NewFile):
|
||||
assert obj.BIMMeshProperties.ifc_definition_id == element.id()
|
||||
|
||||
|
||||
class TestRecordObjectPosition(NewFile):
|
||||
def test_run(self):
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
subject.record_object_position(obj)
|
||||
assert obj.BIMObjectProperties.location_checksum == repr(np.array(obj.matrix_world.translation).tobytes())
|
||||
assert obj.BIMObjectProperties.rotation_checksum == repr(np.array(obj.matrix_world.to_3x3()).tobytes())
|
||||
|
||||
|
||||
class TestRenameObject(NewFile):
|
||||
def test_run(self):
|
||||
obj = bpy.data.meshes.new("Mesh")
|
||||
|
||||
Reference in New Issue
Block a user