Skip to content

Commit f25876b

Browse files
committed
Refactor: adding Loft's side edges
1 parent 0c6a59f commit f25876b

File tree

3 files changed

+76
-49
lines changed

3 files changed

+76
-49
lines changed

src/classy_blocks/construct/operations/operation.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from classy_blocks.base.element import ElementBase
77
from classy_blocks.base.exceptions import EdgeCreationError
88
from classy_blocks.base.transforms import Mirror
9-
from classy_blocks.construct.edges import EdgeData, Line, Project
9+
from classy_blocks.construct.edges import Arc, EdgeData, Line, Project, Spline
1010
from classy_blocks.construct.flat.face import Face
1111
from classy_blocks.construct.point import Point
1212
from classy_blocks.grading.chop import Chop
@@ -323,3 +323,40 @@ def transform(self, transforms):
323323
)
324324

325325
return super().transform(transforms)
326+
327+
@classmethod
328+
def from_series(cls, faces: List[Face]) -> "Operation":
329+
"""Creates a Loft from a list of faces.
330+
At least two are required.
331+
From faces in between, side edges are created:
332+
- 2 faces: no side edges
333+
- 3: Arcs
334+
- 4 or more: Splines"""
335+
if len(faces) < 2:
336+
raise ValueError("Provide at least two faces!")
337+
338+
loft = cls(faces[0], faces[-1])
339+
340+
if len(faces) == 2:
341+
return loft
342+
343+
edge_points: List[List[NPPointType]] = []
344+
345+
# collect points for splines on each side
346+
for i in range(4):
347+
points = []
348+
349+
for face in faces[1:-1]:
350+
points.append(face.points[i].position)
351+
352+
edge_points.append(points)
353+
354+
# add edges according to collected points
355+
for i in range(4):
356+
if len(edge_points[i]) == 1:
357+
loft.add_side_edge(i, Arc(edge_points[i][0]))
358+
continue
359+
360+
loft.add_side_edge(i, Spline(edge_points[i]))
361+
362+
return loft

src/classy_blocks/construct/shape.py

Lines changed: 3 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@
66
import numpy as np
77

88
from classy_blocks.base.element import ElementBase
9-
from classy_blocks.construct.edges import Angle, Arc, Spline
9+
from classy_blocks.construct.edges import Angle
1010
from classy_blocks.construct.flat.sketch import Sketch, SketchT
1111
from classy_blocks.construct.operations.loft import Loft
1212
from classy_blocks.construct.operations.operation import Operation
1313
from classy_blocks.types import AxisType, NPPointType, VectorType
14-
from classy_blocks.util import constants
1514
from classy_blocks.util import functions as f
1615

1716
ShapeT = TypeVar("ShapeT", bound="Shape")
@@ -83,51 +82,8 @@ def __init__(
8382
for j, face_1 in enumerate(list_1):
8483
face_2 = self.sketch_2.grid[i][j]
8584

86-
loft = Loft(face_1, face_2)
87-
88-
# add edges, if applicable
89-
if len(sketch_mid) > 0:
90-
# Create arc from sketch_mid if only one present
91-
if len(self.sketch_mid) == 1:
92-
face_mid = self.sketch_mid[0].grid[i][j]
93-
for k, point in enumerate(face_mid.points):
94-
sketch_1_point = self.sketch_1.grid[i][j].points[k].position
95-
sketch_2_point = self.sketch_2.grid[i][j].points[k].position
96-
# If not linear, make arc
97-
if (
98-
abs(
99-
abs(
100-
np.dot(sketch_1_point - point.position, sketch_1_point - sketch_2_point)
101-
/ f.norm(sketch_1_point - point.position)
102-
)
103-
- 1
104-
)
105-
> constants.TOL
106-
):
107-
loft.add_side_edge(k, Arc(point.position))
108-
109-
# Create spline from multiple sketch_mid
110-
else:
111-
face_mid = [sketch_mid_i.grid[i][j] for sketch_mid_i in self.sketch_mid]
112-
for k in range(len(face_mid[0].points)):
113-
sketch_1_point = self.sketch_1.grid[i][j].points[k].position
114-
sketch_2_point = self.sketch_2.grid[i][j].points[k].position
115-
points = [face_mid_i.points[k].position for face_mid_i in face_mid]
116-
# If not linear, make spline
117-
if any(
118-
[
119-
abs(
120-
abs(
121-
np.dot(sketch_1_point - p, sketch_1_point - sketch_2_point)
122-
/ f.norm(sketch_1_point - p)
123-
)
124-
- 1
125-
)
126-
> constants.TOL
127-
for p in points
128-
]
129-
):
130-
loft.add_side_edge(k, Spline(points))
85+
mid_faces = [sketch.grid[i][j] for sketch in sketch_mid]
86+
loft = Loft.from_series([face_1, *mid_faces, face_2])
13187

13288
self.lofts[-1].append(loft)
13389

tests/test_construct/test_operation/test_operation.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from classy_blocks.base.exceptions import EdgeCreationError
77
from classy_blocks.base.transforms import Mirror
8-
from classy_blocks.construct.edges import Arc, Project
8+
from classy_blocks.construct.edges import Arc, Project, Spline
99
from classy_blocks.construct.flat.face import Face
1010
from classy_blocks.construct.operations.extrude import Extrude
1111
from classy_blocks.construct.operations.loft import Loft
@@ -154,6 +154,40 @@ def test_get_normal_face(self, point, orient):
154154

155155
np.testing.assert_array_equal(normal_face.center, self.loft.get_face(orient).center)
156156

157+
def test_from_series_error(self):
158+
"""Raise an error when creating from a single face"""
159+
with self.assertRaises(ValueError):
160+
Loft.from_series([self.loft.top_face])
161+
162+
def test_from_series_2(self):
163+
loft_1 = self.loft
164+
loft_2 = Loft.from_series([loft_1.bottom_face, loft_1.top_face])
165+
166+
np.testing.assert_equal(loft_1.center, loft_2.center)
167+
168+
def test_from_series_3(self):
169+
loft = self.loft
170+
faces = [loft.bottom_face, loft.bottom_face.copy().translate([0, 0, 0.5]), loft.top_face]
171+
172+
new_loft = Loft.from_series(faces)
173+
174+
for i in range(4):
175+
self.assertIsInstance(new_loft.side_edges[i], Arc)
176+
177+
def test_from_series_4(self):
178+
loft = self.loft
179+
faces = [
180+
loft.bottom_face,
181+
loft.bottom_face.copy().translate([0, 0, 0.33]),
182+
loft.bottom_face.copy().translate([0, 0, 0.66]),
183+
loft.top_face,
184+
]
185+
186+
new_loft = Loft.from_series(faces)
187+
188+
for i in range(4):
189+
self.assertIsInstance(new_loft.side_edges[i], Spline)
190+
157191

158192
class OperationProjectionTests(BlockTestCase):
159193
"""Operation: projections"""

0 commit comments

Comments
 (0)