mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-16 21:42:19 +00:00
See #1227. Implement joins for sloped walls.
This commit is contained in:
@@ -1091,6 +1091,8 @@ class Loader(bonsai.core.tool.Loader):
|
|||||||
def get_extrusion_vector(cls, wall):
|
def get_extrusion_vector(cls, wall):
|
||||||
if body := ifcopenshell.util.representation.get_representation(wall, "Model", "Body", "MODEL_VIEW"):
|
if body := ifcopenshell.util.representation.get_representation(wall, "Model", "Body", "MODEL_VIEW"):
|
||||||
for item in ifcopenshell.util.representation.resolve_representation(body).Items:
|
for item in ifcopenshell.util.representation.resolve_representation(body).Items:
|
||||||
|
while item.is_a("IfcBooleanResult"):
|
||||||
|
item = item.FirstOperand
|
||||||
if item.is_a("IfcExtrudedAreaSolid"):
|
if item.is_a("IfcExtrudedAreaSolid"):
|
||||||
return Vector(item.ExtrudedDirection.DirectionRatios)
|
return Vector(item.ExtrudedDirection.DirectionRatios)
|
||||||
return Vector([0.0, 0.0, 1.0])
|
return Vector([0.0, 0.0, 1.0])
|
||||||
|
|||||||
+189
-65
@@ -11,6 +11,9 @@ import ifcopenshell.api.geometry
|
|||||||
import ifcopenshell.util.shape_builder
|
import ifcopenshell.util.shape_builder
|
||||||
import ifcopenshell.util.element
|
import ifcopenshell.util.element
|
||||||
|
|
||||||
|
# https://stackoverflow.com/a/9184560/9627415
|
||||||
|
# Possible optimisation to linalg.norm?
|
||||||
|
|
||||||
# from ifcopenshell.util.shape_builder import VectorType, SequenceOfVectors
|
# from ifcopenshell.util.shape_builder import VectorType, SequenceOfVectors
|
||||||
from itertools import cycle
|
from itertools import cycle
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
@@ -164,8 +167,8 @@ def test_wall(offset, p1, p2, p3, p4, a1=None, a2=None):
|
|||||||
)
|
)
|
||||||
|
|
||||||
Foo(f, body, axis).regenerate(wall_a, angle=a1)
|
Foo(f, body, axis).regenerate(wall_a, angle=a1)
|
||||||
Foo(f, body, axis).regenerate(wall_b)
|
Foo(f, body, axis).regenerate(wall_b, angle=a1)
|
||||||
Foo(f, body, axis).regenerate(wall_c)
|
Foo(f, body, axis).regenerate(wall_c, angle=a1)
|
||||||
|
|
||||||
|
|
||||||
def create_type(name, layers):
|
def create_type(name, layers):
|
||||||
@@ -181,7 +184,7 @@ def create_type(name, layers):
|
|||||||
return wall_type
|
return wall_type
|
||||||
|
|
||||||
|
|
||||||
def test_atpath(offset):
|
def test_atpath(offset, angle=None):
|
||||||
offset *= 1.5
|
offset *= 1.5
|
||||||
wall_type_a = create_type("A", [(1, 0.05), (2, 0.1), (3, 0.05)])
|
wall_type_a = create_type("A", [(1, 0.05), (2, 0.1), (3, 0.05)])
|
||||||
wall_a = ifcopenshell.api.root.create_entity(f, ifc_class="IfcWall", name="A123")
|
wall_a = ifcopenshell.api.root.create_entity(f, ifc_class="IfcWall", name="A123")
|
||||||
@@ -213,7 +216,7 @@ def test_atpath(offset):
|
|||||||
relating_connection="ATEND",
|
relating_connection="ATEND",
|
||||||
related_connection="ATPATH",
|
related_connection="ATPATH",
|
||||||
)
|
)
|
||||||
Foo(f, body, axis).regenerate(wall)
|
Foo(f, body, axis).regenerate(wall, angle=angle)
|
||||||
|
|
||||||
create_branch("B", 1, 1, 1, 1, 1, -75)
|
create_branch("B", 1, 1, 1, 1, 1, -75)
|
||||||
create_branch("C", 1, 2, 3, 2, 1, -75)
|
create_branch("C", 1, 2, 3, 2, 1, -75)
|
||||||
@@ -227,7 +230,7 @@ def test_atpath(offset):
|
|||||||
create_branch("E", 4, 4, 4, 3.5, -1, 75)
|
create_branch("E", 4, 4, 4, 3.5, -1, 75)
|
||||||
create_branch("F", 4, 2, 4, 4.5, -1, 75)
|
create_branch("F", 4, 2, 4, 4.5, -1, 75)
|
||||||
|
|
||||||
Foo(f, body, axis).regenerate(wall_a)
|
Foo(f, body, axis).regenerate(wall_a, angle=angle)
|
||||||
|
|
||||||
|
|
||||||
PrioritisedLayer = namedtuple("PrioritisedLayer", "priority thickness")
|
PrioritisedLayer = namedtuple("PrioritisedLayer", "priority thickness")
|
||||||
@@ -238,25 +241,32 @@ class Foo:
|
|||||||
self.file = file
|
self.file = file
|
||||||
self.body = body
|
self.body = body
|
||||||
self.axis = axis
|
self.axis = axis
|
||||||
|
self.is_angled = False
|
||||||
|
|
||||||
def regenerate(self, wall, angle=None):
|
def regenerate(self, wall, angle=None):
|
||||||
print("-" * 100)
|
print("-" * 100)
|
||||||
print(wall)
|
print(wall)
|
||||||
|
self.fallback_angle = angle
|
||||||
layers = self.get_layers(wall)
|
layers = self.get_layers(wall)
|
||||||
if not layers:
|
if not layers:
|
||||||
return
|
return
|
||||||
reference = self.get_reference_line(wall)
|
reference = self.get_reference_line(wall)
|
||||||
self.reference_p1, self.reference_p2 = reference
|
self.reference_p1, self.reference_p2 = reference
|
||||||
self.angle = angle or self.get_angle(wall)
|
self.wall_vectors = self.get_wall_vectors(wall)
|
||||||
axes = self.get_axes(wall, reference, layers, self.angle)
|
axes = self.get_axes(wall, reference, layers, self.wall_vectors["a"])
|
||||||
self.miny = axes[0][0][1]
|
self.miny = axes[0][0][1]
|
||||||
self.maxy = axes[-1][0][1]
|
self.maxy = axes[-1][0][1]
|
||||||
self.end_point = None
|
self.end_point = None
|
||||||
self.start_points = []
|
self.start_points = []
|
||||||
|
self.start_vector = np.array((0.0, 0.0, 1.0))
|
||||||
|
self.start_offset = 0.0
|
||||||
|
self.atpath_points = []
|
||||||
self.split_points = []
|
self.split_points = []
|
||||||
self.maxpath_points = []
|
self.maxpath_points = []
|
||||||
self.minpath_points = []
|
self.minpath_points = []
|
||||||
self.end_points = []
|
self.end_points = []
|
||||||
|
self.end_vector = np.array((0.0, 0.0, 1.0))
|
||||||
|
self.end_offset = 0.0
|
||||||
for rel in wall.ConnectedTo:
|
for rel in wall.ConnectedTo:
|
||||||
if rel.is_a("IfcRelConnectsPathElements"):
|
if rel.is_a("IfcRelConnectsPathElements"):
|
||||||
wall2 = rel.RelatedElement
|
wall2 = rel.RelatedElement
|
||||||
@@ -297,56 +307,133 @@ class Foo:
|
|||||||
self.end_points.reverse()
|
self.end_points.reverse()
|
||||||
|
|
||||||
builder = ifcopenshell.util.shape_builder.ShapeBuilder(wall.file)
|
builder = ifcopenshell.util.shape_builder.ShapeBuilder(wall.file)
|
||||||
# A wall footprint may be multiple profiles if the wall is split into two due to an ATPATH connection
|
|
||||||
profiles = []
|
|
||||||
split_points = sorted(self.split_points, key=lambda x: x[0][0]) # Sort islands in the +X direction
|
|
||||||
split_points.insert(0, self.start_points)
|
|
||||||
split_points.append(self.end_points)
|
|
||||||
split_points = iter(split_points)
|
|
||||||
|
|
||||||
while True:
|
if self.is_angled:
|
||||||
# Draw each profile as clockwise starting from (minx, miny)
|
start_points = [p.copy() for p in self.start_points]
|
||||||
start_split = next(split_points, None)
|
end_points = [p.copy() for p in self.end_points]
|
||||||
if not start_split:
|
if self.end_offset > 0:
|
||||||
break
|
for point in end_points:
|
||||||
end_split = next(split_points, None)
|
point[0] += self.end_offset
|
||||||
if not end_split:
|
if self.start_offset < 0:
|
||||||
break
|
for point in start_points:
|
||||||
maxy_minx = start_split[-1][0]
|
point[0] += self.start_offset
|
||||||
maxy_maxx = end_split[-1][0]
|
points = []
|
||||||
miny_minx = start_split[0][0]
|
points.extend(start_points)
|
||||||
miny_maxx = end_split[0][0]
|
end_points.reverse()
|
||||||
# Do more defensive checks here
|
points.extend(end_points)
|
||||||
points = start_split
|
item = builder.extrude(
|
||||||
remaining_path_points = []
|
builder.polyline(points, closed=True),
|
||||||
for maxpath_points in self.maxpath_points:
|
magnitude=self.wall_vectors["d"],
|
||||||
if maxpath_points[0][0] > maxy_minx and maxpath_points[-1][0] < maxy_maxx:
|
extrusion_vector=self.wall_vectors["z"],
|
||||||
points.extend(maxpath_points)
|
)
|
||||||
else:
|
|
||||||
remaining_path_points.append(maxpath_points)
|
|
||||||
self.maxpath_points = remaining_path_points
|
|
||||||
points.extend(end_split[::-1])
|
|
||||||
remaining_path_points = []
|
|
||||||
for minpath_points in self.minpath_points:
|
|
||||||
if minpath_points[0][0] < miny_maxx and minpath_points[-1][0] > miny_minx:
|
|
||||||
points.extend(minpath_points)
|
|
||||||
else:
|
|
||||||
remaining_path_points.append(minpath_points)
|
|
||||||
self.minpath_points = remaining_path_points
|
|
||||||
|
|
||||||
profiles.append(builder.profile(builder.polyline(points, closed=True)))
|
operands = []
|
||||||
|
if not np.allclose(self.start_vector, np.array((0.0, 0.0, 1.0))):
|
||||||
|
points = self.start_points.copy()
|
||||||
|
while ifcopenshell.util.shape_builder.is_x(points[0][1], points[1][1]):
|
||||||
|
points.pop(0)
|
||||||
|
while ifcopenshell.util.shape_builder.is_x(points[-1][1], points[-2][1]):
|
||||||
|
points.pop()
|
||||||
|
newx = min([p[0] for p in points]) - abs(self.start_offset)
|
||||||
|
p1 = points[-1].copy()
|
||||||
|
p1[0] = newx
|
||||||
|
p2 = p1.copy()
|
||||||
|
p2[1] = points[0][1]
|
||||||
|
points.extend((p1, p2))
|
||||||
|
magnitude = np.linalg.norm(self.start_vector * (self.wall_vectors["h"] / self.start_vector[2]))
|
||||||
|
operands.append(
|
||||||
|
builder.extrude(
|
||||||
|
builder.polyline(points, closed=True), magnitude=magnitude, extrusion_vector=self.start_vector
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
for points in self.maxpath_points + self.minpath_points:
|
if not np.allclose(self.end_vector, np.array((0.0, 0.0, 1.0))):
|
||||||
profiles.append(builder.profile(builder.polyline(points, closed=True)))
|
points = self.end_points.copy()
|
||||||
|
while ifcopenshell.util.shape_builder.is_x(points[0][1], points[1][1]):
|
||||||
|
points.pop(0)
|
||||||
|
while ifcopenshell.util.shape_builder.is_x(points[-1][1], points[-2][1]):
|
||||||
|
points.pop()
|
||||||
|
|
||||||
if len(profiles) > 1:
|
newx = max([p[0] for p in points]) + abs(self.end_offset)
|
||||||
profile = wall.file.createIfcCompositeProfileDef("AREA", Profiles=profiles)
|
p1 = points[-1].copy()
|
||||||
|
p1[0] = newx
|
||||||
|
p2 = p1.copy()
|
||||||
|
p2[1] = points[0][1]
|
||||||
|
points.extend((p1, p2))
|
||||||
|
magnitude = np.linalg.norm(self.end_vector * (self.wall_vectors["h"] / self.end_vector[2]))
|
||||||
|
operands.append(
|
||||||
|
builder.extrude(
|
||||||
|
builder.polyline(points, closed=True), magnitude=magnitude, extrusion_vector=self.end_vector
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
for atpath_vector, points in self.atpath_points:
|
||||||
|
if len(points) <= 2:
|
||||||
|
continue
|
||||||
|
magnitude = np.linalg.norm(atpath_vector * (self.wall_vectors["h"] / atpath_vector[2]))
|
||||||
|
operands.append(
|
||||||
|
builder.extrude(
|
||||||
|
builder.polyline(points, closed=True), magnitude=magnitude, extrusion_vector=atpath_vector
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if operands:
|
||||||
|
item = ifcopenshell.api.geometry.add_boolean(wall.file, first_item=item, second_items=operands)[-1]
|
||||||
else:
|
else:
|
||||||
profile = profiles[0]
|
# A wall footprint may be multiple profiles if the wall is split into two due to an ATPATH connection
|
||||||
|
profiles = []
|
||||||
|
split_points = sorted(self.split_points, key=lambda x: x[0][0]) # Sort islands in the +X direction
|
||||||
|
start_points = [p.copy() for p in self.start_points]
|
||||||
|
end_points = [p.copy() for p in self.end_points]
|
||||||
|
split_points.insert(0, start_points)
|
||||||
|
split_points.append(end_points)
|
||||||
|
split_points = iter(split_points)
|
||||||
|
|
||||||
item = builder.extrude(
|
while True:
|
||||||
profile, magnitude=1.0, extrusion_vector=np.array([0.0, sin(self.angle), cos(self.angle)])
|
# Draw each profile as clockwise starting from (minx, miny)
|
||||||
)
|
start_split = next(split_points, None)
|
||||||
|
if not start_split:
|
||||||
|
break
|
||||||
|
end_split = next(split_points, None)
|
||||||
|
if not end_split:
|
||||||
|
break
|
||||||
|
maxy_minx = start_split[-1][0]
|
||||||
|
maxy_maxx = end_split[-1][0]
|
||||||
|
miny_minx = start_split[0][0]
|
||||||
|
miny_maxx = end_split[0][0]
|
||||||
|
# Do more defensive checks here
|
||||||
|
points = start_split
|
||||||
|
|
||||||
|
remaining_path_points = []
|
||||||
|
for maxpath_points in self.maxpath_points:
|
||||||
|
if maxpath_points[0][0] > maxy_minx and maxpath_points[-1][0] < maxy_maxx:
|
||||||
|
print("adding maxpath points", maxpath_points)
|
||||||
|
points.extend(maxpath_points)
|
||||||
|
else:
|
||||||
|
remaining_path_points.append(maxpath_points)
|
||||||
|
self.maxpath_points = remaining_path_points
|
||||||
|
|
||||||
|
points.extend(end_split[::-1])
|
||||||
|
|
||||||
|
remaining_path_points = []
|
||||||
|
for minpath_points in self.minpath_points:
|
||||||
|
if minpath_points[0][0] < miny_maxx and minpath_points[-1][0] > miny_minx:
|
||||||
|
points.extend(minpath_points)
|
||||||
|
else:
|
||||||
|
remaining_path_points.append(minpath_points)
|
||||||
|
self.minpath_points = remaining_path_points
|
||||||
|
|
||||||
|
profiles.append(builder.profile(builder.polyline(points, closed=True)))
|
||||||
|
|
||||||
|
for points in self.maxpath_points + self.minpath_points:
|
||||||
|
profiles.append(builder.profile(builder.polyline(points, closed=True)))
|
||||||
|
|
||||||
|
if len(profiles) > 1:
|
||||||
|
profile = wall.file.createIfcCompositeProfileDef("AREA", Profiles=profiles)
|
||||||
|
else:
|
||||||
|
profile = profiles[0]
|
||||||
|
|
||||||
|
item = builder.extrude(profile, magnitude=self.wall_vectors["d"], extrusion_vector=self.wall_vectors["z"])
|
||||||
rep = builder.get_representation(self.body, items=[item])
|
rep = builder.get_representation(self.body, items=[item])
|
||||||
if old_rep := ifcopenshell.util.representation.get_representation(wall, self.body):
|
if old_rep := ifcopenshell.util.representation.get_representation(wall, self.body):
|
||||||
ifcopenshell.util.element.replace_element(old_rep, rep)
|
ifcopenshell.util.element.replace_element(old_rep, rep)
|
||||||
@@ -371,8 +458,9 @@ class Foo:
|
|||||||
# axes = self.get_axes(wall2, layers2)
|
# axes = self.get_axes(wall2, layers2)
|
||||||
reference1 = self.get_reference_line(wall1)
|
reference1 = self.get_reference_line(wall1)
|
||||||
reference2 = self.get_reference_line(wall2)
|
reference2 = self.get_reference_line(wall2)
|
||||||
axes1 = self.get_axes(wall1, reference1, layers1, self.angle)
|
wall_vectors2 = self.get_wall_vectors(wall2)
|
||||||
axes2 = self.get_axes(wall2, reference2, layers2, self.get_angle(wall2))
|
axes1 = self.get_axes(wall1, reference1, layers1, self.wall_vectors["a"])
|
||||||
|
axes2 = self.get_axes(wall2, reference2, layers2, wall_vectors2["a"])
|
||||||
matrix1i = np.linalg.inv(ifcopenshell.util.placement.get_local_placement(wall1.ObjectPlacement))
|
matrix1i = np.linalg.inv(ifcopenshell.util.placement.get_local_placement(wall1.ObjectPlacement))
|
||||||
matrix2 = ifcopenshell.util.placement.get_local_placement(wall2.ObjectPlacement)
|
matrix2 = ifcopenshell.util.placement.get_local_placement(wall2.ObjectPlacement)
|
||||||
print(axes1)
|
print(axes1)
|
||||||
@@ -384,6 +472,8 @@ class Foo:
|
|||||||
axis[1] = (matrix1i @ matrix2 @ np.concatenate((axis[1], (0, 1))))[:2]
|
axis[1] = (matrix1i @ matrix2 @ np.concatenate((axis[1], (0, 1))))[:2]
|
||||||
reference2[0] = (matrix1i @ matrix2 @ np.concatenate((reference2[0], (0, 1))))[:2]
|
reference2[0] = (matrix1i @ matrix2 @ np.concatenate((reference2[0], (0, 1))))[:2]
|
||||||
reference2[1] = (matrix1i @ matrix2 @ np.concatenate((reference2[1], (0, 1))))[:2]
|
reference2[1] = (matrix1i @ matrix2 @ np.concatenate((reference2[1], (0, 1))))[:2]
|
||||||
|
wall_vectors2["z"] = (matrix1i @ matrix2 @ np.append(wall_vectors2["z"], 0.0))[:3]
|
||||||
|
wall_vectors2["y"] = (matrix1i @ matrix2 @ np.append(wall_vectors2["y"], 0.0))[:3]
|
||||||
|
|
||||||
# Sort axes from interior to exterior
|
# Sort axes from interior to exterior
|
||||||
if connection1 == "ATEND":
|
if connection1 == "ATEND":
|
||||||
@@ -446,6 +536,8 @@ class Foo:
|
|||||||
# Categorise our points into a segment that either splits or cuts the wall
|
# Categorise our points into a segment that either splits or cuts the wall
|
||||||
split_ys = {first_y, last_y}
|
split_ys = {first_y, last_y}
|
||||||
segment = []
|
segment = []
|
||||||
|
atpath_vector = self.get_join_vector(self.wall_vectors["y"], wall_vectors2["y"])
|
||||||
|
self.atpath_points.append((atpath_vector, points))
|
||||||
for point in points:
|
for point in points:
|
||||||
segment.append(point)
|
segment.append(point)
|
||||||
if len(segment) == 1: # Not enough points to categorise the segment
|
if len(segment) == 1: # Not enough points to categorise the segment
|
||||||
@@ -488,9 +580,13 @@ class Foo:
|
|||||||
|
|
||||||
if connection1 == "ATSTART":
|
if connection1 == "ATSTART":
|
||||||
self.start_points = points
|
self.start_points = points
|
||||||
|
self.start_vector = self.get_join_vector(self.wall_vectors["y"], wall_vectors2["y"])
|
||||||
|
self.start_offset = (self.start_vector * (self.wall_vectors["h"] / self.start_vector[2]))[0]
|
||||||
self.reference_p1[0] = self.intersect_axis(*reference2, y=reference1[0][1])
|
self.reference_p1[0] = self.intersect_axis(*reference2, y=reference1[0][1])
|
||||||
elif connection1 == "ATEND":
|
elif connection1 == "ATEND":
|
||||||
self.end_points = points
|
self.end_points = points
|
||||||
|
self.end_vector = self.get_join_vector(self.wall_vectors["y"], wall_vectors2["y"])
|
||||||
|
self.end_offset = (self.end_vector * (self.wall_vectors["h"] / self.end_vector[2]))[0]
|
||||||
self.reference_p2[0] = self.intersect_axis(*reference2, y=reference1[0][1])
|
self.reference_p2[0] = self.intersect_axis(*reference2, y=reference1[0][1])
|
||||||
else:
|
else:
|
||||||
last_y = axes1[-1][0][1]
|
last_y = axes1[-1][0][1]
|
||||||
@@ -532,9 +628,13 @@ class Foo:
|
|||||||
|
|
||||||
if connection1 == "ATSTART":
|
if connection1 == "ATSTART":
|
||||||
self.start_points = points
|
self.start_points = points
|
||||||
|
self.start_vector = self.get_join_vector(self.wall_vectors["y"], wall_vectors2["y"])
|
||||||
|
self.start_offset = (self.start_vector * (self.wall_vectors["h"] / self.start_vector[2]))[0]
|
||||||
self.reference_p1[0] = self.intersect_axis(*reference2, y=reference1[0][1])
|
self.reference_p1[0] = self.intersect_axis(*reference2, y=reference1[0][1])
|
||||||
elif connection1 == "ATEND":
|
elif connection1 == "ATEND":
|
||||||
self.end_points = points
|
self.end_points = points
|
||||||
|
self.end_vector = self.get_join_vector(self.wall_vectors["y"], wall_vectors2["y"])
|
||||||
|
self.end_offset = (self.end_vector * (self.wall_vectors["h"] / self.end_vector[2]))[0]
|
||||||
self.reference_p2[0] = self.intersect_axis(*reference2, y=reference1[0][1])
|
self.reference_p2[0] = self.intersect_axis(*reference2, y=reference1[0][1])
|
||||||
|
|
||||||
def get_layers(self, wall) -> list:
|
def get_layers(self, wall) -> list:
|
||||||
@@ -581,14 +681,38 @@ class Foo:
|
|||||||
return [np.array(points[1]), np.array(points[0])]
|
return [np.array(points[1]), np.array(points[0])]
|
||||||
return [np.array((0.0, 0.0)), np.array((1.0, 0.0))]
|
return [np.array((0.0, 0.0)), np.array((1.0, 0.0))]
|
||||||
|
|
||||||
def get_angle(self, wall):
|
def get_wall_vectors(self, wall):
|
||||||
if body := ifcopenshell.util.representation.get_representation(wall, "Model", "Body", "MODEL_VIEW"):
|
if body := ifcopenshell.util.representation.get_representation(wall, "Model", "Body", "MODEL_VIEW"):
|
||||||
for item in ifcopenshell.util.representation.resolve_representation(body).Items:
|
for item in ifcopenshell.util.representation.resolve_representation(body).Items:
|
||||||
|
while item.is_a("IfcBooleanResult"):
|
||||||
|
item = item.FirstOperand
|
||||||
if item.is_a("IfcExtrudedAreaSolid"):
|
if item.is_a("IfcExtrudedAreaSolid"):
|
||||||
return ifcopenshell.util.shape_builder.np_angle_signed(
|
z = np.array(item.ExtrudedDirection.DirectionRatios)
|
||||||
np.array((0.0, 1.0)), np.array(item.ExtrudedDirection.DirectionRatios[1:])
|
z /= np.linalg.norm(z)
|
||||||
)
|
y = np.cross(z, np.array((1.0, 0.0, 0.0)))
|
||||||
return 0.0
|
d = item.Depth
|
||||||
|
h = (z * d)[2]
|
||||||
|
a = ifcopenshell.util.shape_builder.np_angle_signed(np.array((0.0, 1.0)), z[1:])
|
||||||
|
if not ifcopenshell.util.shape_builder.is_x(a, 0):
|
||||||
|
self.is_angled = True
|
||||||
|
return {"z": z, "y": y, "a": a, "d": d, "h": h}
|
||||||
|
elif self.fallback_angle:
|
||||||
|
a = self.fallback_angle
|
||||||
|
z = np.array([0.0, sin(a), cos(a)])
|
||||||
|
y = np.cross(z, np.array((1.0, 0.0, 0.0)))
|
||||||
|
h = 1.0 # unit scale
|
||||||
|
d = np.linalg.norm(z * (h / z[2]))
|
||||||
|
if not ifcopenshell.util.shape_builder.is_x(a, 0):
|
||||||
|
self.is_angled = True
|
||||||
|
return {"z": z, "y": y, "a": a, "d": d, "h": h}
|
||||||
|
# unit scale
|
||||||
|
return {"z": np.array((0.0, 0.0, 1.0)), "y": np.array((0.0, 1.0, 0.0)), "a": 0.0, "d": 1.0, "h": 1.0}
|
||||||
|
|
||||||
|
def get_join_vector(self, y1, y2):
|
||||||
|
result = np.cross(y1, y2)
|
||||||
|
if result[2] < 0:
|
||||||
|
return result * -1
|
||||||
|
return result
|
||||||
|
|
||||||
def get_axes(self, wall, reference, layers: list[PrioritisedLayer], angle: float):
|
def get_axes(self, wall, reference, layers: list[PrioritisedLayer], angle: float):
|
||||||
axes = [[p.copy() for p in reference]]
|
axes = [[p.copy() for p in reference]]
|
||||||
@@ -605,13 +729,13 @@ class Foo:
|
|||||||
return axes
|
return axes
|
||||||
|
|
||||||
|
|
||||||
test_wall(0, 1, 1, 1, 1)
|
test_wall(0, 1, 1, 1, 1, radians(10))
|
||||||
test_wall(1, 2, 1, 1, 2)
|
test_wall(1, 2, 1, 1, 2, radians(10))
|
||||||
test_wall(2, 2, 1, 1, 1)
|
test_wall(2, 2, 1, 1, 1, radians(10))
|
||||||
test_wall(3, 1, 2, 1, 1)
|
test_wall(3, 1, 2, 1, 1, radians(10))
|
||||||
test_wall(4, 1, 2, 1, 2)
|
test_wall(4, 1, 2, 1, 2, radians(10))
|
||||||
test_wall(5, 3, 1, 2, 4)
|
test_wall(5, 3, 1, 2, 4, radians(10))
|
||||||
test_atpath(7)
|
test_atpath(7, radians(10))
|
||||||
|
|
||||||
|
|
||||||
f.write("/home/dion/wall.ifc")
|
f.write("/home/dion/wall.ifc")
|
||||||
|
|||||||
Reference in New Issue
Block a user