diff --git a/src/blenderbim/blenderbim/bim/__init__.py b/src/blenderbim/blenderbim/bim/__init__.py index 7c51351e8d..4e49f4466e 100644 --- a/src/blenderbim/blenderbim/bim/__init__.py +++ b/src/blenderbim/blenderbim/bim/__init__.py @@ -84,7 +84,6 @@ if bpy is not None: prop.GlobalId, prop.BIMObjectProperties, prop.BIMMaterialProperties, - prop.ItemSlotMap, prop.BIMMeshProperties, ui.BIM_PT_section_plane, ui.BIM_UL_generic, diff --git a/src/blenderbim/blenderbim/bim/export_ifc.py b/src/blenderbim/blenderbim/bim/export_ifc.py index dd1dd54d03..5f9b35812c 100644 --- a/src/blenderbim/blenderbim/bim/export_ifc.py +++ b/src/blenderbim/blenderbim/bim/export_ifc.py @@ -103,7 +103,7 @@ class IfcExporter: ifc_matrix[2][3] *= self.unit_scale props = bpy.context.scene.BIMGeoreferenceProperties - if props.has_blender_offset and props.blender_offset_type == "OBJECT_PLACEMENT": + 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, diff --git a/src/blenderbim/blenderbim/bim/import_ifc.py b/src/blenderbim/blenderbim/bim/import_ifc.py index 4e0897087d..27122b9e76 100644 --- a/src/blenderbim/blenderbim/bim/import_ifc.py +++ b/src/blenderbim/blenderbim/bim/import_ifc.py @@ -229,18 +229,19 @@ class IfcImporter: self.set_default_context() self.profile_code("Setting default context") - def is_element_far_away(self, element): + def is_element_far_away(self, element, is_meters=True): try: - return self.is_point_far_away(element.ObjectPlacement.RelativePlacement.Location) + return self.is_point_far_away(element.ObjectPlacement.RelativePlacement.Location, is_meters=is_meters) except: pass - def is_point_far_away(self, point): - # Arbitrary threshold based on experience + def is_point_far_away(self, point, is_meters=True): + # Locations greater than 1km are not considered "small sites" according to the georeferencing guide + limit = 1000 if is_meters else (1000 / self.unit_scale) coords = point if hasattr(point, "Coordinates"): coords = point.Coordinates - return abs(coords[0]) > 1000000 or abs(coords[1]) > 1000000 or abs(coords[2]) > 1000000 + return abs(coords[0]) > limit or abs(coords[1]) > limit or abs(coords[2]) > limit def process_element_filter(self): if not self.ifc_import_settings.ifc_selector: @@ -340,7 +341,6 @@ class IfcImporter: props.blender_x_axis_abscissa = str(placement.RefDirection.DirectionRatios[0]) props.blender_x_axis_ordinate = str(placement.RefDirection.DirectionRatios[1]) props.has_blender_offset = True - props.blender_offset_type = "OBJECT_PLACEMENT" def guess_absolute_coordinate(self): # Civil BIM applications like to work in absolute coordinates, where the ObjectPlacement is 0,0,0 but each @@ -353,7 +353,6 @@ class IfcImporter: props.blender_northings = str(offset_point[1]) props.blender_orthogonal_height = str(offset_point[2]) props.has_blender_offset = True - props.blender_offset_type = "CARTESIAN_POINT" def get_offset_point(self): offset_point = None @@ -370,7 +369,7 @@ class IfcImporter: if elements_checked > element_checking_threshold: return for i, point in enumerate(point_list.CoordList): - if len(point) == 3 and self.is_point_far_away(point): + if len(point) == 3 and self.is_point_far_away(point, is_meters=False): return point for point in self.file.by_type("IfcCartesianPoint"): @@ -384,22 +383,26 @@ class IfcImporter: elements_checked += 1 if elements_checked > element_checking_threshold: return - if len(point.Coordinates) == 3 and self.is_point_far_away(point): + if len(point.Coordinates) == 3 and self.is_point_far_away(point, is_meters=False): return point.Coordinates - def apply_blender_offset_to_matrix(self, matrix): + def apply_blender_offset_to_matrix_world(self, obj, matrix): props = bpy.context.scene.BIMGeoreferenceProperties - if props.has_blender_offset and props.blender_offset_type == "OBJECT_PLACEMENT": - return mathutils.Matrix( - ifcopenshell.util.geolocation.global2local( - 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), - ).tolist() - ) + if props.has_blender_offset: + if self.is_point_far_away((matrix[0, 3], matrix[1, 3], matrix[2, 3])): + obj.BIMObjectProperties.blender_offset_type = "OBJECT_PLACEMENT" + return mathutils.Matrix( + ifcopenshell.util.geolocation.global2local( + 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), + ).tolist() + ) + else: + obj.BIMObjectProperties.blender_offset_type = "CARTESIAN_POINT" return mathutils.Matrix(matrix.tolist()) def find_decomposed_ifc_class(self, element, ifc_class): @@ -426,29 +429,25 @@ class IfcImporter: shape = ifcopenshell.geom.create_shape(self.settings_2d, grid) grid_obj = self.create_product(grid, shape) collection = bpy.data.collections.new(self.get_name(grid)) - element_matrix = self.get_local_placement(grid.ObjectPlacement) - element_matrix[0][3] *= self.unit_scale - element_matrix[1][3] *= self.unit_scale - element_matrix[2][3] *= self.unit_scale u_axes = bpy.data.collections.new("UAxes") collection.children.link(u_axes) v_axes = bpy.data.collections.new("VAxes") collection.children.link(v_axes) - self.create_grid_axes(grid.UAxes, u_axes, element_matrix) - self.create_grid_axes(grid.VAxes, v_axes, element_matrix) + self.create_grid_axes(grid.UAxes, u_axes, grid_obj) + self.create_grid_axes(grid.VAxes, v_axes, grid_obj) if grid.WAxes: w_axes = bpy.data.collections.new("WAxes") collection.children.link(w_axes) - self.create_grid_axes(grid.WAxes, w_axes, element_matrix) + self.create_grid_axes(grid.WAxes, w_axes, grid_obj) - def create_grid_axes(self, axes, grid, matrix_world): + def create_grid_axes(self, axes, grid_collection, grid_obj): for axis in axes: shape = ifcopenshell.geom.create_shape(self.settings_2d, axis.AxisCurve) mesh = self.create_mesh(axis, shape) obj = bpy.data.objects.new(f"IfcGridAxis/{axis.AxisTag}", mesh) obj.BIMObjectProperties.ifc_definition_id = axis.id() - obj.matrix_world = matrix_world - grid.objects.link(obj) + obj.matrix_world = grid_obj.matrix_world + grid_collection.objects.link(obj) def create_type_products(self): type_products = self.file.by_type("IfcTypeProduct") @@ -617,7 +616,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 = mathutils.Matrix(placement_matrix.tolist()) + obj.matrix_world = self.apply_blender_offset_to_matrix_world(placement_matrix) self.link_element(product, obj) def create_curve_products(self, products): @@ -676,13 +675,13 @@ class IfcImporter: mat = np.matrix( ([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(mat) + obj.matrix_world = 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(self.get_element_matrix(element)) + obj.matrix_world = 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(self.get_element_matrix(element)) + obj.matrix_world = self.apply_blender_offset_to_matrix_world(obj, self.get_element_matrix(element)) self.add_opening_relation(element, obj) @@ -982,6 +981,7 @@ class IfcImporter: def create_aggregate(self, rel_aggregate): element = rel_aggregate.RelatingObject obj = bpy.data.objects.new("{}/{}".format(element.is_a(), element.Name), None) + obj.matrix_world = self.apply_blender_offset_to_matrix_world(obj, self.get_element_matrix(element)) self.link_element(element, obj) collection = bpy.data.collections.new(obj.name) collection.objects.link(obj) @@ -1131,7 +1131,7 @@ class IfcImporter: self.ifc_import_settings.logger.warning("Warning: this object is outside the spatial hierarchy %s", element) bpy.context.scene.collection.objects.link(obj) - def get_element_matrix(self, element, mesh_name=None): + def get_element_matrix(self, element): result = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement) result[0][3] *= self.unit_scale result[1][3] *= self.unit_scale @@ -1265,7 +1265,11 @@ class IfcImporter: mesh = bpy.data.meshes.new(self.get_mesh_name(geometry)) props = bpy.context.scene.BIMGeoreferenceProperties - if props.has_blender_offset and props.blender_offset_type == "CARTESIAN_POINT": + if ( + props.has_blender_offset + and geometry.verts + and self.is_point_far_away((geometry.verts[0], geometry.verts[1], geometry.verts[2])) + ): ordinate_index = 0 verts = [None] * len(geometry.verts) offset_point = ( diff --git a/src/blenderbim/blenderbim/bim/module/geometry/operator.py b/src/blenderbim/blenderbim/bim/module/geometry/operator.py index 05de22c7b5..a49a21eef6 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/operator.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/operator.py @@ -32,7 +32,7 @@ class EditObjectPlacement(bpy.types.Operator): if not obj.BIMObjectProperties.ifc_definition_id: continue matrix = np.array(obj.matrix_world) - if props.has_blender_offset and props.blender_offset_type == "OBJECT_PLACEMENT": + if props.has_blender_offset and obj.BIMObjectProperties.blender_offset_type == "OBJECT_PLACEMENT": unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file) # TODO: np.array? Why not matrix? matrix = np.array( @@ -84,7 +84,7 @@ class AddRepresentation(bpy.types.Operator): gprop = context.scene.BIMGeoreferenceProperties coordinate_offset = None - if gprop.has_blender_offset and gprop.blender_offset_type == "CARTESIAN_POINT": + if gprop.has_blender_offset and obj.BIMObjectProperties.blender_offset_type == "CARTESIAN_POINT": coordinate_offset = Vector( ( float(gprop.blender_eastings), @@ -302,7 +302,7 @@ class UpdateRepresentation(bpy.types.Operator): gprop = context.scene.BIMGeoreferenceProperties coordinate_offset = None - if gprop.has_blender_offset and gprop.blender_offset_type == "CARTESIAN_POINT": + if gprop.has_blender_offset and obj.BIMObjectProperties.blender_offset_type == "CARTESIAN_POINT": coordinate_offset = Vector( ( float(gprop.blender_eastings), diff --git a/src/blenderbim/blenderbim/bim/module/geometry/ui.py b/src/blenderbim/blenderbim/bim/module/geometry/ui.py index 784e2ff739..936aeffd9a 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/ui.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/ui.py @@ -109,6 +109,10 @@ class BIM_PT_mesh(Panel): def BIM_PT_transform(self, context): if context.active_object and context.active_object.BIMObjectProperties.ifc_definition_id: + row = self.layout.row(align=True) + row.label(text="Blender Offset") + row.label(text=context.active_object.BIMObjectProperties.blender_offset_type) + row = self.layout.row() row.operator("bim.edit_object_placement") diff --git a/src/blenderbim/blenderbim/bim/module/georeference/operator.py b/src/blenderbim/blenderbim/bim/module/georeference/operator.py index 645ae7c4f1..bafe90b113 100644 --- a/src/blenderbim/blenderbim/bim/module/georeference/operator.py +++ b/src/blenderbim/blenderbim/bim/module/georeference/operator.py @@ -244,11 +244,7 @@ class ConvertLocalToGlobal(bpy.types.Operator): props = context.scene.BIMGeoreferenceProperties x, y, z = [float(co) for co in props.coordinate_input.split(",")] - if props.has_blender_offset and props.blender_offset_type == "CARTESIAN_POINT": - x -= float(props.blender_eastings) - y -= float(props.blender_northings) - z -= float(props.blender_orthogonal_height) - elif props.has_blender_offset and props.blender_offset_type == "OBJECT_PLACEMENT": + if props.has_blender_offset: results = ifcopenshell.util.geolocation.xyz2enh( x, y, @@ -310,11 +306,7 @@ class ConvertGlobalToLocal(bpy.types.Operator): else: results = (x, y, z) - if props.has_blender_offset and props.blender_offset_type == "CARTESIAN_POINT": - results[0] += float(props.blender_eastings) - results[1] += float(props.blender_northings) - results[2] += float(props.blender_orthogonal_height) - elif props.has_blender_offset and props.blender_offset_type == "OBJECT_PLACEMENT": + if props.has_blender_offset: results = ifcopenshell.util.geolocation.enh2xyz( results[0], results[1], diff --git a/src/blenderbim/blenderbim/bim/module/georeference/prop.py b/src/blenderbim/blenderbim/bim/module/georeference/prop.py index 0bcaafdc7d..8406f823bf 100644 --- a/src/blenderbim/blenderbim/bim/module/georeference/prop.py +++ b/src/blenderbim/blenderbim/bim/module/georeference/prop.py @@ -36,11 +36,6 @@ class BIMGeoreferenceProperties(PropertyGroup): coordinate_input: StringProperty(name="Coordinate Input") coordinate_output: StringProperty(name="Coordinate Output") has_blender_offset: BoolProperty(name="Has Blender Offset") - blender_offset_type: EnumProperty( - items=[(o, o, "") for o in ["OBJECT_PLACEMENT", "CARTESIAN_POINT"]], - name="Blender Offset", - default="OBJECT_PLACEMENT", - ) blender_eastings: StringProperty(name="Blender Eastings", default="0") blender_northings: StringProperty(name="Blender Northings", default="0") blender_orthogonal_height: StringProperty(name="Blender Orthogonal Height", default="0") diff --git a/src/blenderbim/blenderbim/bim/module/georeference/ui.py b/src/blenderbim/blenderbim/bim/module/georeference/ui.py index be2f01a1f3..19f843541a 100644 --- a/src/blenderbim/blenderbim/bim/module/georeference/ui.py +++ b/src/blenderbim/blenderbim/bim/module/georeference/ui.py @@ -90,18 +90,16 @@ class BIM_PT_gis(Panel): def draw_ui(self, context): props = context.scene.BIMGeoreferenceProperties - if not Data.projected_crs and IfcStore.get_file().schema != "IFC2X3": + if not Data.projected_crs: row = self.layout.row(align=True) row.label(text="Not Georeferenced") - row.operator("bim.add_georeferencing", icon="ADD", text="") + if IfcStore.get_file().schema != "IFC2X3": + row.operator("bim.add_georeferencing", icon="ADD", text="") if props.has_blender_offset: row = self.layout.row() row.label(text="Blender Offset", icon="TRACKING_REFINE_FORWARDS") - row = self.layout.row(align=True) - row.label(text="Type") - row.label(text=props.blender_offset_type) row = self.layout.row(align=True) row.label(text="Eastings") row.label(text=props.blender_eastings) diff --git a/src/blenderbim/blenderbim/bim/prop.py b/src/blenderbim/blenderbim/bim/prop.py index cb7e983b81..6f27dba4e8 100644 --- a/src/blenderbim/blenderbim/bim/prop.py +++ b/src/blenderbim/blenderbim/bim/prop.py @@ -259,6 +259,11 @@ class GlobalId(PropertyGroup): class BIMObjectProperties(PropertyGroup): ifc_definition_id: IntProperty(name="IFC Definition ID") + blender_offset_type: EnumProperty( + items=[(o, o, "") for o in ["NONE", "OBJECT_PLACEMENT", "CARTESIAN_POINT"]], + name="Blender Offset", + default="NONE", + ) is_reassigning_class: BoolProperty(name="Is Reassigning Class") global_ids: CollectionProperty(name="GlobalIds", type=GlobalId) relating_object: PointerProperty(name="Aggregate", type=bpy.types.Object) @@ -279,11 +284,6 @@ class BIMMaterialProperties(PropertyGroup): ifc_style_id: IntProperty(name="IFC Style ID") -class ItemSlotMap(PropertyGroup): - name: StringProperty(name="Item Element ID") - slot_index: IntProperty(name="Material Slot Index") - - class BIMMeshProperties(PropertyGroup): ifc_definition_id: IntProperty(name="IFC Definition ID") is_native: BoolProperty(name="Is Native", default=False) @@ -291,4 +291,3 @@ class BIMMeshProperties(PropertyGroup): is_parametric: BoolProperty(name="Is Parametric", default=False) ifc_definition: StringProperty(name="IFC Definition") ifc_parameters: CollectionProperty(name="IFC Parameters", type=IfcParameter) - ifc_item_ids: CollectionProperty(name="IFC Item IDs", type=ItemSlotMap)