mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-17 22:11:36 +00:00
bends - support for start and end segments
This commit is contained in:
@@ -882,12 +882,6 @@ class MEPAddBend(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
ifc_file = tool.Ifc.get()
|
ifc_file = tool.Ifc.get()
|
||||||
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
||||||
|
|
||||||
self.start_length, self.end_length = 0, 0
|
|
||||||
|
|
||||||
if not (self.start_length == 0 and self.end_length == 0):
|
|
||||||
self.report({"ERROR"}, f"Only zero lengths are now supported.")
|
|
||||||
return {"CANCELLED"}
|
|
||||||
|
|
||||||
if self.start_segment_id and self.end_segment_id:
|
if self.start_segment_id and self.end_segment_id:
|
||||||
start_element = ifc_file.by_id(self.start_segment_id)
|
start_element = ifc_file.by_id(self.start_segment_id)
|
||||||
end_element = ifc_file.by_id(self.end_segment_id)
|
end_element = ifc_file.by_id(self.end_segment_id)
|
||||||
@@ -971,7 +965,7 @@ class MEPAddBend(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
end_segment_data["end_point"]: end_segment_data["end_port"],
|
end_segment_data["end_point"]: end_segment_data["end_port"],
|
||||||
}
|
}
|
||||||
|
|
||||||
get_z_basis = lambda o: o.matrix_world.col[2].normalized().to_3d()
|
get_z_basis = lambda o: tool.Cad.get_basis_vector(o, 2)
|
||||||
segments_intersection_ws = tool.Cad.intersect_edges(
|
segments_intersection_ws = tool.Cad.intersect_edges(
|
||||||
(start_object.location, start_object.location + get_z_basis(start_object)),
|
(start_object.location, start_object.location + get_z_basis(start_object)),
|
||||||
(end_object.location, end_object.location + get_z_basis(end_object)),
|
(end_object.location, end_object.location + get_z_basis(end_object)),
|
||||||
@@ -1058,8 +1052,8 @@ class MEPAddBend(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
current_start_offset = segments_intersection.length
|
current_start_offset = segments_intersection.length
|
||||||
current_end_offset = (segments_intersection - profile_offset).length
|
current_end_offset = (segments_intersection - profile_offset).length
|
||||||
|
|
||||||
start_extend = current_start_offset - required_offset
|
start_extend = current_start_offset - (required_offset + self.start_length)
|
||||||
end_extend = current_end_offset - required_offset
|
end_extend = current_end_offset - (required_offset + self.end_length)
|
||||||
|
|
||||||
return start_extend, end_extend
|
return start_extend, end_extend
|
||||||
|
|
||||||
|
|||||||
@@ -526,3 +526,7 @@ class Cad:
|
|||||||
if cls.is_x(value, 0):
|
if cls.is_x(value, 0):
|
||||||
return 0
|
return 0
|
||||||
return 1 if value > 0 else -1
|
return 1 if value > 0 else -1
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_basis_vector(cls, object, axis_i):
|
||||||
|
return object.matrix_world.col[axis_i].normalized().to_3d()
|
||||||
|
|||||||
@@ -1356,10 +1356,26 @@ class ShapeBuilder:
|
|||||||
O[lateral_axis] = (radius + profile_dim[lateral_axis]) * lateral_sign
|
O[lateral_axis] = (radius + profile_dim[lateral_axis]) * lateral_sign
|
||||||
theta = angle
|
theta = angle
|
||||||
|
|
||||||
|
def get_circle_point(angle, radius):
|
||||||
|
point = V(0, 0, 0)
|
||||||
|
angle -= pi / 2
|
||||||
|
# fmt: off
|
||||||
|
point.z = z_sign * cos(angle) * radius
|
||||||
|
point[lateral_axis] = lateral_sign * sin(angle) * radius
|
||||||
|
# fmt: on
|
||||||
|
return point
|
||||||
|
|
||||||
|
def get_circle_tangent(angle):
|
||||||
|
tangent = V(0, 0, 0)
|
||||||
|
tangent.z = cos(angle) * z_sign
|
||||||
|
tangent[lateral_axis] = sin(angle) * lateral_sign
|
||||||
|
return tangent
|
||||||
|
|
||||||
def get_bend_representation_item():
|
def get_bend_representation_item():
|
||||||
if is_circular_profile:
|
if is_circular_profile:
|
||||||
theta_segments = [0, theta / 2, theta]
|
theta_segments = [0, theta / 2, theta]
|
||||||
else:
|
else:
|
||||||
|
# TODO: try to replace with curves instead of segments
|
||||||
# get as much segment_length segments as possible
|
# get as much segment_length segments as possible
|
||||||
segment_length = pi / 20
|
segment_length = pi / 20
|
||||||
num_segments = ceil(theta / segment_length)
|
num_segments = ceil(theta / segment_length)
|
||||||
@@ -1371,32 +1387,27 @@ class ShapeBuilder:
|
|||||||
r = radius
|
r = radius
|
||||||
if is_circular_profile:
|
if is_circular_profile:
|
||||||
r += profile_dim[lateral_axis]
|
r += profile_dim[lateral_axis]
|
||||||
|
else:
|
||||||
|
outer_r = r + 2 * profile_dim[lateral_axis]
|
||||||
|
|
||||||
for cur_theta in theta_segments:
|
for cur_theta in theta_segments:
|
||||||
cur_theta -= pi / 2
|
inner_points.append(get_circle_point(cur_theta, r))
|
||||||
inner = V(0, 0, 0)
|
|
||||||
# fmt: off
|
|
||||||
inner.z = z_sign * cos(cur_theta) * r
|
|
||||||
inner[lateral_axis] = lateral_sign * sin(cur_theta) * r
|
|
||||||
inner_points.append(inner)
|
|
||||||
|
|
||||||
if not is_circular_profile:
|
if not is_circular_profile:
|
||||||
outer = V(0, 0, 0)
|
outer_points.append(get_circle_point(cur_theta, outer_r))
|
||||||
outer.z = z_sign * cos(cur_theta) * (r + 2 * profile_dim[lateral_axis])
|
|
||||||
outer[lateral_axis] = lateral_sign * sin(cur_theta) * (r + 2 * profile_dim[lateral_axis])
|
|
||||||
outer_points.append(outer)
|
|
||||||
# fmt: on
|
|
||||||
|
|
||||||
points = inner_points + outer_points[::-1]
|
points = inner_points + outer_points[::-1]
|
||||||
points = [p + O for p in points]
|
points = [p + O for p in points]
|
||||||
|
offset = V(0, 0, 0)
|
||||||
|
offset.z = z_sign * start_length
|
||||||
|
|
||||||
if is_circular_profile:
|
if is_circular_profile:
|
||||||
bend_path = self.polyline(points, closed=False, arc_points=[1])
|
bend_path = self.polyline(points, closed=False, arc_points=[1], position_offset=offset)
|
||||||
bend = self.create_swept_disk_solid(bend_path, profile_dim[lateral_axis])
|
bend = self.create_swept_disk_solid(bend_path, profile_dim[lateral_axis])
|
||||||
else:
|
else:
|
||||||
main_axes = lambda v: getattr(v, "xy"[lateral_axis] + "z")
|
main_axes = lambda v: getattr(v, "xy"[lateral_axis] + "z")
|
||||||
offset = V(0, 0, 0)
|
|
||||||
offset[non_lateral_axis] = -profile_dim[non_lateral_axis]
|
offset[non_lateral_axis] = -profile_dim[non_lateral_axis]
|
||||||
|
|
||||||
extrusion_kwargs = self.extrude_kwargs("XY"[non_lateral_axis])
|
extrusion_kwargs = self.extrude_kwargs("XY"[non_lateral_axis])
|
||||||
profile_curve = self.polyline([main_axes(p) for p in points], closed=True)
|
profile_curve = self.polyline([main_axes(p) for p in points], closed=True)
|
||||||
bend = self.extrude(
|
bend = self.extrude(
|
||||||
@@ -1405,6 +1416,28 @@ class ShapeBuilder:
|
|||||||
return bend
|
return bend
|
||||||
|
|
||||||
rep_items.append(get_bend_representation_item())
|
rep_items.append(get_bend_representation_item())
|
||||||
|
if start_length:
|
||||||
|
rep_items.append(self.extrude(profile, start_length, extrusion_vector=V(0, 0, z_sign)))
|
||||||
|
if end_length:
|
||||||
|
end_position = O + get_circle_point(theta, radius + profile_dim[lateral_axis])
|
||||||
|
end_position.z += start_length * z_sign
|
||||||
|
|
||||||
|
# define extrusion space for the segment after the bend
|
||||||
|
z_axis = get_circle_tangent(theta)
|
||||||
|
extrude_kwargs = {
|
||||||
|
"position_z_axis": z_axis,
|
||||||
|
"extrusion_vector": Vector((0, 0, 1)),
|
||||||
|
}
|
||||||
|
# since we are sure that tangent involves only two axis
|
||||||
|
# it's safe to assume that non lateral axis is untouched
|
||||||
|
if lateral_axis == 0:
|
||||||
|
x_axis = z_axis.cross(Vector((0, 1, 0)))
|
||||||
|
else:
|
||||||
|
x_axis = Vector((1, 0, 0))
|
||||||
|
extrude_kwargs["position_x_axis"] = x_axis
|
||||||
|
|
||||||
|
rep_items.append(self.extrude(profile, end_length, end_position, **extrude_kwargs))
|
||||||
|
|
||||||
body = ifcopenshell.util.representation.get_context(self.file, "Model", "Body", "MODEL_VIEW")
|
body = ifcopenshell.util.representation.get_context(self.file, "Model", "Body", "MODEL_VIEW")
|
||||||
rep = self.get_representation(body, rep_items)
|
rep = self.get_representation(body, rep_items)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user