mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
MEP bends - more robust start/end points detection
also support for bends with angles > 90 degrees and some other bugs fixed
This commit is contained in:
@@ -35,7 +35,7 @@ import blenderbim.core.type
|
||||
import blenderbim.core.root
|
||||
import blenderbim.core.geometry
|
||||
import blenderbim.tool as tool
|
||||
from math import pi, degrees, radians, sin, cos, asin
|
||||
from math import pi, degrees, radians, sin, cos, asin, tan
|
||||
from copy import copy
|
||||
from mathutils import Vector, Matrix
|
||||
from ifcopenshell.util.shape_builder import ShapeBuilder
|
||||
@@ -973,10 +973,20 @@ class MEPAddBend(bpy.types.Operator, tool.Ifc.Operator):
|
||||
end_segment_data["start_point"]: end_segment_data["start_port"],
|
||||
end_segment_data["end_point"]: end_segment_data["end_port"],
|
||||
}
|
||||
(start_point, end_point), (first_segment_start, second_segment_end) = tool.Cad.closest_points(
|
||||
(start_segment_data["start_point"], start_segment_data["end_point"]),
|
||||
(end_segment_data["start_point"], end_segment_data["end_point"]),
|
||||
|
||||
get_z_basis = lambda o: o.matrix_world.col[2].normalized().to_3d()
|
||||
segments_intersection_ws = tool.Cad.intersect_edges(
|
||||
(start_object.location, start_object.location + get_z_basis(start_object)),
|
||||
(end_object.location, end_object.location + get_z_basis(end_object)),
|
||||
)[0]
|
||||
|
||||
start_point, first_segment_start = tool.Cad.closest_and_furthest_vectors(
|
||||
segments_intersection_ws, (start_segment_data["start_point"], start_segment_data["end_point"])
|
||||
)
|
||||
end_point, second_segment_end = tool.Cad.closest_and_furthest_vectors(
|
||||
segments_intersection_ws, (end_segment_data["start_point"], end_segment_data["end_point"])
|
||||
)
|
||||
|
||||
start_port = points_ports_map[start_point]
|
||||
end_port = points_ports_map[end_point]
|
||||
start_point_on_origin = start_point == start_segment_data["start_point"]
|
||||
@@ -1032,7 +1042,6 @@ class MEPAddBend(bpy.types.Operator, tool.Ifc.Operator):
|
||||
return {"CANCELLED"}
|
||||
|
||||
O = V(0, 0, 0)
|
||||
get_z_basis = lambda o: o.matrix_world.col[2].normalized().to_3d()
|
||||
angle = tool.Cad.angle_edges((get_z_basis(start_object), O), (get_z_basis(end_object), O))
|
||||
|
||||
lateral_sign = tool.Cad.sign(profile_offset[lateral_axis])
|
||||
@@ -1042,18 +1051,18 @@ class MEPAddBend(bpy.types.Operator, tool.Ifc.Operator):
|
||||
radial_offset.z = ref_point_radius * sin(angle)
|
||||
|
||||
def get_segments_extend():
|
||||
end_segment_z_local = to_start_object_space @ get_z_basis(end_object)
|
||||
segments_intersection = tool.Cad.intersect_edges(
|
||||
(V(0, 0, 1), V(0, 0, 0)), (profile_offset + end_segment_z_local, profile_offset)
|
||||
)[0]
|
||||
segments_intersection = segments_intersection_ws - start_point
|
||||
segments_intersection = to_start_object_space @ segments_intersection
|
||||
|
||||
curent_start_offset = segments_intersection.length
|
||||
required_start_offset = abs(radial_offset.z)
|
||||
# since tangent segments are equal
|
||||
# if drawn for the circle from the same point
|
||||
required_offset = ref_point_radius * tan(angle / 2)
|
||||
|
||||
current_start_offset = segments_intersection.length
|
||||
current_end_offset = (segments_intersection - profile_offset).length
|
||||
required_end_offset = abs(radial_offset[lateral_axis])
|
||||
|
||||
start_extend = curent_start_offset - required_start_offset
|
||||
end_extend = current_end_offset - required_end_offset
|
||||
start_extend = current_start_offset - required_offset
|
||||
end_extend = current_end_offset - required_offset
|
||||
|
||||
return start_extend, end_extend
|
||||
|
||||
@@ -1076,7 +1085,6 @@ class MEPAddBend(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
# adjust segments to fit the radius and angle
|
||||
start_segment_extend, end_segment_extend = get_segments_extend()
|
||||
|
||||
start_segment_extend_point = start_point + start_segment_sign * start_segment_extend * get_z_basis(start_object)
|
||||
projection = check_new_segment_length(first_segment_start, start_point, start_segment_extend_point)
|
||||
if projection is not None:
|
||||
@@ -1108,6 +1116,7 @@ class MEPAddBend(bpy.types.Operator, tool.Ifc.Operator):
|
||||
angle,
|
||||
self.radius / si_conversion,
|
||||
profile_offset / si_conversion,
|
||||
flip_z_axis=start_segment_sign == -1,
|
||||
)
|
||||
|
||||
bpy.ops.bim.create_shape_from_step_id(step_id=rep.id(), should_include_curves=True)
|
||||
|
||||
@@ -1367,9 +1367,7 @@ class DumbWallJoiner:
|
||||
clamp_axis = clamp_axis[::-1]
|
||||
vectors = tuple([clamp_point_by_direction(v, clamp_axis) for v in vectors])
|
||||
|
||||
closest = tool.Cad.closest_vector(ref_point_2d.to_3d(), vectors)
|
||||
farthest = vectors[1] if closest == vectors[0] else vectors[0]
|
||||
return closest, farthest
|
||||
return tool.Cad.closest_and_furthest_vectors(ref_point_2d.to_3d(), vectors)
|
||||
|
||||
bbn, bbf = get_closest_and_furthest_vectors(axis1["base"][i], (bb1, bb2), bba1)
|
||||
bsn, bsf = get_closest_and_furthest_vectors(axis1["side"][i], (bs1, bs2))
|
||||
|
||||
@@ -192,6 +192,18 @@ class Cad:
|
||||
distance_test = (v1 - pt).length >= (v2 - pt).length
|
||||
return v1 if distance_test else v2
|
||||
|
||||
@classmethod
|
||||
def closest_and_furthest_vectors(cls, pt, e):
|
||||
"""
|
||||
> pt: vector
|
||||
> e: 2 vector tuple
|
||||
< returns the two vectors closest to and furthest from pt.
|
||||
"""
|
||||
if isinstance(e, tuple) and all([isinstance(co, Vector) for co in e]):
|
||||
closest = cls.closest_vector(pt, e)
|
||||
furthest = e[1] if closest == e[0] else e[0]
|
||||
return closest, furthest
|
||||
|
||||
@classmethod
|
||||
def coords_tuple_from_edge_idx(cls, bm, idx):
|
||||
"""bm is a bmesh representation"""
|
||||
|
||||
@@ -1278,7 +1278,14 @@ class ShapeBuilder:
|
||||
return angle
|
||||
|
||||
def mep_bend_shape(
|
||||
self, segment, start_length: float, end_length: float, angle: float, radius: float, profile_offset: Vector
|
||||
self,
|
||||
segment,
|
||||
start_length: float,
|
||||
end_length: float,
|
||||
angle: float,
|
||||
radius: float,
|
||||
profile_offset: Vector,
|
||||
flip_z_axis: bool,
|
||||
):
|
||||
"""
|
||||
|
||||
@@ -1290,9 +1297,11 @@ class ShapeBuilder:
|
||||
:param radius: bend radius
|
||||
:param type: float
|
||||
:param profile_offset: offset between start and end segments in local space of start segment
|
||||
used mainly to determine the bend axes and their direction.
|
||||
Values themselves are replaced by the radius.
|
||||
used mainly to determine the seconn bend axis and it's direction.
|
||||
:param type: Vector
|
||||
:param flip_z_axis: since we cannot determine z axis direction from the profile offset,
|
||||
there is an option to flip it if bend is going by start segment Z- axis.
|
||||
:param type: bool
|
||||
|
||||
:return: tuple of Model/Body/MODEL_VIEW IfcRepresentation and transition shape data
|
||||
"""
|
||||
@@ -1318,7 +1327,7 @@ class ShapeBuilder:
|
||||
lateral_axis = next(i for i in range(2) if not is_x(rounded_offset[i], 0))
|
||||
non_lateral_axis = 1 if lateral_axis == 0 else 0
|
||||
lateral_sign = sign(profile_offset[lateral_axis])
|
||||
z_sign = sign(profile_offset.z)
|
||||
z_sign = -1 if flip_z_axis else 1
|
||||
|
||||
rep_items = []
|
||||
|
||||
|
||||
Reference in New Issue
Block a user