mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
Merge remote-tracking branch 'origin/v0.8.0' into tfk-rocksdb-storage
This commit is contained in:
@@ -60,7 +60,9 @@ from .create_segment_representations import create_segment_representations
|
||||
from .create_representation import create_representation
|
||||
from .distance_along_from_station import distance_along_from_station
|
||||
from .get_alignment import get_alignment
|
||||
from .get_alignment_station import get_alignment_station
|
||||
from .get_alignment_layout_nest import get_alignment_layout_nest
|
||||
from .get_alignment_segment_nest import get_alignment_segment_nest
|
||||
from .get_alignment_start_station import get_alignment_start_station
|
||||
from .get_curve_segment_transition_code import get_curve_segment_transition_code
|
||||
from .get_layout_segments import get_layout_segments
|
||||
from .get_horizontal_layout import get_horizontal_layout
|
||||
@@ -74,6 +76,7 @@ from .get_curve import get_curve
|
||||
from .get_layout_curve import get_layout_curve
|
||||
from .get_mapped_segments import get_mapped_segments
|
||||
from .get_parent_alignment import get_parent_alignment
|
||||
from .get_referent_nest import get_referent_nest
|
||||
from .has_zero_length_segment import has_zero_length_segment
|
||||
from .layout_horizontal_alignment_by_pi_method import layout_horizontal_alignment_by_pi_method
|
||||
from .layout_vertical_alignment_by_pi_method import layout_vertical_alignment_by_pi_method
|
||||
@@ -97,8 +100,10 @@ __all__ = [
|
||||
"create_segment_representations",
|
||||
"distance_along_from_station",
|
||||
"get_alignment",
|
||||
"get_alignment_layout_nest",
|
||||
"get_alignment_layouts",
|
||||
"get_alignment_station",
|
||||
"get_alignment_segment_nest",
|
||||
"get_alignment_start_station",
|
||||
"get_axis_subcontext",
|
||||
"get_basis_curve",
|
||||
"get_cant_layout",
|
||||
@@ -109,6 +114,7 @@ __all__ = [
|
||||
"get_layout_curve",
|
||||
"get_layout_segments",
|
||||
"get_parent_alignment",
|
||||
"get_referent_nest",
|
||||
"get_vertical_layout",
|
||||
"has_zero_length_segment",
|
||||
"layout_horizontal_alignment_by_pi_method",
|
||||
|
||||
@@ -60,132 +60,93 @@ def _add_segment_to_layout(file: ifcopenshell.file, layout: entity_instance, seg
|
||||
# swap the last two segments
|
||||
ifcopenshell.api.nest.reorder_nesting(file, segment, -1, -1)
|
||||
|
||||
# add the new segment to the geometric representation curve
|
||||
_add_segment_to_curve(file, segment, curve)
|
||||
if curve:
|
||||
# add the new segment to the geometric representation curve
|
||||
_add_segment_to_curve(file, segment, curve)
|
||||
|
||||
# gather information to:
|
||||
# (1) add a referent at the start of this segment
|
||||
# (2) update the name of the zero length segment's referent
|
||||
# gather information to:
|
||||
# (1) add a referent at the start of this segment
|
||||
# (2) update the name of the zero length segment's referent
|
||||
|
||||
# get the distance along the alignment to the start of the new segment
|
||||
dist_along = 0.0
|
||||
if layout.is_a("IfcAlignmentHorizontal"):
|
||||
for nest in layout.IsNestedBy:
|
||||
for seg in nest.RelatedObjects:
|
||||
if seg.is_a("IfcAlignmentSegment"):
|
||||
dist_along += seg.DesignParameters.SegmentLength
|
||||
# get the distance along the alignment to the start of the new segment
|
||||
dist_along = 0.0
|
||||
if layout.is_a("IfcAlignmentHorizontal"):
|
||||
for nest in layout.IsNestedBy:
|
||||
for seg in nest.RelatedObjects:
|
||||
if seg.is_a("IfcAlignmentSegment"):
|
||||
dist_along += seg.DesignParameters.SegmentLength
|
||||
|
||||
# the length of the current segment is in dist_along, so subtract it out
|
||||
dist_along -= segment.DesignParameters.SegmentLength
|
||||
else:
|
||||
dist_along = segment.DesignParameters.StartDistAlong
|
||||
|
||||
# get the station of the start of the segment
|
||||
alignment = ifcopenshell.api.alignment.get_alignment(layout)
|
||||
start_station = ifcopenshell.api.alignment.get_alignment_station(file, alignment)
|
||||
station = start_station + dist_along
|
||||
|
||||
# update the zero length layout segment
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(file)
|
||||
|
||||
zero_length_segment = layout.IsNestedBy[0].RelatedObjects[-1]
|
||||
# DesignParameters.StartPoint for IfcAlignmentHorizontalSegment is automatically updated when the
|
||||
# geometric representation is updated because the semantic and geometric data use the same IfcPoint.
|
||||
# This is not the case of IfcAlignmentVerticalSegment and IfcAlignmentCantSegment. For these
|
||||
# segment types, the design parameters of the zero length segment must be updated explicitly.
|
||||
if zero_length_segment.DesignParameters.is_a(
|
||||
"IfcAlignmentVerticalSegment"
|
||||
) or zero_length_segment.DesignParameters.is_a("IfcAlignmentCantSegment"):
|
||||
# get the geometric representation for the new segment
|
||||
mapped_segments = ifcopenshell.api.alignment.get_mapped_segments(segment)
|
||||
mapped_segment = mapped_segments[0] if mapped_segments[1] == None else mapped_segments[1]
|
||||
|
||||
# compute the end point matrix
|
||||
settings = ifcopenshell.geom.settings()
|
||||
segment_fn = ifcopenshell_wrapper.map_shape(settings, mapped_segment.wrapped_data)
|
||||
segment_evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, segment_fn)
|
||||
e = segment_evaluator.evaluate(segment_fn.end())
|
||||
end = np.array(e)
|
||||
|
||||
# update the zero length segment semantic representation parameters
|
||||
if zero_length_segment.DesignParameters.is_a("IfcAlignmentVerticalSegment"):
|
||||
y = float(end[1, 3]) / unit_scale
|
||||
zero_length_segment.DesignParameters.StartHeight = y
|
||||
dx = float(end[0, 0])
|
||||
dy = float(end[1, 0])
|
||||
zero_length_segment.DesignParameters.StartGradient = dy / dx
|
||||
zero_length_segment.DesignParameters.EndGradient = zero_length_segment.DesignParameters.StartGradient
|
||||
# the length of the current segment is in dist_along, so subtract it out
|
||||
dist_along -= segment.DesignParameters.SegmentLength
|
||||
else:
|
||||
z = float(end[2, 3]) / unit_scale
|
||||
dx = float(end[0, 1])
|
||||
dy = float(end[1, 1])
|
||||
dz = float(end[2, 1])
|
||||
ds = math.sqrt(dx * dx + dy * dy)
|
||||
slope = dz / ds
|
||||
railhead = layout.RailHeadDistance
|
||||
dist_along = segment.DesignParameters.StartDistAlong
|
||||
|
||||
zero_length_segment.DesignParameters.StartCantLeft = z + slope * railhead / 2.0
|
||||
zero_length_segment.DesignParameters.StartCantRight = z - slope * railhead / 2.0
|
||||
|
||||
# updated the referent's name because the referent is now at a new station
|
||||
start_dist_along = 0.0
|
||||
if segment.DesignParameters.is_a("IfcAlignmentHorizontalSegment"):
|
||||
start_dist_along = dist_along + segment.DesignParameters.SegmentLength
|
||||
else:
|
||||
start_dist_along = segment.DesignParameters.StartDistAlong + segment.DesignParameters.HorizontalLength
|
||||
zero_length_segment.DesignParameters.StartDistAlong = start_dist_along
|
||||
|
||||
end_referent = zero_length_segment.IsNestedBy[0].RelatedObjects[0]
|
||||
end_referent.Name = f"{_get_segment_start_point_label(zero_length_segment,None)} ({ifcopenshell.util.alignment.station_as_string(file,start_station+start_dist_along)})"
|
||||
|
||||
# update the referent's geometric representation's location
|
||||
end_referent.ObjectPlacement.RelativePlacement.Location.DistanceAlong.wrappedValue = start_dist_along
|
||||
settings = ifcopenshell.geom.settings()
|
||||
basis_curve = ifcopenshell.api.alignment.get_basis_curve(alignment)
|
||||
curve_fn = ifcopenshell_wrapper.map_shape(settings, basis_curve.wrapped_data)
|
||||
curve_evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, curve_fn)
|
||||
p = curve_evaluator.evaluate(start_dist_along * unit_scale)
|
||||
p = np.array(p)
|
||||
|
||||
x = float(p[0, 3]) / unit_scale
|
||||
y = float(p[1, 3]) / unit_scale
|
||||
z = float(p[2, 3]) / unit_scale
|
||||
|
||||
rx = float(p[0, 0])
|
||||
ry = float(p[1, 0])
|
||||
rz = float(p[2, 0])
|
||||
|
||||
ax = float(p[0, 2])
|
||||
ay = float(p[1, 2])
|
||||
az = float(p[2, 2])
|
||||
|
||||
end_referent.ObjectPlacement.CartesianPosition.Location.Coordinates = (x, y, z)
|
||||
end_referent.ObjectPlacement.CartesianPosition.Axis.DirectionRatios = (ax, ay, az)
|
||||
end_referent.ObjectPlacement.CartesianPosition.RefDirection.DirectionRatios = (rx, ry, rz)
|
||||
|
||||
start_station = ifcopenshell.api.alignment.get_alignment_station(file, alignment)
|
||||
end_referent_station = start_station + start_dist_along
|
||||
pset_stationing = ifcopenshell.api.pset.add_pset(file, product=end_referent, name="Pset_Stationing")
|
||||
ifcopenshell.api.pset.edit_pset(file, pset=pset_stationing, properties={"Station": end_referent_station})
|
||||
|
||||
# create the start of segment referent
|
||||
|
||||
# get the previous segment. Working from the end of the basis curve, -1 is zero length segment
|
||||
# -2 is the newly added segment, so -3 is the segment occuring just before the newly added segment
|
||||
prev_segment = layout.IsNestedBy[0].RelatedObjects[-3] if 2 < len(layout.IsNestedBy[0].RelatedObjects) else None
|
||||
name = f"{_get_segment_start_point_label(prev_segment,segment)} ({ifcopenshell.util.alignment.station_as_string(file,station)})"
|
||||
referent = ifcopenshell.api.alignment.add_stationing_referent(
|
||||
file, segment, distance_along=dist_along, station=station, name=name
|
||||
)
|
||||
|
||||
if len(curve.Segments) == 2 and layout.is_a("IfcAlignmentHorizontal"):
|
||||
# this is the first real segment in the horizontal alignment
|
||||
# update the location of the alignment's stationing referent
|
||||
# get the station of the start of the segment
|
||||
alignment = ifcopenshell.api.alignment.get_alignment(layout)
|
||||
stationing_referent = alignment.IsNestedBy[0].RelatedObjects[0]
|
||||
p = curve_evaluator.evaluate(
|
||||
stationing_referent.ObjectPlacement.RelativePlacement.Location.DistanceAlong.wrappedValue
|
||||
)
|
||||
start_station = ifcopenshell.api.alignment.get_alignment_start_station(file, alignment)
|
||||
station = start_station + dist_along
|
||||
|
||||
# update the zero length layout segment
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(file)
|
||||
|
||||
segment_nest = ifcopenshell.api.alignment.get_alignment_segment_nest(layout)
|
||||
zero_length_segment = segment_nest.RelatedObjects[-1]
|
||||
# DesignParameters.StartPoint for IfcAlignmentHorizontalSegment is automatically updated when the
|
||||
# geometric representation is updated because the semantic and geometric data use the same IfcPoint.
|
||||
# This is not the case of IfcAlignmentVerticalSegment and IfcAlignmentCantSegment. For these
|
||||
# segment types, the design parameters of the zero length segment must be updated explicitly.
|
||||
if zero_length_segment.DesignParameters.is_a(
|
||||
"IfcAlignmentVerticalSegment"
|
||||
) or zero_length_segment.DesignParameters.is_a("IfcAlignmentCantSegment"):
|
||||
# get the geometric representation for the new segment
|
||||
mapped_segments = ifcopenshell.api.alignment.get_mapped_segments(segment)
|
||||
mapped_segment = mapped_segments[0] if mapped_segments[1] == None else mapped_segments[1]
|
||||
|
||||
# compute the end point matrix
|
||||
settings = ifcopenshell.geom.settings()
|
||||
segment_fn = ifcopenshell_wrapper.map_shape(settings, mapped_segment.wrapped_data)
|
||||
segment_evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, segment_fn)
|
||||
e = segment_evaluator.evaluate(segment_fn.end())
|
||||
end = np.array(e)
|
||||
|
||||
# update the zero length segment semantic representation parameters
|
||||
if zero_length_segment.DesignParameters.is_a("IfcAlignmentVerticalSegment"):
|
||||
y = float(end[1, 3]) / unit_scale
|
||||
zero_length_segment.DesignParameters.StartHeight = y
|
||||
dx = float(end[0, 0])
|
||||
dy = float(end[1, 0])
|
||||
zero_length_segment.DesignParameters.StartGradient = dy / dx
|
||||
zero_length_segment.DesignParameters.EndGradient = zero_length_segment.DesignParameters.StartGradient
|
||||
else:
|
||||
z = float(end[2, 3]) / unit_scale
|
||||
dx = float(end[0, 1])
|
||||
dy = float(end[1, 1])
|
||||
dz = float(end[2, 1])
|
||||
ds = math.sqrt(dx * dx + dy * dy)
|
||||
slope = dz / ds
|
||||
railhead = layout.RailHeadDistance
|
||||
|
||||
zero_length_segment.DesignParameters.StartCantLeft = z + slope * railhead / 2.0
|
||||
zero_length_segment.DesignParameters.StartCantRight = z - slope * railhead / 2.0
|
||||
|
||||
# updated the referent's name because the referent is now at a new station
|
||||
start_dist_along = 0.0
|
||||
if segment.DesignParameters.is_a("IfcAlignmentHorizontalSegment"):
|
||||
start_dist_along = dist_along + segment.DesignParameters.SegmentLength
|
||||
else:
|
||||
start_dist_along = segment.DesignParameters.StartDistAlong + segment.DesignParameters.HorizontalLength
|
||||
zero_length_segment.DesignParameters.StartDistAlong = start_dist_along
|
||||
|
||||
end_referent = zero_length_segment.PositionedRelativeTo[0].RelatingPositioningElement
|
||||
end_referent.Name = f"{_get_segment_start_point_label(zero_length_segment,None)} ({ifcopenshell.util.alignment.station_as_string(file,start_station+start_dist_along)})"
|
||||
|
||||
# update the referent's geometric representation's location
|
||||
end_referent.ObjectPlacement.RelativePlacement.Location.DistanceAlong.wrappedValue = start_dist_along
|
||||
settings = ifcopenshell.geom.settings()
|
||||
basis_curve = ifcopenshell.api.alignment.get_basis_curve(alignment)
|
||||
curve_fn = ifcopenshell_wrapper.map_shape(settings, basis_curve.wrapped_data)
|
||||
curve_evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, curve_fn)
|
||||
p = curve_evaluator.evaluate(start_dist_along * unit_scale)
|
||||
p = np.array(p)
|
||||
|
||||
x = float(p[0, 3]) / unit_scale
|
||||
@@ -200,6 +161,48 @@ def _add_segment_to_layout(file: ifcopenshell.file, layout: entity_instance, seg
|
||||
ay = float(p[1, 2])
|
||||
az = float(p[2, 2])
|
||||
|
||||
stationing_referent.ObjectPlacement.CartesianPosition.Location.Coordinates = (x, y, z)
|
||||
stationing_referent.ObjectPlacement.CartesianPosition.Axis.DirectionRatios = (ax, ay, az)
|
||||
stationing_referent.ObjectPlacement.CartesianPosition.RefDirection.DirectionRatios = (rx, ry, rz)
|
||||
end_referent.ObjectPlacement.CartesianPosition.Location.Coordinates = (x, y, z)
|
||||
end_referent.ObjectPlacement.CartesianPosition.Axis.DirectionRatios = (ax, ay, az)
|
||||
end_referent.ObjectPlacement.CartesianPosition.RefDirection.DirectionRatios = (rx, ry, rz)
|
||||
|
||||
start_station = ifcopenshell.api.alignment.get_alignment_start_station(file, alignment)
|
||||
end_referent_station = start_station + start_dist_along
|
||||
pset_stationing = ifcopenshell.api.pset.add_pset(file, product=end_referent, name="Pset_Stationing")
|
||||
ifcopenshell.api.pset.edit_pset(file, pset=pset_stationing, properties={"Station": end_referent_station})
|
||||
|
||||
# create the start of segment referent
|
||||
|
||||
# get the previous segment. Working from the end of the basis curve, -1 is zero length segment
|
||||
# -2 is the newly added segment, so -3 is the segment occuring just before the newly added segment
|
||||
prev_segment = segment_nest.RelatedObjects[-3] if 2 < len(segment_nest.RelatedObjects) else None
|
||||
name = f"{_get_segment_start_point_label(prev_segment,segment)} ({ifcopenshell.util.alignment.station_as_string(file,station)})"
|
||||
referent = ifcopenshell.api.alignment.add_stationing_referent(
|
||||
file, alignment, distance_along=dist_along, station=station, name=name, positioned_product=segment
|
||||
)
|
||||
|
||||
if len(curve.Segments) == 2 and layout.is_a("IfcAlignmentHorizontal"):
|
||||
# this is the first real segment in the horizontal alignment
|
||||
# update the location of the alignment's stationing referent
|
||||
alignment = ifcopenshell.api.alignment.get_alignment(layout)
|
||||
ref_nest = ifcopenshell.api.alignment.get_referent_nest(file, alignment)
|
||||
stationing_referent = ref_nest.RelatedObjects[0]
|
||||
p = curve_evaluator.evaluate(
|
||||
stationing_referent.ObjectPlacement.RelativePlacement.Location.DistanceAlong.wrappedValue
|
||||
)
|
||||
p = np.array(p)
|
||||
|
||||
x = float(p[0, 3]) / unit_scale
|
||||
y = float(p[1, 3]) / unit_scale
|
||||
z = float(p[2, 3]) / unit_scale
|
||||
|
||||
rx = float(p[0, 0])
|
||||
ry = float(p[1, 0])
|
||||
rz = float(p[2, 0])
|
||||
|
||||
ax = float(p[0, 2])
|
||||
ay = float(p[1, 2])
|
||||
az = float(p[2, 2])
|
||||
|
||||
stationing_referent.ObjectPlacement.CartesianPosition.Location.Coordinates = (x, y, z)
|
||||
stationing_referent.ObjectPlacement.CartesianPosition.Axis.DirectionRatios = (ax, ay, az)
|
||||
stationing_referent.ObjectPlacement.CartesianPosition.RefDirection.DirectionRatios = (rx, ry, rz)
|
||||
|
||||
@@ -48,8 +48,9 @@ def _add_zero_length_segment(file: ifcopenshell.file, layout: entity_instance) -
|
||||
if curve:
|
||||
ifcopenshell.api.alignment.add_zero_length_segment(file, curve)
|
||||
|
||||
segment = layout.IsNestedBy[0].RelatedObjects[-1]
|
||||
alignment = ifcopenshell.api.alignment.get_alignment(layout)
|
||||
station = ifcopenshell.api.alignment.get_alignment_station(file, alignment)
|
||||
name = f"{_get_segment_start_point_label(segment,None)} ({ifcopenshell.util.alignment.station_as_string(file,station)})"
|
||||
ifcopenshell.api.alignment.add_stationing_referent(file, segment, 0.0, station, name=name)
|
||||
segment_nest = ifcopenshell.api.alignment.get_alignment_segment_nest(layout)
|
||||
segment = segment_nest.RelatedObjects[-1]
|
||||
alignment = ifcopenshell.api.alignment.get_alignment(layout)
|
||||
station = ifcopenshell.api.alignment.get_alignment_start_station(file, alignment)
|
||||
name = f"{_get_segment_start_point_label(segment,None)} ({ifcopenshell.util.alignment.station_as_string(file,station)})"
|
||||
referent = ifcopenshell.api.alignment.add_stationing_referent(file, alignment, 0.0, station, name, segment)
|
||||
|
||||
@@ -30,19 +30,20 @@ import numpy as np
|
||||
|
||||
def add_stationing_referent(
|
||||
file: ifcopenshell.file,
|
||||
element: entity_instance,
|
||||
alignment: entity_instance,
|
||||
distance_along: float,
|
||||
station: float,
|
||||
name: str,
|
||||
positioned_product: entity_instance,
|
||||
) -> entity_instance:
|
||||
"""
|
||||
Adds an IfcReferent to the element with the Pset_Stationing property set.
|
||||
If element is an IfcAlignment, IfcReferent.PredefinedType is set to "STATION", otherwise "POSITION"
|
||||
Adds an IfcReferent to the alignment with the Pset_Stationing property set.
|
||||
|
||||
:param element: the element to receive the referent, expected to be an IfcAlignment or IfcAlignmentSegment
|
||||
:param distance_along: distance along the alignment curve
|
||||
:param alignment: the alignment to receive the referent
|
||||
:param distance_along: distance along the alignment basis curve
|
||||
:param station: station value
|
||||
:param name: name to assign to IfcReferent.Name, typically a stringized version of the station value
|
||||
:param positioned_product: the product whose position is informed by the referent
|
||||
:return: referent
|
||||
|
||||
Example:
|
||||
@@ -50,13 +51,8 @@ def add_stationing_referent(
|
||||
.. code:: python
|
||||
|
||||
alignment = model.by_type("IfcAlignment")[0]
|
||||
ifcopenshell.api.alignment.add_stationing_referent(model,entity=alignment,distance_along=0.0,station=100.0)
|
||||
ifcopenshell.api.alignment.add_stationing_referent(model,alignment=alignment,distance_along=0.0,station=100.0)
|
||||
"""
|
||||
alignment = element
|
||||
|
||||
if element.is_a("IfcAlignmentSegment"):
|
||||
layout = element.Nests[0].RelatingObject
|
||||
alignment = ifcopenshell.api.alignment.get_alignment(layout)
|
||||
|
||||
basis_curve = ifcopenshell.api.alignment.get_basis_curve(alignment)
|
||||
|
||||
@@ -76,6 +72,8 @@ def add_stationing_referent(
|
||||
)
|
||||
|
||||
is_valid_curve = True
|
||||
if basis_curve.is_a("IfcCompositeCurve") and len(basis_curve.Segments) == 0:
|
||||
is_valid_curve = False
|
||||
if basis_curve.is_a("IfcPolyline") and len(basis_curve.Points) < 2:
|
||||
is_valid_curve = False
|
||||
elif basis_curve.is_a("IfcIndexedPolyCurve") and len(basis_curve.Points.CoordList) < 2:
|
||||
@@ -91,6 +89,7 @@ def add_stationing_referent(
|
||||
fn = ifcopenshell_wrapper.convert_loop_to_function_item(fn)
|
||||
|
||||
evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, fn)
|
||||
|
||||
p = evaluator.evaluate(distance_along * unit_scale)
|
||||
p = np.array(p)
|
||||
|
||||
@@ -105,12 +104,23 @@ def add_stationing_referent(
|
||||
ax = float(p[0, 2])
|
||||
ay = float(p[1, 2])
|
||||
az = float(p[2, 2])
|
||||
else:
|
||||
x = 0.0
|
||||
y = 0.0
|
||||
z = 0.0
|
||||
rx = 1.0
|
||||
ry = 0.0
|
||||
rz = 0.0
|
||||
ax = 0.0
|
||||
ay = 0.0
|
||||
az = 1.0
|
||||
|
||||
object_placement.CartesianPosition = file.createIfcAxis2Placement3D(
|
||||
Location=file.createIfcCartesianPoint((x, y, z)),
|
||||
Axis=file.createIfcDirection((ax, ay, az)),
|
||||
RefDirection=file.createIfcDirection((rx, ry, rz)),
|
||||
)
|
||||
|
||||
object_placement.CartesianPosition = file.createIfcAxis2Placement3D(
|
||||
Location=file.createIfcCartesianPoint((x, y, z)),
|
||||
Axis=file.createIfcDirection((ax, ay, az)),
|
||||
RefDirection=file.createIfcDirection((rx, ry, rz)),
|
||||
)
|
||||
# this commented out code is what you would do to add a geometric representation of the referent
|
||||
# the example is a circle. a better way would be to pass a representation into the function
|
||||
# representation = file.create_entity(
|
||||
@@ -120,7 +130,6 @@ def add_stationing_referent(
|
||||
# )
|
||||
|
||||
# create referent for the station
|
||||
predefined_type = "STATION" if element.is_a("IfcAlignment") else "POSITION"
|
||||
referent = file.createIfcReferent(
|
||||
GlobalId=ifcopenshell.guid.new(),
|
||||
OwnerHistory=None,
|
||||
@@ -129,21 +138,27 @@ def add_stationing_referent(
|
||||
ObjectType=None,
|
||||
ObjectPlacement=object_placement,
|
||||
Representation=representation,
|
||||
PredefinedType=predefined_type,
|
||||
PredefinedType="STATION",
|
||||
)
|
||||
pset_stationing = ifcopenshell.api.pset.add_pset(file, product=referent, name="Pset_Stationing")
|
||||
ifcopenshell.api.pset.edit_pset(file, pset=pset_stationing, properties={"Station": station})
|
||||
ifcopenshell.api.nest.assign_object(file, related_objects=[referent], relating_object=element)
|
||||
|
||||
if len(alignment.Positions) == 0:
|
||||
nest = ifcopenshell.api.alignment.get_referent_nest(file, alignment)
|
||||
nest.RelatedObjects += (referent,)
|
||||
|
||||
nest.RelatedObjects = sorted(
|
||||
nest.RelatedObjects, key=lambda x: ifcopenshell.util.element.get_pset(x, name="Pset_Stationing", prop="Station")
|
||||
)
|
||||
|
||||
if len(referent.Positions) == 0:
|
||||
rel_positions = file.createIfcRelPositions(
|
||||
GlobalId=ifcopenshell.guid.new(),
|
||||
RelatingPositioningElement=alignment,
|
||||
RelatingPositioningElement=referent,
|
||||
RelatedProducts=[
|
||||
referent,
|
||||
positioned_product,
|
||||
],
|
||||
)
|
||||
else:
|
||||
alignment.Positions[0].RelatedProducts += (referent,)
|
||||
referent.Positions[0].RelatedProducts += (positioned_product,)
|
||||
|
||||
return referent
|
||||
|
||||
@@ -50,9 +50,21 @@ def _move_vertical_layout_to_child_alignment(
|
||||
# nest the vertical layout onto the child alignment
|
||||
ifcopenshell.api.nest.assign_object(file, related_objects=[vertical_layout], relating_object=child_alignment)
|
||||
|
||||
# aggreage the child alignment to the parent alignment
|
||||
# aggregate the child alignment to the parent alignment
|
||||
ifcopenshell.api.aggregate.assign_object(file, products=[child_alignment], relating_object=parent_alignment)
|
||||
|
||||
# move all referents positioning segments of the vertical layout to the referent nest of the child alignment
|
||||
child_referent_nest = ifcopenshell.api.alignment.get_referent_nest(file, child_alignment)
|
||||
parent_referent_nest = ifcopenshell.api.alignment.get_referent_nest(file, parent_alignment)
|
||||
for referent in parent_referent_nest.RelatedObjects:
|
||||
for product in referent.Positions[0].RelatedProducts:
|
||||
if product.is_a("IfcAlignmentSegment") and product.Nests[0].RelatingObject == vertical_layout:
|
||||
# ifcopenshell.api.nest.change_nest(file,referent,child_alignment) - this doesn't work because referent is assigned to child_alignment.IsNestedBy[0].RelatedObjects
|
||||
# and it needs to be assigned to child_alignment.IsNestedBy[1].RelatedObjects
|
||||
# move the referent manually - unassign it and add it to the child alignment's referent nest
|
||||
ifcopenshell.api.nest.unassign_object(file, [referent])
|
||||
child_referent_nest.RelatedObjects += (referent,)
|
||||
|
||||
# if the parent alignment has a representation, move the Axis/Curve3D represention to the child alignment
|
||||
base_curve = ifcopenshell.api.alignment.get_basis_curve(parent_alignment)
|
||||
if base_curve:
|
||||
|
||||
@@ -231,8 +231,11 @@ def add_zero_length_segment(file: ifcopenshell.file, layout: entity_instance, in
|
||||
|
||||
if include_referent:
|
||||
alignment = ifcopenshell.api.alignment.get_alignment(layout)
|
||||
station = ifcopenshell.api.alignment.get_alignment_station(file, alignment)
|
||||
station = ifcopenshell.api.alignment.get_alignment_start_station(file, alignment)
|
||||
name = f"{_get_segment_start_point_label(zero_length_curve_segment,None)} ({ifcopenshell.util.alignment.station_as_string(file,station)})"
|
||||
ifcopenshell.api.alignment.add_stationing_referent(file, zero_length_curve_segment, 0.0, station, name=name)
|
||||
referent = ifcopenshell.api.alignment.add_stationing_referent(
|
||||
file, alignment, 0.0, station, name, zero_length_curve_segment
|
||||
)
|
||||
referent.Description = f"Positions zero length segment {zero_length_curve_segment.id()}"
|
||||
|
||||
return True
|
||||
|
||||
@@ -33,27 +33,31 @@ def create(
|
||||
name: str,
|
||||
include_vertical: bool = False,
|
||||
include_cant: bool = False,
|
||||
include_geometry: bool = True,
|
||||
start_station: float = 0.0,
|
||||
) -> entity_instance:
|
||||
"""
|
||||
Creates a new IfcAlignment with an IfcRelNests nesting an IfcReferent (for stationing) and IfcAlignmentHorizontal. The nest relationship can optionally
|
||||
include IfcAlignmentVertical and IfcAlignmentCant. Geometric representations for the alignment layouts (IfcCompositeCurve,
|
||||
IfcGradientCurve, IfcSegmentedReferenceCurve) are created as well.
|
||||
Creates a new alignment with a horizontal layout. Optionally, vertical and cant layouts can be created as well.
|
||||
The geometric representations are created as well, unless they are explicitly excluded.
|
||||
Zero length segments are added at the end of the layouts and geometric representations.
|
||||
The alignment is automatically aggreated to the project if it exists.
|
||||
|
||||
Zero length segments are added at the end.
|
||||
Use get_horizontal_layout(alignment), get_vertical_layout(alignment) and get_cant_layout(alignment) to get the
|
||||
corresponding IfcAlignmentHorizontal, IfcAlignmentVertical, and IfcAlignmentCant layout entities.
|
||||
|
||||
The IfcAlignment is aggreated to IfcProject
|
||||
If the alignment has Viennese Bend transition curves, create the segments in the cant layout before the horizontal layout using create_layout_segment().
|
||||
The horizontal geometry in the Viennese Bend transition curves depends on the Viennese Bend cant parameters. create_layout_segment() automatically creates
|
||||
the geometric representation from the semantic definition. The horizontal segment geometric representation will fail if the cant segment is not defined.
|
||||
|
||||
Use get_horizontal_layout(alignment) to get the IfcAlignmentHorizontal layout.
|
||||
|
||||
If the alignment has Viennese Bend transition curves, create the cant layout before the horizontal layout. This is because the horizontal layout
|
||||
in the Viennese Bend transition curves depends on the Viennese Bend cant parameters.
|
||||
If geometric representations are created, the alignment stationing referent is also created using the start_station value. IfcReferent.ObjectPlacement
|
||||
is required for linear positiion elements and IfcLinearPlacement is defined relative to alignment curve geometry.
|
||||
|
||||
:param file:
|
||||
:param name: name assigned to IfcAlignment.Name
|
||||
:param include_vertical: If True, IfcAlignmentVertical and IfcGradientCurve are created
|
||||
:param include_cant: If True, IfcAlignmentCant and IfcSegmentedReferenceCurve are created
|
||||
:param start_station: station value at the start of the alignment
|
||||
:param include_vertical: If True, IfcAlignmentVertical is created. IfcGradientCurve is created if include_geometry is True
|
||||
:param include_cant: If True, IfcAlignmentCant is created. IfcSegmentedReferenceCurve is created if include_geometry is True
|
||||
:param include_geometry: If True, the geometric representations are added
|
||||
:param start_station: station value at the start of the alignment.
|
||||
:return: Returns an IfcAlignment
|
||||
"""
|
||||
alignment = file.createIfcAlignment(
|
||||
@@ -73,16 +77,17 @@ def create(
|
||||
|
||||
ifcopenshell.api.nest.assign_object(file, related_objects=alignment_layouts, relating_object=alignment)
|
||||
|
||||
_create_geometric_representation(file, alignment)
|
||||
if include_geometry:
|
||||
_create_geometric_representation(file, alignment)
|
||||
|
||||
name = ifcopenshell.util.alignment.station_as_string(file, start_station)
|
||||
referent = ifcopenshell.api.alignment.add_stationing_referent(
|
||||
file, alignment, 0.0, start_station, name, alignment
|
||||
)
|
||||
|
||||
for layout in alignment_layouts:
|
||||
_add_zero_length_segment(file, layout)
|
||||
|
||||
# define stationing
|
||||
name = ifcopenshell.util.alignment.station_as_string(file, start_station)
|
||||
referent = ifcopenshell.api.alignment.add_stationing_referent(file, alignment, 0.0, start_station, name)
|
||||
ifcopenshell.api.nest.reorder_nesting(file, referent, -1, 0)
|
||||
|
||||
# IFC 4.1.4.1.1 Alignment Aggregation To Project
|
||||
project = file.by_type("IfcProject")[0]
|
||||
if project:
|
||||
|
||||
@@ -53,11 +53,6 @@ def create_as_offset_curve(
|
||||
|
||||
_create_offset_curve_representation(file, alignment, offsets)
|
||||
|
||||
# define stationing
|
||||
# name = ifcopenshell.util.alignment.station_as_string(file, start_station)
|
||||
# referent = ifcopenshell.api.alignment.add_stationing_referent(file, alignment, 0.0, start_station, name)
|
||||
# ifcopenshell.api.nest.reorder_nesting(file, referent, -1, 0)
|
||||
|
||||
# IFC 4.1.4.1.1 Alignment Aggregation To Project
|
||||
project = file.by_type("IfcProject")[0]
|
||||
if project:
|
||||
|
||||
@@ -137,14 +137,11 @@ def create_as_polyline(
|
||||
Name=name,
|
||||
)
|
||||
|
||||
# _create_layout(file,alignment,points)
|
||||
|
||||
_create_polyline_representation(file, alignment, points)
|
||||
|
||||
# define stationing
|
||||
name = ifcopenshell.util.alignment.station_as_string(file, start_station)
|
||||
referent = ifcopenshell.api.alignment.add_stationing_referent(file, alignment, 0.0, start_station, name)
|
||||
ifcopenshell.api.nest.reorder_nesting(file, referent, -1, 0)
|
||||
referent = ifcopenshell.api.alignment.add_stationing_referent(file, alignment, 0.0, start_station, name, alignment)
|
||||
|
||||
# IFC 4.1.4.1.1 Alignment Aggregation To Project
|
||||
project = file.by_type("IfcProject")[0]
|
||||
|
||||
@@ -23,20 +23,21 @@ from ifcopenshell import entity_instance
|
||||
import math
|
||||
from ifcopenshell import ifcopenshell_wrapper
|
||||
import numpy as np
|
||||
from typing import Union
|
||||
|
||||
from ifcopenshell.api.alignment._add_segment_to_layout import _add_segment_to_layout
|
||||
|
||||
|
||||
def create_layout_segment(
|
||||
file: ifcopenshell.file, layout: entity_instance, design_parameters: entity_instance
|
||||
) -> np.array:
|
||||
) -> Union[np.array, None]:
|
||||
"""
|
||||
Creates a new IfcAlignmentSegment using the IfcAlignmentParameterSegment design parameters.
|
||||
The new segment is appended to the layout alignment and the corresponding IfcCurveSegment is created in the geometric representation
|
||||
The new segment is appended to the layout alignment and the corresponding IfcCurveSegment is created in the geometric representation if it exists.
|
||||
|
||||
:param layout: The layout to receive the new layout segment. This parameter is expected to be IfcAlignmentHorizontal, IfcAlignmentVertical or IfcAlignmentCant
|
||||
:param design_parameters: The parameters defining the segment. Expected to be the appropreate subclass of IfcAlignmentParameterSegment
|
||||
:return: 4x4 matrix at end of segment as np.array intended to be used as the start point geometry for the next segment.
|
||||
:return: 4x4 matrix at end of segment as np.array intended to be used as the start point geometry for the next segment or None if there is the geometric representation is not defined.
|
||||
"""
|
||||
expected_types = ["IfcAlignmentHorizontal", "IfcAlignmentVertical", "IfcAlignmentCant"]
|
||||
if not layout.is_a() in expected_types:
|
||||
@@ -60,25 +61,28 @@ def create_layout_segment(
|
||||
alignment = ifcopenshell.api.alignment.get_alignment(layout)
|
||||
curve = ifcopenshell.api.alignment.get_curve(alignment)
|
||||
|
||||
if layout.is_a("IfcAlignmentHorizontal"):
|
||||
if curve.is_a("IfcGradientCurve"):
|
||||
curve = curve.BaseCurve
|
||||
elif curve.is_a("IfcSegmentedReferenceCurve"):
|
||||
curve = (
|
||||
curve.BaseCurve.BaseCurve
|
||||
) # layout is horizontal and curve is segmented ref ... we want the curve's base curve
|
||||
elif layout.is_a("IfcAlignmentVertical"):
|
||||
if curve.is_a("IfcSegmentedReferenceCurve"):
|
||||
curve = curve.BaseCurve
|
||||
if curve:
|
||||
if layout.is_a("IfcAlignmentHorizontal"):
|
||||
if curve.is_a("IfcGradientCurve"):
|
||||
curve = curve.BaseCurve
|
||||
elif curve.is_a("IfcSegmentedReferenceCurve"):
|
||||
curve = (
|
||||
curve.BaseCurve.BaseCurve
|
||||
) # layout is horizontal and curve is segmented ref ... we want the curve's base curve
|
||||
elif layout.is_a("IfcAlignmentVertical"):
|
||||
if curve.is_a("IfcSegmentedReferenceCurve"):
|
||||
curve = curve.BaseCurve
|
||||
|
||||
# the new segment is two from the end... the end segment is zero length
|
||||
curve_segment = curve.Segments[-2]
|
||||
# the new segment is two from the end... the end segment is zero length
|
||||
curve_segment = curve.Segments[-2]
|
||||
|
||||
settings = ifcopenshell.geom.settings()
|
||||
settings = ifcopenshell.geom.settings()
|
||||
|
||||
segment_fn = ifcopenshell_wrapper.map_shape(settings, curve_segment.wrapped_data)
|
||||
segment_evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, segment_fn)
|
||||
e = segment_evaluator.evaluate(segment_fn.end())
|
||||
end = np.array(e)
|
||||
segment_fn = ifcopenshell_wrapper.map_shape(settings, curve_segment.wrapped_data)
|
||||
segment_evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, segment_fn)
|
||||
e = segment_evaluator.evaluate(segment_fn.end())
|
||||
end = np.array(e)
|
||||
|
||||
return end
|
||||
return end
|
||||
else:
|
||||
return None
|
||||
|
||||
@@ -50,5 +50,6 @@ def create_representation(
|
||||
layouts = ifcopenshell.api.alignment.get_alignment_layouts(alignment)
|
||||
for layout in layouts:
|
||||
curve = ifcopenshell.api.alignment.get_layout_curve(layout)
|
||||
for segment in layout.IsNestedBy[0].RelatedObjects:
|
||||
layout_nest = ifcopenshell.api.alignment.get_alignment_segment_nest(layout)
|
||||
for segment in layout_nest.RelatedObjects:
|
||||
_add_segment_to_curve(file, segment, curve)
|
||||
|
||||
@@ -43,6 +43,6 @@ def distance_along_from_station(file: ifcopenshell.file, alignment: entity_insta
|
||||
print(dist_along) # 100.00
|
||||
"""
|
||||
|
||||
start_station = ifcopenshell.api.alignment.get_alignment_station(file, alignment)
|
||||
start_station = ifcopenshell.api.alignment.get_alignment_start_station(file, alignment)
|
||||
dist_along = station - start_station
|
||||
return dist_along
|
||||
|
||||
@@ -16,16 +16,17 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util
|
||||
from ifcopenshell import entity_instance
|
||||
from collections.abc import Sequence
|
||||
|
||||
import ifcopenshell.util.representation
|
||||
|
||||
|
||||
def get_alignment(layout: entity_instance) -> entity_instance:
|
||||
"""
|
||||
Returns the alignment that nests this layout
|
||||
"""
|
||||
return layout.Nests[0].RelatingObject if 0 < len(layout.Nests) else None
|
||||
alignment = None
|
||||
for nest in layout.Nests:
|
||||
if nest.RelatingObject.is_a("IfcAlignment"):
|
||||
alignment = nest.RelatingObject
|
||||
break
|
||||
|
||||
return alignment
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# IfcOpenShell - IFC toolkit and geometry engine
|
||||
# Copyright (C) 2025 Thomas Krijnen <thomas@aecgeeks.com>
|
||||
#
|
||||
# This file is part of IfcOpenShell.
|
||||
#
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# IfcOpenShell is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
|
||||
def get_alignment_layout_nest(alignment: entity_instance) -> entity_instance:
|
||||
"""
|
||||
Searches for the IfcRelNest that contains IfcAlignmentHorizontal, IfcAlignmentVertical, or IfcAlignmentCant
|
||||
|
||||
:param alignment: the alignment
|
||||
:return: Returns the IfcRelNests containing the alignment layout
|
||||
"""
|
||||
layout_types = ["IfcAlignmentHorizontal", "IfcAlignmentVertical", "IfcAlignmentCant"]
|
||||
|
||||
for nest in alignment.IsNestedBy:
|
||||
for related_object in nest.RelatedObjects:
|
||||
if related_object.is_a() in layout_types:
|
||||
return nest
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,34 @@
|
||||
# IfcOpenShell - IFC toolkit and geometry engine
|
||||
# Copyright (C) 2025 Thomas Krijnen <thomas@aecgeeks.com>
|
||||
#
|
||||
# This file is part of IfcOpenShell.
|
||||
#
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# IfcOpenShell is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
|
||||
def get_alignment_segment_nest(layout: entity_instance) -> entity_instance:
|
||||
"""
|
||||
Searches for the IfcRelNest that contains IfcAlignmentSegment
|
||||
|
||||
:param layout: an alignment layout, expected to be one of IfcAlignmentHorizontal, IfcAlignmentVertical, or IfcAlignmentCant
|
||||
:return: Returns the IfcRelNests
|
||||
"""
|
||||
for nest in layout.IsNestedBy:
|
||||
for related_object in nest.RelatedObjects:
|
||||
if related_object.is_a("IfcAlignmentSegment"):
|
||||
return nest
|
||||
return None
|
||||
+8
-7
@@ -22,11 +22,11 @@ import ifcopenshell.util.element
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
|
||||
def get_alignment_station(file: ifcopenshell.file, alignment: entity_instance) -> float:
|
||||
def get_alignment_start_station(file: ifcopenshell.file, alignment: entity_instance) -> float:
|
||||
"""
|
||||
Returns the start station of the alignment. If the alignment is nested by an IfcReferent
|
||||
the referent is checked for PredefinedType of STATION and an occurance of Pset_Stationing.Station,
|
||||
otherwise start station is taken to be 0.0.
|
||||
Returns the start station of the alignment. The starting station is defined by the first nested IfcReferent.
|
||||
This is interpreted to mean the first IfcReferent with an occurance of Pset_Stationing.Station,
|
||||
otherwise returns 0.0.
|
||||
"""
|
||||
|
||||
if not alignment.is_a("IfcAlignment"):
|
||||
@@ -36,12 +36,13 @@ def get_alignment_station(file: ifcopenshell.file, alignment: entity_instance) -
|
||||
|
||||
parent_alignment = ifcopenshell.api.alignment.get_parent_alignment(alignment)
|
||||
if parent_alignment:
|
||||
start_station = ifcopenshell.api.alignment.get_alignment_station(file, parent_alignment)
|
||||
start_station = ifcopenshell.api.alignment.get_alignment_start_station(file, parent_alignment)
|
||||
else:
|
||||
components = ifcopenshell.util.element.get_components(alignment)
|
||||
for c in components:
|
||||
if c.is_a("IfcReferent") and ifcopenshell.util.element.get_predefined_type(c) == "STATION":
|
||||
if c.is_a("IfcReferent"):
|
||||
start_station = ifcopenshell.util.element.get_pset(c, name="Pset_Stationing", prop="Station")
|
||||
break
|
||||
if not start_station == None:
|
||||
break
|
||||
|
||||
return start_station
|
||||
@@ -0,0 +1,40 @@
|
||||
# IfcOpenShell - IFC toolkit and geometry engine
|
||||
# Copyright (C) 2025 Thomas Krijnen <thomas@aecgeeks.com>
|
||||
#
|
||||
# This file is part of IfcOpenShell.
|
||||
#
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# IfcOpenShell is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
|
||||
def get_referent_nest(file: ifcopenshell.file, alignment: entity_instance) -> entity_instance:
|
||||
"""
|
||||
Searches for the IfcRelNest that contains IfcReferent. If one is not found, a empty IfcRelNests is created.
|
||||
|
||||
:param file:
|
||||
:param alignment: The IfcAlignment which hosts IfcReferent
|
||||
:return: Returns the IfcRelNests.
|
||||
"""
|
||||
if not alignment.is_a("IfcAlignment"):
|
||||
raise TypeError(f"Expected IfcAlignment, instead received {alignment.is_a()}")
|
||||
|
||||
for nest in alignment.IsNestedBy:
|
||||
for related_object in nest.RelatedObjects:
|
||||
if related_object.is_a("IfcReferent"):
|
||||
return nest
|
||||
|
||||
nest = file.createIfcRelNests(GlobalId=ifcopenshell.guid.new(), RelatingObject=alignment, RelatedObjects=[])
|
||||
return nest
|
||||
@@ -162,3 +162,12 @@ def print_composite_curve_deep(curve):
|
||||
print(" " * 4, segment.Placement)
|
||||
print(" " * 4, segment.Placement.Location)
|
||||
print(" " * 4, segment.Placement.RefDirection)
|
||||
|
||||
|
||||
def print_positioned_products(file: ifcopenshell.file):
|
||||
referents = file.by_type("IfcReferent")
|
||||
for referent in referents:
|
||||
print(referent)
|
||||
for rel in referent.Positions:
|
||||
for product in rel.RelatedProducts:
|
||||
print(" " * 2, product)
|
||||
|
||||
Reference in New Issue
Block a user