mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-12 10:33:20 +00:00
WIP implement blender offsets for non-geolocated files. Also deprecate a whole bunch of geolocation vendor workarounds into a standard feature. See #1222.
This commit is contained in:
@@ -17,6 +17,7 @@ import math
|
||||
import multiprocessing
|
||||
import zipfile
|
||||
import tempfile
|
||||
import numpy as np
|
||||
from pathlib import Path
|
||||
from itertools import cycle
|
||||
from datetime import datetime
|
||||
@@ -345,8 +346,8 @@ class IfcImporter:
|
||||
self.profile_code("Set vendor worksarounds")
|
||||
self.calculate_unit_scale()
|
||||
self.profile_code("Calculate unit scale")
|
||||
self.patch_ifc()
|
||||
self.profile_code("Patching ifc")
|
||||
self.calculate_model_offset()
|
||||
self.profile_code("Calculate model offset")
|
||||
self.set_units()
|
||||
self.profile_code("Set units")
|
||||
self.create_project()
|
||||
@@ -409,41 +410,17 @@ class IfcImporter:
|
||||
self.profile_code("Mesh cleaning")
|
||||
|
||||
def auto_set_workarounds(self):
|
||||
if (
|
||||
"DDS-CAD" in self.file.wrapped_data.header.file_name.originating_system
|
||||
or "DDS" in self.file.wrapped_data.header.file_name.preprocessor_version
|
||||
):
|
||||
self.ifc_import_settings.should_reset_absolute_coordinates = True
|
||||
applications = self.file.by_type("IfcApplication")
|
||||
if not applications:
|
||||
return
|
||||
if applications[0].ApplicationIdentifier == "Revit":
|
||||
if self.is_ifc_class_far_away("IfcSite"):
|
||||
self.ifc_import_settings.should_ignore_site_coordinates = True
|
||||
self.ifc_import_settings.should_guess_georeferencing = True
|
||||
if self.is_ifc_class_far_away("IfcBuilding"):
|
||||
self.ifc_import_settings.should_ignore_building_coordinates = True
|
||||
self.ifc_import_settings.should_guess_georeferencing = True
|
||||
elif "prostructures" in applications[0].ApplicationFullName.lower():
|
||||
if "prostructures" in applications[0].ApplicationFullName.lower():
|
||||
self.ifc_import_settings.should_allow_non_element_aggregates = True
|
||||
elif applications[0].ApplicationFullName.lower() == "12d model":
|
||||
self.ifc_import_settings.should_reset_absolute_coordinates = True
|
||||
elif "Civil 3D" in applications[0].ApplicationFullName:
|
||||
self.ifc_import_settings.should_reset_absolute_coordinates = True
|
||||
elif applications[0].ApplicationFullName == "Tekla Structures":
|
||||
if self.is_ifc_class_far_away("IfcSite"):
|
||||
self.ifc_import_settings.should_ignore_site_coordinates = True
|
||||
|
||||
def is_ifc_class_far_away(self, ifc_class):
|
||||
for site in self.file.by_type(ifc_class):
|
||||
if (
|
||||
not site.ObjectPlacement
|
||||
or not site.ObjectPlacement.RelativePlacement
|
||||
or not site.ObjectPlacement.RelativePlacement.Location
|
||||
):
|
||||
continue
|
||||
if self.is_point_far_away(site.ObjectPlacement.RelativePlacement.Location):
|
||||
return True
|
||||
def is_element_far_away(self, element):
|
||||
try:
|
||||
return self.is_point_far_away(element.ObjectPlacement.RelativePlacement.Location)
|
||||
except:
|
||||
pass
|
||||
|
||||
def is_point_far_away(self, point):
|
||||
# Arbitrary threshold based on experience
|
||||
@@ -533,94 +510,94 @@ class IfcImporter:
|
||||
products.extend(self.get_products_from_shape_representation(inverse_element))
|
||||
return products
|
||||
|
||||
def patch_ifc(self):
|
||||
def calculate_model_offset(self):
|
||||
project = self.file.by_type("IfcProject")[0]
|
||||
if self.ifc_import_settings.should_ignore_site_coordinates:
|
||||
sites = self.find_decomposed_ifc_class(project, "IfcSite")
|
||||
if self.ifc_import_settings.should_guess_georeferencing and sites:
|
||||
self.guess_georeferencing(sites[0])
|
||||
for site in sites:
|
||||
self.patch_placement_to_origin(site)
|
||||
if self.ifc_import_settings.should_ignore_building_coordinates:
|
||||
buildings = self.find_decomposed_ifc_class(project, "IfcBuilding")
|
||||
if self.ifc_import_settings.should_guess_georeferencing and buildings:
|
||||
self.guess_georeferencing(buildings[0])
|
||||
for building in buildings:
|
||||
self.patch_placement_to_origin(building)
|
||||
if self.ifc_import_settings.should_reset_absolute_coordinates:
|
||||
self.reset_absolute_coordinates()
|
||||
site = self.find_decomposed_ifc_class(project, "IfcSite")
|
||||
if site and self.is_element_far_away(site[0]):
|
||||
return self.guess_georeferencing(site[0])
|
||||
building = self.find_decomposed_ifc_class(project, "IfcBuilding")
|
||||
if building and self.is_element_far_away(building[0]):
|
||||
return self.guess_georeferencing(building[0])
|
||||
return self.guess_absolute_coordinate()
|
||||
|
||||
def guess_georeferencing(self, element):
|
||||
if not element.ObjectPlacement.is_a("IfcLocalPlacement"):
|
||||
return
|
||||
placement = element.ObjectPlacement.RelativePlacement
|
||||
bpy.context.scene.MapConversion.eastings = str(placement.Location.Coordinates[0])
|
||||
bpy.context.scene.MapConversion.northings = str(placement.Location.Coordinates[1])
|
||||
bpy.context.scene.MapConversion.orthogonal_height = str(placement.Location.Coordinates[2])
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
props.blender_eastings = str(placement.Location.Coordinates[0])
|
||||
props.blender_northings = str(placement.Location.Coordinates[1])
|
||||
props.blender_orthogonal_height = str(placement.Location.Coordinates[2])
|
||||
if placement.RefDirection:
|
||||
bpy.context.scene.MapConversion.x_axis_abscissa = str(placement.RefDirection.DirectionRatios[0])
|
||||
bpy.context.scene.MapConversion.x_axis_ordinate = str(placement.RefDirection.DirectionRatios[1] * -1)
|
||||
bpy.context.scene.MapConversion.scale = "1"
|
||||
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 reset_absolute_coordinates(self):
|
||||
# 12D can have some funky coordinates out of any sensible range. This
|
||||
# method will not work all the time, but will catch most issues.
|
||||
def guess_absolute_coordinate(self):
|
||||
# Civil BIM applications like to work in absolute coordinates, where the ObjectPlacement is 0,0,0 but each
|
||||
# individual coordinate of the shape representation is in absolute values.
|
||||
offset_point = self.get_offset_point()
|
||||
if not offset_point:
|
||||
return
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
props.blender_eastings = str(offset_point[0])
|
||||
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
|
||||
elements_checked = 0
|
||||
# If more than these points aren't far away, the file probably isn't absolutely positioned
|
||||
element_checking_threshold = 100
|
||||
try:
|
||||
point_lists = self.file.by_type("IfcCartesianPointList3D")
|
||||
except:
|
||||
# IFC2X3 does not have IfcCartesianPointList3D
|
||||
point_lists = []
|
||||
for point_list in point_lists:
|
||||
coord_list = [None] * len(point_list.CoordList)
|
||||
elements_checked += 1
|
||||
if elements_checked > element_checking_threshold:
|
||||
return
|
||||
for i, point in enumerate(point_list.CoordList):
|
||||
if len(point) == 2 or not self.is_point_far_away(point):
|
||||
coord_list[i] = point
|
||||
continue
|
||||
if not offset_point:
|
||||
offset_point = (point[0], point[1], point[2])
|
||||
self.ifc_import_settings.logger.info("Resetting absolute coordinates by %s", point)
|
||||
point = (point[0] - offset_point[0], point[1] - offset_point[1], point[2] - offset_point[2])
|
||||
coord_list[i] = point
|
||||
point_list.CoordList = coord_list
|
||||
if len(point) == 3 and self.is_point_far_away(point):
|
||||
return point[0]
|
||||
# offset_point = (point[0], point[1], point[2])
|
||||
|
||||
for point in self.file.by_type("IfcCartesianPoint"):
|
||||
if len(point.Coordinates) == 2 or not self.is_point_far_away(point):
|
||||
continue
|
||||
if not offset_point:
|
||||
offset_point = (point.Coordinates[0], point.Coordinates[1], point.Coordinates[2])
|
||||
self.ifc_import_settings.logger.info("Resetting absolute coordinates by %s", point)
|
||||
point.Coordinates = (
|
||||
point.Coordinates[0] - offset_point[0],
|
||||
point.Coordinates[1] - offset_point[1],
|
||||
point.Coordinates[2] - offset_point[2],
|
||||
elements_checked += 1
|
||||
if elements_checked > element_checking_threshold:
|
||||
return
|
||||
if len(point.Coordinates) == 3 and self.is_point_far_away(point):
|
||||
return point[0]
|
||||
|
||||
def apply_blender_offset_to_matrix(self, matrix):
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
if props.has_blender_offset and props.blender_offset_type == "OBJECT_PLACEMENT":
|
||||
test = 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 not offset_point:
|
||||
return
|
||||
if self.file.wrapped_data.schema == "IFC2X3":
|
||||
properties = [
|
||||
self.file.createIfcPropertySingleValue(
|
||||
"Eastings", None, self.file.createIfcLengthMeasure(offset_point[0])
|
||||
),
|
||||
self.file.createIfcPropertySingleValue(
|
||||
"Northings", None, self.file.createIfcLengthMeasure(offset_point[1])
|
||||
),
|
||||
self.file.createIfcPropertySingleValue(
|
||||
"OrthogonalHeight", None, self.file.createIfcLengthMeasure(offset_point[2])
|
||||
),
|
||||
]
|
||||
history = self.file.createIfcOwnerHistory()
|
||||
pset = self.file.createIfcPropertySet(
|
||||
ifcopenshell.guid.new(), history, "EPset_MapConversion", None, properties
|
||||
|
||||
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()
|
||||
)
|
||||
self.file.createIfcRelDefinesByProperties(
|
||||
ifcopenshell.guid.new(), history, None, None, self.file.by_type("IfcSite"), pset
|
||||
)
|
||||
else:
|
||||
# We don't have the full geolocation information, so we'll add what we can
|
||||
scene = bpy.context.scene
|
||||
scene.MapConversion.eastings = str(offset_point[0])
|
||||
scene.MapConversion.northings = str(offset_point[1])
|
||||
scene.MapConversion.orthogonal_height = str(offset_point[2])
|
||||
return mathutils.Matrix(matrix.tolist())
|
||||
|
||||
def find_decomposed_ifc_class(self, element, ifc_class):
|
||||
results = []
|
||||
@@ -634,20 +611,6 @@ class IfcImporter:
|
||||
results.extend(self.find_decomposed_ifc_class(part, ifc_class))
|
||||
return results
|
||||
|
||||
def patch_placement_to_origin(self, element):
|
||||
element.ObjectPlacement.RelativePlacement.Location.Coordinates = (0.0, 0.0, 0.0)
|
||||
if element.ObjectPlacement.RelativePlacement.Axis:
|
||||
element.ObjectPlacement.RelativePlacement.Axis.DirectionRatios = (0.0, 0.0, 1.0)
|
||||
if element.ObjectPlacement.RelativePlacement.RefDirection:
|
||||
element.ObjectPlacement.RelativePlacement.RefDirection.DirectionRatios = (1.0, 0.0, 0.0)
|
||||
|
||||
def get_unit_name(self, named_unit):
|
||||
name = ""
|
||||
if hasattr(named_unit, "Prefix") and named_unit.Prefix:
|
||||
name += named_unit.Prefix
|
||||
name += named_unit.Name
|
||||
return name
|
||||
|
||||
def create_groups(self):
|
||||
group_collection = None
|
||||
for collection in self.project["blender"].children:
|
||||
@@ -848,14 +811,14 @@ class IfcImporter:
|
||||
|
||||
if shape:
|
||||
m = shape.transformation.matrix.data
|
||||
mat = mathutils.Matrix(
|
||||
([m[0], m[1], m[2], 0], [m[3], m[4], m[5], 0], [m[6], m[7], m[8], 0], [m[9], m[10], m[11], 1])
|
||||
# We use numpy here because Blender mathutils.Matrix is not accurate enough
|
||||
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])
|
||||
)
|
||||
mat.transpose()
|
||||
obj.matrix_world = mat
|
||||
obj.matrix_world = self.apply_blender_offset_to_matrix(mat)
|
||||
self.material_creator.create(element, obj, mesh)
|
||||
elif hasattr(element, "ObjectPlacement"):
|
||||
obj.matrix_world = self.get_element_matrix(element)
|
||||
obj.matrix_world = self.apply_blender_offset_to_matrix(self.get_element_matrix(element))
|
||||
|
||||
self.add_element_representation_items(element, obj)
|
||||
self.add_element_classifications(element, obj)
|
||||
@@ -1674,38 +1637,11 @@ class IfcImporter:
|
||||
return self.get_referenced_source_name(element.ReferencedSource)
|
||||
|
||||
def get_element_matrix(self, element, mesh_name=None):
|
||||
element_matrix = self.get_local_placement(element.ObjectPlacement)
|
||||
|
||||
if mesh_name:
|
||||
# Blender supports reusing a mesh with a different transformation
|
||||
# applied at the object level. In contrast, IFC supports reusing a mesh
|
||||
# with a different transformation applied at the mesh level _as well as_
|
||||
# the object level. For this reason, if the end-goal is to re-use mesh
|
||||
# data, we must combine IFC's mesh-level transformation into Blender's
|
||||
# object level transformation.
|
||||
|
||||
# The first step to do this is to _undo_ the mesh-level transformation
|
||||
# from whatever shared mesh we are using, as it is not necessarily the
|
||||
# same as the current mesh.
|
||||
shared_shape_transformation = self.get_representation_cartesian_transformation(
|
||||
self.file.by_id(self.mesh_shapes[mesh_name].product.id())
|
||||
)
|
||||
if shared_shape_transformation:
|
||||
shared_transform = self.get_cartesiantransformationoperator(shared_shape_transformation)
|
||||
shared_transform.invert()
|
||||
element_matrix = element_matrix @ shared_transform
|
||||
|
||||
# The next step is to apply the current element's mesh level
|
||||
# transformation to our current element's object transformation
|
||||
transformation = self.get_representation_cartesian_transformation(element)
|
||||
if transformation:
|
||||
element_matrix = self.get_cartesiantransformationoperator(transformation) @ element_matrix
|
||||
|
||||
element_matrix[0][3] *= self.unit_scale
|
||||
element_matrix[1][3] *= self.unit_scale
|
||||
element_matrix[2][3] *= self.unit_scale
|
||||
|
||||
return element_matrix
|
||||
result = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement)
|
||||
result[0][3] *= self.unit_scale
|
||||
result[1][3] *= self.unit_scale
|
||||
result[2][3] *= self.unit_scale
|
||||
return result
|
||||
|
||||
def get_body_representations(self, representations, matrix=None):
|
||||
if matrix is None:
|
||||
@@ -1775,11 +1711,29 @@ class IfcImporter:
|
||||
representation_id = int(re.sub(r"\D", "", representation_id.split("-")[0]))
|
||||
else:
|
||||
representation_id = int(re.sub(r"\D", "", representation_id))
|
||||
mesh = bpy.data.meshes.new("{}/{}".format(
|
||||
self.file.by_id(representation_id).ContextOfItems.id(), geometry.id))
|
||||
mesh = bpy.data.meshes.new(
|
||||
"{}/{}".format(self.file.by_id(representation_id).ContextOfItems.id(), geometry.id)
|
||||
)
|
||||
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
if props.has_blender_offset and props.blender_offset_type == "CARTESIAN_POINT":
|
||||
ordinate_index = 0
|
||||
verts = [None] * len(geometry.verts)
|
||||
offset_point = (
|
||||
float(props.blender_eastings),
|
||||
float(props.blender_northings),
|
||||
float(props.blender_orthogonal_height),
|
||||
)
|
||||
for i, vert in enumerate(geometry.verts):
|
||||
if ordinate_index > 2:
|
||||
ordinate_index = 0
|
||||
verts[i] = vert - offset_point[ordinate_index]
|
||||
ordinate_index += 1
|
||||
else:
|
||||
verts = geometry.verts
|
||||
|
||||
if geometry.faces:
|
||||
num_vertices = len(geometry.verts) // 3
|
||||
num_vertices = len(verts) // 3
|
||||
total_faces = len(geometry.faces)
|
||||
loop_start = range(0, total_faces, 3)
|
||||
num_loops = total_faces // 3
|
||||
@@ -1791,11 +1745,11 @@ class IfcImporter:
|
||||
# Potentially, there is a smarter way to do this. See #1047
|
||||
v_index = cycle((0, 1, 2))
|
||||
verts = [
|
||||
v + self.ifc_import_settings.model_offset_coordinates[next(v_index)] for v in geometry.verts
|
||||
v + self.ifc_import_settings.model_offset_coordinates[next(v_index)] for v in verts
|
||||
]
|
||||
mesh.vertices.foreach_set("co", verts)
|
||||
else:
|
||||
mesh.vertices.foreach_set("co", geometry.verts)
|
||||
mesh.vertices.foreach_set("co", verts)
|
||||
mesh.loops.add(num_vertex_indices)
|
||||
mesh.loops.foreach_set("vertex_index", geometry.faces)
|
||||
mesh.polygons.add(num_loops)
|
||||
@@ -1804,7 +1758,7 @@ class IfcImporter:
|
||||
mesh.update()
|
||||
else:
|
||||
e = geometry.edges
|
||||
v = geometry.verts
|
||||
v = verts
|
||||
vertices = [[v[i], v[i + 1], v[i + 2]] for i in range(0, len(v), 3)]
|
||||
edges = [[e[i], e[i + 1]] for i in range(0, len(e), 2)]
|
||||
mesh.from_pydata(vertices, edges, [])
|
||||
@@ -1821,6 +1775,7 @@ class IfcImporter:
|
||||
except:
|
||||
self.ifc_import_settings.logger.error("Could not create mesh for %s", element)
|
||||
import traceback
|
||||
|
||||
print(traceback.format_exc())
|
||||
|
||||
def create_curve(self, geometry):
|
||||
@@ -1925,7 +1880,6 @@ class IfcImportSettings:
|
||||
self.should_auto_set_workarounds = True
|
||||
self.should_ignore_site_coordinates = False
|
||||
self.should_ignore_building_coordinates = False
|
||||
self.should_reset_absolute_coordinates = False
|
||||
self.should_merge_materials_by_colour = False
|
||||
self.should_import_type_representations = False
|
||||
self.should_import_curves = False
|
||||
@@ -1950,10 +1904,6 @@ class IfcImportSettings:
|
||||
settings.diff_file = scene_bim.diff_json_file
|
||||
settings.ifc_import_filter = scene_bim.ifc_import_filter
|
||||
settings.ifc_selector = scene_bim.ifc_selector
|
||||
settings.should_ignore_site_coordinates = scene_bim.import_should_ignore_site_coordinates
|
||||
settings.should_ignore_building_coordinates = scene_bim.import_should_ignore_building_coordinates
|
||||
settings.should_reset_absolute_coordinates = scene_bim.import_should_reset_absolute_coordinates
|
||||
settings.should_guess_georeferencing = scene_bim.import_should_guess_georeferencing
|
||||
settings.should_import_type_representations = scene_bim.import_should_import_type_representations
|
||||
settings.should_import_curves = scene_bim.import_should_import_curves
|
||||
settings.should_import_opening_elements = scene_bim.import_should_import_opening_elements
|
||||
|
||||
@@ -20,15 +20,43 @@ class EditObjectPlacement(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
obj = bpy.data.objects.get(self.obj) if self.obj else bpy.context.active_object
|
||||
self.file = IfcStore.get_file()
|
||||
# TODO: determine how to deal with this module dependency
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
matrix = np.array(obj.matrix_world)
|
||||
if props.has_blender_offset and props.blender_offset_type == "OBJECT_PLACEMENT":
|
||||
self.calculate_unit_scale()
|
||||
# TODO: np.array? Why not matrix?
|
||||
matrix = np.array(
|
||||
ifcopenshell.util.geolocation.local2global(
|
||||
np.matrix(obj.matrix_world),
|
||||
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),
|
||||
)
|
||||
)
|
||||
edit_object_placement.Usecase(
|
||||
self.file,
|
||||
{
|
||||
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
|
||||
"matrix": np.array(obj.matrix_world),
|
||||
"matrix": matrix,
|
||||
},
|
||||
).execute()
|
||||
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):
|
||||
bl_idname = "bim.add_representation"
|
||||
@@ -67,7 +95,8 @@ class AddRepresentation(bpy.types.Operator):
|
||||
},
|
||||
).execute()
|
||||
assign_representation.Usecase(
|
||||
self.file, {"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), "representation": result}
|
||||
self.file,
|
||||
{"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id), "representation": result},
|
||||
).execute()
|
||||
|
||||
existing_mesh = obj.data
|
||||
|
||||
@@ -208,7 +208,7 @@ class ConvertLocalToGlobal(bpy.types.Operator):
|
||||
Data.map_conversion["Northings"],
|
||||
Data.map_conversion["OrthogonalHeight"],
|
||||
Data.map_conversion.get("XAxisAbscissa", 1.0),
|
||||
Data.map_conversion.get("XAxisAbscissa", 0.0),
|
||||
Data.map_conversion.get("XAxisOrdinate", 0.0),
|
||||
Data.map_conversion.get("Scale", 1.0),
|
||||
)
|
||||
props.coordinate_output = ",".join([str(r) for r in results])
|
||||
@@ -233,7 +233,7 @@ class ConvertGlobalToLocal(bpy.types.Operator):
|
||||
Data.map_conversion["Northings"],
|
||||
Data.map_conversion["OrthogonalHeight"],
|
||||
Data.map_conversion.get("XAxisAbscissa", 1.0),
|
||||
Data.map_conversion.get("XAxisAbscissa", 0.0),
|
||||
Data.map_conversion.get("XAxisOrdinate", 0.0),
|
||||
Data.map_conversion.get("Scale", 1.0),
|
||||
)
|
||||
props.coordinate_output = ",".join([str(r) for r in results])
|
||||
|
||||
@@ -35,3 +35,14 @@ class BIMGeoreferenceProperties(PropertyGroup):
|
||||
is_map_unit_null: BoolProperty(name="Is Map Unit Null")
|
||||
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")
|
||||
blender_x_axis_abscissa: StringProperty(name="Blender X Axis Abscissa", default="1")
|
||||
blender_x_axis_ordinate: StringProperty(name="Blender X Axis Ordinate", default="0")
|
||||
|
||||
@@ -21,7 +21,7 @@ class BIM_PT_gis(Panel):
|
||||
|
||||
if props.is_editing:
|
||||
return self.draw_editable_ui(context)
|
||||
self.draw_ui()
|
||||
self.draw_ui(context)
|
||||
|
||||
def draw_editable_ui(self, context):
|
||||
props = context.scene.BIMGeoreferenceProperties
|
||||
@@ -70,12 +70,40 @@ class BIM_PT_gis(Panel):
|
||||
row.prop(props, "map_unit_imperial", text="")
|
||||
row.prop(props, "is_map_unit_null", icon="RADIOBUT_OFF" if props.is_map_unit_null else "RADIOBUT_ON", text="")
|
||||
|
||||
def draw_ui(self):
|
||||
if not Data.map_conversion:
|
||||
def draw_ui(self, context):
|
||||
props = context.scene.BIMGeoreferenceProperties
|
||||
|
||||
if not Data.map_conversion and IfcStore.get_file().schema != "IFC2X3":
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Not Georeferenced")
|
||||
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)
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Northings")
|
||||
row.label(text=props.blender_northings)
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="OrthogonalHeight")
|
||||
row.label(text=props.blender_orthogonal_height)
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="XAxisAbscissa")
|
||||
row.label(text=props.blender_x_axis_abscissa)
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="XAxisOrdinate")
|
||||
row.label(text=props.blender_x_axis_ordinate)
|
||||
elif IfcStore.get_file().schema == "IFC2X3":
|
||||
row = self.layout.row()
|
||||
row.label(text="Not Georeferenced")
|
||||
|
||||
if Data.map_conversion:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Map Conversion", icon="GRID")
|
||||
|
||||
@@ -1036,10 +1036,6 @@ class BIMProperties(PropertyGroup):
|
||||
export_should_force_faceted_brep: BoolProperty(name="Export with Faceted Breps", default=False)
|
||||
export_should_force_triangulation: BoolProperty(name="Export with Triangulation", default=False)
|
||||
export_should_export_from_memory: BoolProperty(name="Export from Memory", default=True)
|
||||
import_should_ignore_site_coordinates: BoolProperty(name="Import Ignoring Site Coordinates", default=False)
|
||||
import_should_ignore_building_coordinates: BoolProperty(name="Import Ignoring Building Coordinates", default=False)
|
||||
import_should_reset_absolute_coordinates: BoolProperty(name="Import Resetting Absolute Coordinates", default=False)
|
||||
import_should_guess_georeferencing: BoolProperty(name="Import Guessing Georeferencing", default=False)
|
||||
import_should_import_type_representations: BoolProperty(name="Import Type Representations", default=False)
|
||||
import_should_import_curves: BoolProperty(name="Import Curves", default=False)
|
||||
import_should_import_opening_elements: BoolProperty(name="Import Opening Elements", default=False)
|
||||
|
||||
@@ -1015,11 +1015,6 @@ class BIM_PT_mvd(Panel):
|
||||
row = layout.row()
|
||||
row.prop(bim_properties, "export_should_force_triangulation")
|
||||
|
||||
layout.label(text="Tekla Workarounds:")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(bim_properties, "import_should_ignore_site_coordinates")
|
||||
|
||||
layout.label(text="ProStructures Workarounds:")
|
||||
|
||||
row = layout.row()
|
||||
@@ -1029,26 +1024,10 @@ class BIM_PT_mvd(Panel):
|
||||
row = layout.row()
|
||||
row.prop(bim_properties, "import_model_offset_coordinates")
|
||||
|
||||
layout.label(text="12D Workarounds:")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(bim_properties, "import_should_reset_absolute_coordinates")
|
||||
|
||||
layout.label(text="Civil 3D Workarounds:")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(bim_properties, "import_should_reset_absolute_coordinates")
|
||||
|
||||
layout.label(text="Revit Workarounds:")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(bim_properties, "export_should_use_presentation_style_assignment")
|
||||
row = layout.row()
|
||||
row.prop(bim_properties, "import_should_guess_georeferencing")
|
||||
row = layout.row()
|
||||
row.prop(bim_properties, "import_should_ignore_site_coordinates")
|
||||
row = layout.row()
|
||||
row.prop(bim_properties, "import_should_ignore_building_coordinates")
|
||||
|
||||
|
||||
class BIM_UL_generic(bpy.types.UIList):
|
||||
|
||||
Reference in New Issue
Block a user