mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 02:02:22 +00:00
Fix #7838: Fix slab layer direction and thickness offset
For IFC files exported from Revit, IfcMaterialLayerSetUsage may declare DirectionSense=POSITIVE while the IfcExtrudedAreaSolid extrudes in the negative direction. The layer slicing planes in loader.py, decoration.py, and operator.py now detect this by checking whether the mesh centroid is behind the starting plane, and flip the normal accordingly. The change_thickness function in slab.py was also overwriting the full extrusion position coordinates, discarding the XY profile origin encoded by Revit. It now decomposes the original position into components parallel and perpendicular to the layer normal, preserving the perpendicular (XY) component. Generated with the assistance of an AI coding tool.
This commit is contained in:
@@ -1898,6 +1898,13 @@ class CutDecorator:
|
||||
no = tool.Drawing.get_extrusion_vector(element).normalized()
|
||||
no = Vector([1.0, 0.0, 0.0])
|
||||
no *= sense_factor
|
||||
# Detect non-conformant exports (e.g. Revit) where DirectionSense=POSITIVE
|
||||
# but the geometry extrudes in the negative direction. If the mesh centroid
|
||||
# in object local space is on the wrong side of the starting plane, flip no.
|
||||
bb = [Vector(v) for v in obj.bound_box]
|
||||
mesh_centroid = sum(bb, Vector((0.0, 0.0, 0.0))) / 8
|
||||
if (mesh_centroid - co).dot(no) < 0:
|
||||
no = -no
|
||||
last_i = len(layer_set.MaterialLayers) - 1
|
||||
|
||||
vert_map = {}
|
||||
|
||||
@@ -729,6 +729,13 @@ class CreateDrawing(bpy.types.Operator):
|
||||
no = tool.Drawing.get_extrusion_vector(element).normalized()
|
||||
no = Vector([1.0, 0.0, 0.0])
|
||||
no *= sense_factor
|
||||
# Detect non-conformant exports (e.g. Revit) where DirectionSense=POSITIVE
|
||||
# but the geometry extrudes in the negative direction. If the mesh centroid
|
||||
# in object local space is on the wrong side of the starting plane, flip no.
|
||||
bb = [Vector(v) for v in obj.bound_box]
|
||||
mesh_centroid = sum(bb, Vector((0.0, 0.0, 0.0))) / 8
|
||||
if (mesh_centroid - co).dot(no) < 0:
|
||||
no = -no
|
||||
last_i = len(layer_set.MaterialLayers) - 1
|
||||
for i, layer in enumerate(layer_set.MaterialLayers):
|
||||
prev_co = co.copy()
|
||||
|
||||
@@ -248,7 +248,8 @@ class DumbSlabPlaner:
|
||||
|
||||
def change_thickness(self, element: ifcopenshell.entity_instance, thickness: float) -> None:
|
||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
if tool.Model.get_usage_type(element) != "LAYER3":
|
||||
usage_type = tool.Model.get_usage_type(element)
|
||||
if usage_type != "LAYER3":
|
||||
return
|
||||
layer_params = tool.Model.get_material_layer_parameters(element)
|
||||
ifc_file = tool.Ifc.get()
|
||||
@@ -304,11 +305,15 @@ class DumbSlabPlaner:
|
||||
ifc_position = extrusion.Position
|
||||
position = offset_direction * perpendicular_offset
|
||||
material = ifcopenshell.util.element.get_material(element)
|
||||
if material:
|
||||
if material.is_a("IfcMaterialLayerSetUsage"):
|
||||
material.OffsetFromReferenceLine = position.z
|
||||
if ifc_position:
|
||||
ifc_position.Location.Coordinates = position
|
||||
orig = Vector(ifc_position.Location.Coordinates)
|
||||
layer_normal = offset_direction.normalized()
|
||||
perp = orig - orig.dot(layer_normal) * layer_normal
|
||||
new_coords = perp + layer_normal * perpendicular_offset
|
||||
ifc_position.Location.Coordinates = new_coords
|
||||
if material:
|
||||
if material.is_a("IfcMaterialLayerSetUsage"):
|
||||
material.OffsetFromReferenceLine = new_coords.z
|
||||
else:
|
||||
tool.Model.add_extrusion_position(extrusion, position)
|
||||
|
||||
|
||||
@@ -1090,6 +1090,13 @@ class Loader(bonsai.core.tool.Loader):
|
||||
no = cls.get_extrusion_vector(element).normalized()
|
||||
no = Vector([1.0, 0.0, 0.0])
|
||||
no *= sense_factor
|
||||
# Detect non-conformant exports (e.g. Revit) where DirectionSense=POSITIVE
|
||||
# but the geometry extrudes in the negative direction. If the mesh centroid
|
||||
# in object local space is on the wrong side of the starting plane, flip no.
|
||||
if bm.verts:
|
||||
mesh_centroid = sum((v.co for v in bm.verts), Vector((0.0, 0.0, 0.0))) / len(bm.verts)
|
||||
if (mesh_centroid - co).dot(no) < 0:
|
||||
no = -no
|
||||
# Cache this
|
||||
body = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW")
|
||||
styles = {}
|
||||
|
||||
Reference in New Issue
Block a user