mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 18:16:40 +00:00
Derive pipe segment length through boolean-clipped bodies (#6761)
get_segment_length only handled a body whose single representation item is a bare IfcExtrudedAreaSolid. A miter bend or otherwise clipped pipe segment wraps that extrusion in an IfcBooleanClippingResult (an IfcBooleanResult), so the guard failed, the function returned None, and the Qto length (and thus the whole base-quantity set) came out empty while plain segments worked. Unwrap any IfcBooleanResult to its FirstOperand until the underlying extrusion is reached, then apply the existing depth logic. The length is still taken from the sweep Depth, matching a plain segment. Non-extrusion items after unwrapping still return None as before. Verified on the reported sample: the two booleaned IfcPipeSegment miter bends go from an empty Qto_PipeSegmentBaseQuantities to Length 5.05; a bare-extrusion segment is unchanged. Generated with the assistance of an AI coding tool. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+25
-18
@@ -398,27 +398,34 @@ class IfcOpenShell(QtoCalculator):
|
||||
or ``None`` if element doesn't have a representation or it's not supported.
|
||||
"""
|
||||
rep = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||
if rep and len(rep.Items or []) == 1 and rep.Items[0].is_a("IfcExtrudedAreaSolid"):
|
||||
if rep and len(rep.Items or []) == 1:
|
||||
item = rep.Items[0]
|
||||
if item.SweptArea.is_a("IfcRectangleProfileDef"):
|
||||
# Revit doesn't follow the +Z extrusion rule, so the rectangle isn't the cross section
|
||||
x = item.SweptArea.XDim
|
||||
y = item.SweptArea.YDim
|
||||
# Miter bends and other clipped segments wrap the swept solid in a
|
||||
# boolean result (e.g. IfcBooleanClippingResult with a half space).
|
||||
# Unwrap it to reach the underlying extrusion so the segment length
|
||||
# is still derived from the sweep depth, matching plain segments.
|
||||
while item.is_a("IfcBooleanResult"):
|
||||
item = item.FirstOperand
|
||||
if item.is_a("IfcExtrudedAreaSolid"):
|
||||
if item.SweptArea.is_a("IfcRectangleProfileDef"):
|
||||
# Revit doesn't follow the +Z extrusion rule, so the rectangle isn't the cross section
|
||||
x = item.SweptArea.XDim
|
||||
y = item.SweptArea.YDim
|
||||
z = item.Depth
|
||||
return max([x, y, z])
|
||||
elif item.SweptArea.is_a("IfcParameterizedProfileDef"):
|
||||
return item.Depth
|
||||
settings = ifcopenshell.geom.settings()
|
||||
settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS)
|
||||
try:
|
||||
area_shape = ifcopenshell.geom.create_shape(settings, item.SweptArea)
|
||||
except RuntimeError:
|
||||
return
|
||||
assert isinstance(area_shape, W.Triangulation)
|
||||
x = ifcopenshell.util.shape.get_x(area_shape) / cls.unit_scale
|
||||
y = ifcopenshell.util.shape.get_y(area_shape) / cls.unit_scale
|
||||
z = item.Depth
|
||||
return max([x, y, z])
|
||||
elif item.SweptArea.is_a("IfcParameterizedProfileDef"):
|
||||
return item.Depth
|
||||
settings = ifcopenshell.geom.settings()
|
||||
settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS)
|
||||
try:
|
||||
area_shape = ifcopenshell.geom.create_shape(settings, item.SweptArea)
|
||||
except RuntimeError:
|
||||
return
|
||||
assert isinstance(area_shape, W.Triangulation)
|
||||
x = ifcopenshell.util.shape.get_x(area_shape) / cls.unit_scale
|
||||
y = ifcopenshell.util.shape.get_y(area_shape) / cls.unit_scale
|
||||
z = item.Depth
|
||||
return max([x, y, z])
|
||||
|
||||
@classmethod
|
||||
def get_weight(
|
||||
|
||||
Reference in New Issue
Block a user