mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-25 04:44:37 +00:00
Fixed zero length segment for vertical alignment. Refactors curve segment transition code
This commit is contained in:
+4
-3
@@ -143,6 +143,9 @@ def _map_circular_arc(file: ifcopenshell.file, design_parameters: entity_instanc
|
|||||||
end_angle = math.atan(end_gradient)
|
end_angle = math.atan(end_gradient)
|
||||||
dx = math.cos(start_angle)
|
dx = math.cos(start_angle)
|
||||||
dy = math.sin(start_angle)
|
dy = math.sin(start_angle)
|
||||||
|
|
||||||
|
# start and end angles are for the curve tangents
|
||||||
|
# convert them to be angles of the radii lines
|
||||||
if start_angle < end_angle:
|
if start_angle < end_angle:
|
||||||
radius = horizontal_length / (math.sin(end_angle) - math.sin(start_angle))
|
radius = horizontal_length / (math.sin(end_angle) - math.sin(start_angle))
|
||||||
x = -radius * math.sin(start_angle)
|
x = -radius * math.sin(start_angle)
|
||||||
@@ -158,14 +161,12 @@ def _map_circular_arc(file: ifcopenshell.file, design_parameters: entity_instanc
|
|||||||
|
|
||||||
parent_curve = file.createIfcCircle(
|
parent_curve = file.createIfcCircle(
|
||||||
Position=file.createIfcAxis2Placement2D(
|
Position=file.createIfcAxis2Placement2D(
|
||||||
Location=file.createIfcCartesianPoint((0.0, 0.0)),
|
Location=file.createIfcCartesianPoint((x, y)),
|
||||||
RefDirection=file.createIfcDirection((1.0, 0.0)),
|
RefDirection=file.createIfcDirection((1.0, 0.0)),
|
||||||
),
|
),
|
||||||
Radius=radius,
|
Radius=radius,
|
||||||
)
|
)
|
||||||
|
|
||||||
segment_curve_length = radius * math.fabs(end_angle - start_angle)
|
|
||||||
|
|
||||||
curve_segment = file.create_entity(
|
curve_segment = file.create_entity(
|
||||||
type="IfcCurveSegment",
|
type="IfcCurveSegment",
|
||||||
Transition=transition,
|
Transition=transition,
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import math
|
|||||||
|
|
||||||
from ifcopenshell.api.alignment._get_segment_start_point_label import _get_segment_start_point_label
|
from ifcopenshell.api.alignment._get_segment_start_point_label import _get_segment_start_point_label
|
||||||
from ifcopenshell.api.alignment._map_alignment_horizontal_segment import _map_alignment_horizontal_segment
|
from ifcopenshell.api.alignment._map_alignment_horizontal_segment import _map_alignment_horizontal_segment
|
||||||
|
from ifcopenshell.api.alignment._map_alignment_vertical_segment import _map_alignment_vertical_segment
|
||||||
from ifcopenshell.api.alignment._update_curve_segment_transition_code import _update_curve_segment_transition_code
|
from ifcopenshell.api.alignment._update_curve_segment_transition_code import _update_curve_segment_transition_code
|
||||||
|
|
||||||
|
|
||||||
@@ -157,20 +158,35 @@ def add_zero_length_segment(file: ifcopenshell.file, layout: entity_instance, in
|
|||||||
)
|
)
|
||||||
elif layout.is_a("IfcAlignmentVertical"):
|
elif layout.is_a("IfcAlignmentVertical"):
|
||||||
last_segment_dist_along = 0.0
|
last_segment_dist_along = 0.0
|
||||||
|
last_segment_height = 0.0
|
||||||
last_segment_end_gradient = 0.0
|
last_segment_end_gradient = 0.0
|
||||||
|
last_segment = None
|
||||||
for rel in layout.IsNestedBy:
|
for rel in layout.IsNestedBy:
|
||||||
if 0 < len(rel.RelatedObjects):
|
if 0 < len(rel.RelatedObjects):
|
||||||
last_segment = rel.RelatedObjects[-1]
|
last_segment = rel.RelatedObjects[-1]
|
||||||
last_segment_dist_along = (
|
|
||||||
last_segment.DesignParameters.StartDistAlong + last_segment.DesignParameters.HorizontalLength
|
|
||||||
)
|
|
||||||
last_segment_end_gradient = last_segment.DesignParameters.EndGradient
|
|
||||||
break
|
break
|
||||||
|
|
||||||
|
if last_segment:
|
||||||
|
file.begin_transaction()
|
||||||
|
last_segment_dist_along = (
|
||||||
|
last_segment.DesignParameters.StartDistAlong + last_segment.DesignParameters.HorizontalLength
|
||||||
|
)
|
||||||
|
last_segment_end_gradient = last_segment.DesignParameters.EndGradient
|
||||||
|
settings = ifcopenshell.geom.settings()
|
||||||
|
mapped_segments = _map_alignment_vertical_segment(file, last_segment)
|
||||||
|
geometry_segment = mapped_segments[0] if mapped_segments[1] == None else mapped_segments[1]
|
||||||
|
fn = wrapper.map_shape(settings, geometry_segment.wrapped_data)
|
||||||
|
eval = wrapper.function_item_evaluator(settings, fn)
|
||||||
|
e = np.array(eval.evaluate(fn.end()))
|
||||||
|
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(file)
|
||||||
|
last_segment_height = float(e[1, 3]) / unit_scale
|
||||||
|
|
||||||
|
file.discard_transaction()
|
||||||
|
|
||||||
design_parameters = file.createIfcAlignmentVerticalSegment(
|
design_parameters = file.createIfcAlignmentVerticalSegment(
|
||||||
StartDistAlong=last_segment_dist_along,
|
StartDistAlong=last_segment_dist_along,
|
||||||
HorizontalLength=0.0,
|
HorizontalLength=0.0,
|
||||||
StartHeight=0.0,
|
StartHeight=last_segment_height,
|
||||||
StartGradient=last_segment_end_gradient,
|
StartGradient=last_segment_end_gradient,
|
||||||
EndGradient=last_segment_end_gradient,
|
EndGradient=last_segment_end_gradient,
|
||||||
PredefinedType="CONSTANTGRADIENT",
|
PredefinedType="CONSTANTGRADIENT",
|
||||||
|
|||||||
+23
-18
@@ -26,47 +26,52 @@ import math
|
|||||||
|
|
||||||
|
|
||||||
def get_curve_segment_transition_code(
|
def get_curve_segment_transition_code(
|
||||||
prev_segment: entity_instance, segment: entity_instance, tolerance: float = 5.0e-4
|
segment: entity_instance, next_segment: entity_instance, position_tolerance: float = 0.001
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Returns the IfcCurveSegment.Transition of prev_segment based on a comparison of
|
Returns the IfcCurveSegment.Transition of segment based on a comparison of
|
||||||
the position, ref. direction, and curvature at the end of the prev_segment and the start of segment.
|
the position, ref. direction, and curvature at the end of the segment and the start of next_segment.
|
||||||
|
|
||||||
|
:param segment: segment for which the position curve is being being determined
|
||||||
|
:param next_segment: next segment
|
||||||
|
:param position_tolerance: tolerance used for evaluation positions. The default is 1mm
|
||||||
|
:return: the transition code
|
||||||
"""
|
"""
|
||||||
expected_type = "IfcCurveSegment"
|
expected_type = "IfcCurveSegment"
|
||||||
if not prev_segment.is_a(expected_type):
|
|
||||||
raise TypeError(f"Expected to see '{expected_type}', instead received '{prev_segment.is_a()}'.")
|
|
||||||
|
|
||||||
if not segment.is_a(expected_type):
|
if not segment.is_a(expected_type):
|
||||||
raise TypeError(f"Expected to see '{expected_type}', instead received '{segment.is_a()}'.")
|
raise TypeError(f"Expected to see '{expected_type}', instead received '{segment.is_a()}'.")
|
||||||
|
|
||||||
if len(prev_segment.UsingCurves) != 1:
|
if not next_segment.is_a(expected_type):
|
||||||
raise TypeError("prev_segment must belong to exactly one curve")
|
raise TypeError(f"Expected to see '{expected_type}', instead received '{next_segment.is_a()}'.")
|
||||||
|
|
||||||
if len(segment.UsingCurves) != 1:
|
if len(segment.UsingCurves) != 1:
|
||||||
raise TypeError("segment must belong to exactly one curve")
|
raise TypeError("segment must belong to exactly one curve")
|
||||||
|
|
||||||
if prev_segment.UsingCurves[0] != segment.UsingCurves[0]:
|
if len(next_segment.UsingCurves) != 1:
|
||||||
|
raise TypeError("next_segment must belong to exactly one curve")
|
||||||
|
|
||||||
|
if segment.UsingCurves[0] != next_segment.UsingCurves[0]:
|
||||||
raise TypeError("Both segments must belong to the same curve")
|
raise TypeError("Both segments must belong to the same curve")
|
||||||
|
|
||||||
settings = ifcopenshell.geom.settings()
|
settings = ifcopenshell.geom.settings()
|
||||||
settings.set("COMPUTE_CURVATURE", True)
|
settings.set("COMPUTE_CURVATURE", True)
|
||||||
|
|
||||||
prev_segment_fn = ifcopenshell_wrapper.map_shape(settings, prev_segment.wrapped_data)
|
segment_fn = ifcopenshell_wrapper.map_shape(settings, segment.wrapped_data)
|
||||||
prev_segment_evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, prev_segment_fn)
|
segment_evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, segment_fn)
|
||||||
e = prev_segment_evaluator.evaluate(prev_segment_fn.end())
|
e = segment_evaluator.evaluate(segment_fn.end())
|
||||||
end = np.array(e)
|
end = np.array(e)
|
||||||
|
|
||||||
# must add the new segment to the container before mapping it, otherwise the segment doesn't
|
# must add the new segment to the container before mapping it, otherwise the segment doesn't
|
||||||
# have enough context to know if it is for horizontal, vertical, cant
|
# have enough context to know if it is for horizontal, vertical, cant
|
||||||
|
|
||||||
segment_fn = ifcopenshell_wrapper.map_shape(settings, segment.wrapped_data)
|
next_segment_fn = ifcopenshell_wrapper.map_shape(settings, next_segment.wrapped_data)
|
||||||
segment_evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, segment_fn)
|
next_segment_evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, next_segment_fn)
|
||||||
s = segment_evaluator.evaluate(segment_fn.start())
|
s = next_segment_evaluator.evaluate(next_segment_fn.start())
|
||||||
start = np.array(s)
|
start = np.array(s)
|
||||||
|
|
||||||
same_position = True if np.allclose(end[:3, 3], start[:3, 3], atol=tolerance) else False
|
same_position = True if np.allclose(end[:3, 3], start[:3, 3], atol=position_tolerance) else False
|
||||||
same_gradient = True if np.allclose(end[:3, 0], start[:3, 0], atol=tolerance) else False
|
same_gradient = True if np.allclose(end[:3, 0], start[:3, 0]) else False
|
||||||
same_curvature = True if np.allclose(end[3:, :3], start[3:, :3], atol=tolerance) else False
|
same_curvature = True if np.allclose(end[3:, :3], start[3:, :3]) else False
|
||||||
|
|
||||||
transition_code = ""
|
transition_code = ""
|
||||||
if same_position:
|
if same_position:
|
||||||
|
|||||||
@@ -794,3 +794,5 @@ def test_map_alignment_vertical_segment():
|
|||||||
_ParabolicArc_100_0_10_0__1_0__0_5_1_Meter(file)
|
_ParabolicArc_100_0_10_0__1_0__0_5_1_Meter(file)
|
||||||
|
|
||||||
# VERTICAL CLOTHOID NOT IMPLEMENTED
|
# VERTICAL CLOTHOID NOT IMPLEMENTED
|
||||||
|
|
||||||
|
test_map_alignment_vertical_segment()
|
||||||
Reference in New Issue
Block a user