mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-13 10:57:49 +00:00
See #1227. Basic implementation of sloped walls (joins not yet considered)
This commit is contained in:
@@ -1043,7 +1043,8 @@ class Loader(bonsai.core.tool.Loader):
|
||||
bm.from_mesh(mesh)
|
||||
prev_co = None
|
||||
co = Vector((0.0, offset, 0.0))
|
||||
no = Vector((0.0, 1.0, 0.0))
|
||||
# no = Vector((0.0, 1.0, 0.0))
|
||||
no = (cls.get_extrusion_vector(element).cross(Vector([1., 0., 0.]))).normalized()
|
||||
# Cache this
|
||||
body = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW")
|
||||
styles = {}
|
||||
@@ -1053,7 +1054,8 @@ class Loader(bonsai.core.tool.Loader):
|
||||
styles[style] = i
|
||||
for layer in layer_set.MaterialLayers[:-1]:
|
||||
prev_co = co.copy()
|
||||
co.y += layer.LayerThickness * cls.unit_scale * sense_factor
|
||||
co += no * layer.LayerThickness * cls.unit_scale * sense_factor
|
||||
# co.y += layer.LayerThickness * cls.unit_scale * sense_factor
|
||||
bisect_geom = bmesh.ops.bisect_plane(
|
||||
bm, geom=bm.verts[:] + bm.edges[:] + bm.faces[:], dist=0.0001, plane_co=co, plane_no=no
|
||||
)
|
||||
@@ -1064,8 +1066,9 @@ class Loader(bonsai.core.tool.Loader):
|
||||
mesh.materials.append(tool.Ifc.get_object(style))
|
||||
for face in bisect_geom["geom"]:
|
||||
if isinstance(face, bmesh.types.BMFace):
|
||||
center = face.calc_center_bounds() * sense_factor
|
||||
if center.y < co.y and center.y > prev_co.y:
|
||||
center = face.calc_center_median()
|
||||
# if center.y < co.y and center.y > prev_co.y:
|
||||
if (center - co).dot(no) < 0 and (center - prev_co).dot(no) >= 0:
|
||||
face.material_index = material_index
|
||||
has_layer_styles = True
|
||||
|
||||
@@ -1077,8 +1080,9 @@ class Loader(bonsai.core.tool.Loader):
|
||||
mesh.materials.append(tool.Ifc.get_object(style))
|
||||
for face in bisect_geom["geom"]:
|
||||
if isinstance(face, bmesh.types.BMFace):
|
||||
center = face.calc_center_bounds() * sense_factor
|
||||
if center.y > co.y:
|
||||
center = face.calc_center_median() * sense_factor
|
||||
# if center.y > co.y:
|
||||
if (center - co).dot(no) >= 0:
|
||||
face.material_index = material_index
|
||||
has_layer_styles = True
|
||||
|
||||
@@ -1087,6 +1091,14 @@ class Loader(bonsai.core.tool.Loader):
|
||||
mesh["has_layer_styles"] = has_layer_styles
|
||||
return mesh
|
||||
|
||||
@classmethod
|
||||
def get_extrusion_vector(cls, wall):
|
||||
if body := ifcopenshell.util.representation.get_representation(wall, "Model", "Body", "MODEL_VIEW"):
|
||||
for item in ifcopenshell.util.representation.resolve_representation(body).Items:
|
||||
if item.is_a("IfcExtrudedAreaSolid"):
|
||||
return Vector(item.ExtrudedDirection.DirectionRatios)
|
||||
return Vector([0., 0., 1.])
|
||||
|
||||
@classmethod
|
||||
def create_mesh_from_shape(
|
||||
cls,
|
||||
|
||||
+26
-12
@@ -14,6 +14,7 @@ import ifcopenshell.util.element
|
||||
# from ifcopenshell.util.shape_builder import VectorType, SequenceOfVectors
|
||||
from itertools import cycle
|
||||
from collections import namedtuple
|
||||
from math import sin, cos, radians
|
||||
|
||||
f = ifcopenshell.api.project.create_file()
|
||||
|
||||
@@ -46,7 +47,7 @@ ifcopenshell.api.style.add_surface_style(f, style=style, ifc_class="IfcSurfaceSt
|
||||
ifcopenshell.api.style.assign_material_style(f, material=material2, style=style, context=body)
|
||||
|
||||
|
||||
def test_wall(offset, p1, p2, p3, p4):
|
||||
def test_wall(offset, p1, p2, p3, p4, a1=None, a2=None):
|
||||
offset *= 1.5
|
||||
wall_type_a = ifcopenshell.api.root.create_entity(f, ifc_class="IfcWallType", name="A")
|
||||
wall_type_b = ifcopenshell.api.root.create_entity(f, ifc_class="IfcWallType", name="B")
|
||||
@@ -162,7 +163,7 @@ def test_wall(offset, p1, p2, p3, p4):
|
||||
related_connection="ATSTART",
|
||||
)
|
||||
|
||||
Foo(f, body, axis).regenerate(wall_a)
|
||||
Foo(f, body, axis).regenerate(wall_a, angle=a1)
|
||||
Foo(f, body, axis).regenerate(wall_b)
|
||||
Foo(f, body, axis).regenerate(wall_c)
|
||||
|
||||
@@ -238,7 +239,7 @@ class Foo:
|
||||
self.body = body
|
||||
self.axis = axis
|
||||
|
||||
def regenerate(self, wall):
|
||||
def regenerate(self, wall, angle=None):
|
||||
print("-" * 100)
|
||||
print(wall)
|
||||
layers = self.get_layers(wall)
|
||||
@@ -246,7 +247,8 @@ class Foo:
|
||||
return
|
||||
reference = self.get_reference_line(wall)
|
||||
self.reference_p1, self.reference_p2 = reference
|
||||
axes = self.get_axes(wall, reference, layers)
|
||||
self.angle = angle or self.get_angle(wall)
|
||||
axes = self.get_axes(wall, reference, layers, self.angle)
|
||||
self.miny = axes[0][0][1]
|
||||
self.maxy = axes[-1][0][1]
|
||||
self.end_point = None
|
||||
@@ -342,7 +344,9 @@ class Foo:
|
||||
else:
|
||||
profile = profiles[0]
|
||||
|
||||
item = builder.extrude(profile, magnitude=1.0)
|
||||
item = builder.extrude(
|
||||
profile, magnitude=1.0, extrusion_vector=np.array([0.0, sin(self.angle), cos(self.angle)])
|
||||
)
|
||||
rep = builder.get_representation(self.body, items=[item])
|
||||
if old_rep := ifcopenshell.util.representation.get_representation(wall, self.body):
|
||||
ifcopenshell.util.element.replace_element(old_rep, rep)
|
||||
@@ -367,8 +371,8 @@ class Foo:
|
||||
# axes = self.get_axes(wall2, layers2)
|
||||
reference1 = self.get_reference_line(wall1)
|
||||
reference2 = self.get_reference_line(wall2)
|
||||
axes1 = self.get_axes(wall1, reference1, layers1)
|
||||
axes2 = self.get_axes(wall2, reference2, layers2)
|
||||
axes1 = self.get_axes(wall1, reference1, layers1, self.angle)
|
||||
axes2 = self.get_axes(wall2, reference2, layers2, self.get_angle(wall2))
|
||||
matrix1i = np.linalg.inv(ifcopenshell.util.placement.get_local_placement(wall1.ObjectPlacement))
|
||||
matrix2 = ifcopenshell.util.placement.get_local_placement(wall2.ObjectPlacement)
|
||||
print(axes1)
|
||||
@@ -444,14 +448,14 @@ class Foo:
|
||||
segment = []
|
||||
for point in points:
|
||||
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
|
||||
continue
|
||||
elif {segment[0][1], segment[-1][1]} == split_ys: # This segment splits the wall
|
||||
elif {segment[0][1], segment[-1][1]} == split_ys: # This segment splits the wall
|
||||
if segment[0][1] > segment[-1][1]: # Go in the +Y direction
|
||||
segment.reverse()
|
||||
self.split_points.append(segment)
|
||||
segment = []
|
||||
elif segment[0][1] == segment[-1][1]: # This segment cuts some of the wall
|
||||
elif segment[0][1] == segment[-1][1]: # This segment cuts some of the wall
|
||||
if segment[0][1] == self.maxy: # Go in the +X direction
|
||||
if segment[0][0] > segment[-1][0]:
|
||||
segment.reverse()
|
||||
@@ -577,7 +581,16 @@ class Foo:
|
||||
return [np.array(points[1]), np.array(points[0])]
|
||||
return [np.array((0.0, 0.0)), np.array((1.0, 0.0))]
|
||||
|
||||
def get_axes(self, wall, reference, layers: list[PrioritisedLayer]):
|
||||
def get_angle(self, wall):
|
||||
if body := ifcopenshell.util.representation.get_representation(wall, "Model", "Body", "MODEL_VIEW"):
|
||||
for item in ifcopenshell.util.representation.resolve_representation(body).Items:
|
||||
if item.is_a("IfcExtrudedAreaSolid"):
|
||||
return ifcopenshell.util.shape_builder.np_angle_signed(
|
||||
np.array((0.0, 1.0)), np.array(item.ExtrudedDirection.DirectionRatios[1:])
|
||||
)
|
||||
return 0.0
|
||||
|
||||
def get_axes(self, wall, reference, layers: list[PrioritisedLayer], angle: float):
|
||||
axes = [[p.copy() for p in reference]]
|
||||
# Apply usage to convert the Reference line into MlsBase
|
||||
sense_factor = 1
|
||||
@@ -587,7 +600,8 @@ class Foo:
|
||||
sense_factor = 1 if usage.DirectionSense == "POSITIVE" else -1
|
||||
|
||||
for layer in layers:
|
||||
axes.append([p.copy() + np.array((0.0, layer.thickness * sense_factor)) for p in axes[-1]])
|
||||
y_offset = (layer.thickness * sense_factor) / cos(angle)
|
||||
axes.append([p.copy() + np.array((0.0, y_offset)) for p in axes[-1]])
|
||||
return axes
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user