Skip to content

Commit 2b93cf6

Browse files
committed
edit pipe segments
1 parent 49fcc60 commit 2b93cf6

File tree

4 files changed

+135
-60
lines changed

4 files changed

+135
-60
lines changed

src/bim2fem/ifcplus/api/distribution_element.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,9 @@ def create_elbow(
198198

199199

200200
def create_pipe_segment(
201-
p1: tuple[float, float, float],
202-
p2: tuple[float, float, float],
201+
ifc4_file: ifcopenshell.file,
202+
start_point: tuple[float, float, float],
203+
end_point: tuple[float, float, float],
203204
nominal_diameter: float,
204205
thickness: float,
205206
material: ifcopenshell.entity_instance,
@@ -211,8 +212,6 @@ def create_pipe_segment(
211212
add_shape_representation_to_ports: bool = False,
212213
) -> ifcopenshell.entity_instance:
213214

214-
ifc4_file = material.file
215-
216215
if pipe_segment is None:
217216
pipe_segment = ifcopenshell.api.root.create_entity(
218217
file=ifc4_file,
@@ -239,7 +238,7 @@ def create_pipe_segment(
239238
system=distribution_system,
240239
)
241240

242-
object_z_axis_in_global_coordinates = np.array(p2) - np.array(p1)
241+
object_z_axis_in_global_coordinates = np.array(end_point) - np.array(start_point)
243242
angle_between_local_and_global_z_axes = (
244243
bim2fem.ifcplus.util.geometry.calculate_angle_between_two_vectors(
245244
vector1=tuple(object_z_axis_in_global_coordinates.tolist()),
@@ -298,7 +297,7 @@ def create_pipe_segment(
298297
representation=shape_model,
299298
)
300299

301-
object_origin_in_global_coordinates = p1
300+
object_origin_in_global_coordinates = start_point
302301

303302
bim2fem.ifcplus.api.placement.edit_object_placement(
304303
product=pipe_segment,

src/bim2fem/ifcplus/api/system.py

Lines changed: 16 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import bim2fem.ifcplus.util.geometry
1010
import bim2fem.ifcplus.api.style
1111
import numpy as np
12-
import ifcopenshell.util.placement
1312
import ifcopenshell.util.representation
1413
from bim2fem.ifcplus.api.distribution_element import ELBOW_RADIUS_TYPE
1514
import bim2fem.ifcplus.util.system
@@ -19,6 +18,10 @@ def add_shape_representation_to_distribution_ports(
1918
ports: list[ifcopenshell.entity_instance],
2019
arrow_size: float = 0.1,
2120
) -> None:
21+
"""Add ShapeRepresentation to DistributionPorts as RectangularPyramids pointing
22+
in the direction of flow.
23+
"""
24+
2225
ifc4_file = ports[0].file
2326

2427
sink_arrow = None
@@ -96,52 +99,6 @@ def add_shape_representation_to_distribution_ports(
9699
)
97100

98101

99-
def filter_out_colinear_points_from_polyline(
100-
polyline: list[tuple[float, float, float]],
101-
) -> list[tuple[float, float, float]]:
102-
103-
def remove_items_by_indices(lst: list, indices: list) -> list:
104-
indices_set = set(indices)
105-
return [item for idx, item in enumerate(lst) if idx not in indices_set]
106-
107-
if len(polyline) < 3:
108-
return polyline
109-
110-
indices_of_points_to_remove = []
111-
112-
for index in range(len(polyline)):
113-
114-
if index == len(polyline) - 2:
115-
break
116-
117-
p1 = polyline[index]
118-
p2 = polyline[index + 1]
119-
p3 = polyline[index + 2]
120-
121-
v12 = bim2fem.ifcplus.util.geometry.calculate_unit_direction_vector_between_two_points(
122-
p1=p1,
123-
p2=p2,
124-
)
125-
126-
v23 = bim2fem.ifcplus.util.geometry.calculate_unit_direction_vector_between_two_points(
127-
p1=p2,
128-
p2=p3,
129-
)
130-
131-
angle = bim2fem.ifcplus.util.geometry.calculate_angle_between_two_vectors(
132-
vector1=v12, vector2=v23
133-
)
134-
135-
if angle == 0.0:
136-
indices_of_points_to_remove.append(index + 1)
137-
138-
new_polyine = remove_items_by_indices(
139-
lst=polyline, indices=indices_of_points_to_remove
140-
)
141-
142-
return new_polyine
143-
144-
145102
def create_piping_system_from_polyline(
146103
ifc4_file: ifcopenshell.file,
147104
polyline: list[tuple[float, float, float]],
@@ -163,8 +120,9 @@ def create_piping_system_from_polyline(
163120

164121
if len(polyline) == 2:
165122
pipe_segment = bim2fem.ifcplus.api.distribution_element.create_pipe_segment(
166-
p1=polyline[0],
167-
p2=polyline[1],
123+
ifc4_file=ifc4_file,
124+
start_point=polyline[0],
125+
end_point=polyline[1],
168126
nominal_diameter=nominal_diameter,
169127
thickness=thickness,
170128
material=material,
@@ -176,7 +134,9 @@ def create_piping_system_from_polyline(
176134
)
177135
return [pipe_segment]
178136

179-
polyline = filter_out_colinear_points_from_polyline(polyline=polyline)
137+
polyline = bim2fem.ifcplus.util.geometry.filter_out_colinear_points_from_polyline(
138+
polyline=polyline,
139+
)
180140

181141
if elbow_radius_type == "LONG":
182142
radius_of_curvature = 1.5 * nominal_diameter
@@ -192,8 +152,9 @@ def create_piping_system_from_polyline(
192152
if index + 2 == len(polyline):
193153
last_pipe_segment = (
194154
bim2fem.ifcplus.api.distribution_element.create_pipe_segment(
195-
p1=pipe_segment_start_point,
196-
p2=polyline[-1],
155+
ifc4_file=ifc4_file,
156+
start_point=pipe_segment_start_point,
157+
end_point=polyline[-1],
197158
nominal_diameter=nominal_diameter,
198159
thickness=thickness,
199160
material=material,
@@ -219,8 +180,9 @@ def create_piping_system_from_polyline(
219180
pipe_segment_end_point = horizontal_curve.point_of_curvature
220181

221182
pipe_segment = bim2fem.ifcplus.api.distribution_element.create_pipe_segment(
222-
p1=pipe_segment_start_point,
223-
p2=pipe_segment_end_point,
183+
ifc4_file=ifc4_file,
184+
start_point=pipe_segment_start_point,
185+
end_point=pipe_segment_end_point,
224186
nominal_diameter=nominal_diameter,
225187
thickness=thickness,
226188
material=material,

src/bim2fem/ifcplus/util/geometry.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1527,3 +1527,48 @@ def line_parallel_to_triangle_plane(
15271527
is_coplanar = is_parallel and (dist <= dist_tol)
15281528

15291529
return is_parallel, is_coplanar, angle_to_plane_deg
1530+
1531+
1532+
def filter_out_colinear_points_from_polyline(
1533+
polyline: list[tuple[float, float, float]],
1534+
) -> list[tuple[float, float, float]]:
1535+
"""Filter out colinear points from 3D polyline"""
1536+
1537+
def remove_items_by_indices(lst: list, indices: list) -> list:
1538+
indices_set = set(indices)
1539+
return [item for idx, item in enumerate(lst) if idx not in indices_set]
1540+
1541+
if len(polyline) < 3:
1542+
return polyline
1543+
1544+
indices_of_points_to_remove = []
1545+
1546+
for index in range(len(polyline)):
1547+
1548+
if index == len(polyline) - 2:
1549+
break
1550+
1551+
p1 = polyline[index]
1552+
p2 = polyline[index + 1]
1553+
p3 = polyline[index + 2]
1554+
1555+
v12 = calculate_unit_direction_vector_between_two_points(
1556+
p1=p1,
1557+
p2=p2,
1558+
)
1559+
1560+
v23 = calculate_unit_direction_vector_between_two_points(
1561+
p1=p2,
1562+
p2=p3,
1563+
)
1564+
1565+
angle = calculate_angle_between_two_vectors(vector1=v12, vector2=v23)
1566+
1567+
if angle == 0.0:
1568+
indices_of_points_to_remove.append(index + 1)
1569+
1570+
new_polyline = remove_items_by_indices(
1571+
lst=polyline, indices=indices_of_points_to_remove
1572+
)
1573+
1574+
return new_polyline

tests/ifcplus/api/test_distribution_element.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,75 @@ def test_add_elbows(
276276

277277
assert len(logger.statements) == 0
278278

279+
def test_add_pipe_segments(
280+
self,
281+
ifc_file_with_ventilation_distribution_system: ifcopenshell.file,
282+
):
283+
284+
distribution_system = ifc_file_with_ventilation_distribution_system.by_type(
285+
type="IfcDistributionSystem",
286+
include_subtypes=False,
287+
)[0]
288+
289+
site = ifc_file_with_ventilation_distribution_system.by_type(
290+
type="IfcSite",
291+
include_subtypes=False,
292+
)[0]
293+
294+
material = bim2fem.ifcplus.api.material.add_material_with_structural_properties(
295+
ifc4_file=ifc_file_with_ventilation_distribution_system,
296+
name="Galvanized Steel",
297+
category="steel",
298+
mass_density=7850.0,
299+
young_modulus=200.0e9,
300+
poisson_ratio=0.3,
301+
thermal_expansion_coefficient=1.2e-6,
302+
check_for_duplicate=True,
303+
)
304+
305+
bim2fem.ifcplus.api.distribution_element.create_pipe_segment(
306+
ifc4_file=ifc_file_with_ventilation_distribution_system,
307+
start_point=(1.0, 1.0, 0.0),
308+
end_point=(1.0, 1.0 + 5.0, 0.0),
309+
nominal_diameter=1.0,
310+
thickness=0.10,
311+
material=material,
312+
name="Pipe #1",
313+
spatial_element=site,
314+
distribution_system=distribution_system,
315+
place_object_relative_to_parent=False,
316+
add_shape_representation_to_ports=False,
317+
)
318+
319+
bim2fem.ifcplus.api.distribution_element.create_pipe_segment(
320+
ifc4_file=ifc_file_with_ventilation_distribution_system,
321+
start_point=(1.0, 1.0 + 8.0, 0.0),
322+
end_point=(1.0, 1.0 + 5.0 + 8.0, 0.0 + 5.0),
323+
nominal_diameter=1.0,
324+
thickness=0.10,
325+
material=material,
326+
name="Pipe #2",
327+
spatial_element=site,
328+
distribution_system=distribution_system,
329+
place_object_relative_to_parent=False,
330+
add_shape_representation_to_ports=False,
331+
)
332+
333+
output_path = str(OUTPUT_DIR_FOR_DISTRIBUTION_ELEMENT / "pipe_segments.ifc")
334+
bim2fem.ifcplus.api.project.write_to_ifc_spf(
335+
ifc4_file=ifc_file_with_ventilation_distribution_system,
336+
file_path=output_path,
337+
add_annotations=True,
338+
)
339+
340+
logger = ifcopenshell.validate.json_logger()
341+
ifcopenshell.validate.validate(output_path, logger, express_rules=True)
342+
from pprint import pprint
343+
344+
pprint(logger.statements)
345+
346+
assert len(logger.statements) == 0
347+
279348

280349
class TestConnectEquipment:
281350

0 commit comments

Comments
 (0)