Object placements are now updated on export in case you forgot to sync them in authoring mode. See #1360.

This commit is contained in:
Dion Moult
2021-03-15 18:22:18 +11:00
parent a25ca91ba6
commit f4f2a3d24e
3 changed files with 40 additions and 17 deletions
@@ -1,10 +1,12 @@
import os import os
import bpy import bpy
import json import json
import numpy as np
import datetime import datetime
import zipfile import zipfile
import tempfile import tempfile
import ifcopenshell import ifcopenshell
import ifcopenshell.util.placement
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
import addon_utils import addon_utils
@@ -16,6 +18,8 @@ class IfcExporter:
def export(self): def export(self):
self.file = IfcStore.get_file() self.file = IfcStore.get_file()
self.set_header() self.set_header()
if bpy.context.scene.BIMProjectProperties.is_authoring:
self.sync_object_placements()
extension = self.ifc_export_settings.output_file.split(".")[-1] extension = self.ifc_export_settings.output_file.split(".")[-1]
if extension == "ifczip": if extension == "ifczip":
with tempfile.TemporaryDirectory() as unzipped_path: with tempfile.TemporaryDirectory() as unzipped_path:
@@ -68,6 +72,36 @@ class IfcExporter:
# else: # else:
# self.file.wrapped_data.header.file_name.authorization = "Nobody" # self.file.wrapped_data.header.file_name.authorization = "Nobody"
def sync_object_placements(self):
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
for obj in bpy.data.objects:
try:
self.sync_object_placement(obj)
except:
pass
def sync_object_placement(self, obj):
blender_matrix = np.matrix(obj.matrix_world)
ifc_matrix = ifcopenshell.util.placement.get_local_placement(
self.file.by_id(obj.BIMObjectProperties.ifc_definition_id).ObjectPlacement
)
ifc_matrix[0][3] *= self.unit_scale
ifc_matrix[1][3] *= self.unit_scale
ifc_matrix[2][3] *= self.unit_scale
props = bpy.context.scene.BIMGeoreferenceProperties
if props.has_blender_offset and props.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):
bpy.ops.bim.edit_object_placement(obj=obj.name)
def get_application_name(self): def get_application_name(self):
return "BlenderBIM" return "BlenderBIM"
@@ -1,6 +1,7 @@
import bpy import bpy
import numpy as np import numpy as np
import ifcopenshell import ifcopenshell
import ifcopenshell.util.unit
import ifcopenshell.util.element import ifcopenshell.util.element
import logging import logging
import blenderbim.bim.module.geometry.edit_object_placement as edit_object_placement import blenderbim.bim.module.geometry.edit_object_placement as edit_object_placement
@@ -37,19 +38,19 @@ class EditObjectPlacement(bpy.types.Operator):
self.file = IfcStore.get_file() self.file = IfcStore.get_file()
# TODO: determine how to deal with this module dependency # TODO: determine how to deal with this module dependency
props = bpy.context.scene.BIMGeoreferenceProperties props = bpy.context.scene.BIMGeoreferenceProperties
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
for obj in objs: for obj in objs:
if not obj.BIMObjectProperties.ifc_definition_id: if not obj.BIMObjectProperties.ifc_definition_id:
continue continue
matrix = np.array(obj.matrix_world) matrix = np.array(obj.matrix_world)
if props.has_blender_offset and props.blender_offset_type == "OBJECT_PLACEMENT": if props.has_blender_offset and props.blender_offset_type == "OBJECT_PLACEMENT":
self.calculate_unit_scale()
# TODO: np.array? Why not matrix? # TODO: np.array? Why not matrix?
matrix = np.array( matrix = np.array(
ifcopenshell.util.geolocation.local2global( ifcopenshell.util.geolocation.local2global(
np.matrix(obj.matrix_world), np.matrix(obj.matrix_world),
float(props.blender_eastings) * self.unit_scale, float(props.blender_eastings) * unit_scale,
float(props.blender_northings) * self.unit_scale, float(props.blender_northings) * unit_scale,
float(props.blender_orthogonal_height) * self.unit_scale, float(props.blender_orthogonal_height) * unit_scale,
float(props.blender_x_axis_abscissa), float(props.blender_x_axis_abscissa),
float(props.blender_x_axis_ordinate), float(props.blender_x_axis_ordinate),
) )
@@ -63,18 +64,6 @@ class EditObjectPlacement(bpy.types.Operator):
).execute() ).execute()
return {"FINISHED"} return {"FINISHED"}
def calculate_unit_scale(self):
self.unit_scale = 1
units = self.file.by_type("IfcUnitAssignment")[0]
for unit in units.Units:
if not hasattr(unit, "UnitType") or unit.UnitType != "LENGTHUNIT":
continue
while unit.is_a("IfcConversionBasedUnit"):
self.unit_scale *= unit.ConversionFactor.ValueComponent.wrappedValue
unit = unit.ConversionFactor.UnitComponent
if unit.is_a("IfcSIUnit"):
self.unit_scale *= ifcopenshell.util.unit.get_prefix_multiplier(unit.Prefix)
class AddRepresentation(bpy.types.Operator): class AddRepresentation(bpy.types.Operator):
bl_idname = "bim.add_representation" bl_idname = "bim.add_representation"
@@ -13,4 +13,4 @@ from bpy.props import (
class BIMProjectProperties(PropertyGroup): class BIMProjectProperties(PropertyGroup):
is_authoring: BoolProperty(name="Enable Authoring Mode") is_authoring: BoolProperty(name="Enable Authoring Mode", default=True)