Skip to content

Commit 269ef7b

Browse files
committed
Add Evolved
1 parent 771898f commit 269ef7b

File tree

5 files changed

+178
-0
lines changed

5 files changed

+178
-0
lines changed

declaracad/occ/algo.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,17 @@ def set_fill_mode(self, mode: str):
177177
raise NotImplementedError
178178

179179

180+
class ProxyEvolved(ProxyOffset):
181+
#: A reference to the Shape declaration.
182+
declaration = ForwardTyped(lambda: Evolved)
183+
184+
def set_spline(self, spline: Optional[Union[Shape, TopoDS_Shape]]):
185+
raise NotImplementedError
186+
187+
def set_profile(self, profile: Optional[Union[Shape, TopoDS_Shape]]):
188+
raise NotImplementedError
189+
190+
180191
class ProxyAbstractRibSlot(ProxyOperation):
181192
#: Abstract class
182193

@@ -760,6 +771,57 @@ def _update_proxy(self, change: dict[str, Any]):
760771
super(Pipe, self)._update_proxy(change)
761772

762773

774+
class Evolved(Operation):
775+
"""An operation that extrudes a profile along a spline, wire, or path.
776+
777+
Attributes
778+
----------
779+
780+
spline: Edge or Wire
781+
The spline to extrude along.
782+
profile: Wire
783+
The profile to extrude.
784+
785+
Examples
786+
--------
787+
788+
See examples/evolved.enaml
789+
790+
"""
791+
792+
#: Reference to the implementation control
793+
proxy = Typed(ProxyEvolved)
794+
795+
#: Spline to make the evolve along. It must be closed.
796+
spline = d_(Instance(object))
797+
798+
#: Profile to make the evolved shaped from.
799+
#: This must be a planar Wire or Face.
800+
profile = d_(Instance(object))
801+
802+
#: Run in parallel
803+
parallel = d_(Bool(True))
804+
805+
#: Whether to fuse into a single solid or keep as a compound.
806+
solid = d_(Bool())
807+
808+
#: Remove self-intersections in the result
809+
volume = d_(Bool())
810+
811+
#: This axe prof flag
812+
global_axis = d_(Bool(True))
813+
814+
# Whether the profile must be connected to the spline
815+
require_profile_on_spline = d_(Bool())
816+
817+
#: Join type
818+
join_type = d_(Enum("arc", "tangent", "intersection"))
819+
820+
@observe("spline", "profile", "join_type", "solid", "volume", "global_axis")
821+
def _update_proxy(self, change: dict[str, Any]):
822+
super()._update_proxy(change)
823+
824+
763825
class AbstractRibSlot(Operation):
764826
#: Base shape
765827
shape = d_(Instance(Shape))

declaracad/occ/api.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
Common,
2121
Cut,
2222
DraftAngle,
23+
Evolved,
2324
Extend,
2425
Fillet,
2526
Fuse,

declaracad/occ/impl/occ_evolved.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"""
2+
Copyright (c) 2025, Jairus Martin.
3+
4+
Distributed under the terms of the GPL v3 License.
5+
6+
The full license is in the file LICENSE, distributed with this software.
7+
"""
8+
9+
from atom.api import Instance
10+
from OCCT.BRepBuilderAPI import BRepBuilderAPI_MakeWire
11+
from OCCT.BRepOffsetAPI import BRepOffsetAPI_MakeEvolved
12+
from OCCT.GeomAbs import GeomAbs_Arc, GeomAbs_Intersection, GeomAbs_Tangent
13+
from OCCT.TopoDS import TopoDS_Edge
14+
15+
from declaracad.occ.algo import ProxyEvolved
16+
17+
from .occ_algo import OccOperation, coerce_shape
18+
from .occ_shape import OccShape
19+
20+
21+
class OccEvolved(OccOperation, ProxyEvolved):
22+
reference = (
23+
"https://dev.opencascade.org/doc/refman/html/"
24+
"class_b_rep_offset_a_p_i___make_evolved.html"
25+
)
26+
27+
join_types = {
28+
"arc": GeomAbs_Arc,
29+
"tangent": GeomAbs_Tangent,
30+
"intersection": GeomAbs_Intersection,
31+
}
32+
33+
def update_shape(self, change=None):
34+
d = self.declaration
35+
36+
if d.spline and d.profile:
37+
spline, profile = d.spline, d.profile
38+
elif d.spline:
39+
spline = d.spline
40+
profile = self.get_first_child().shape
41+
elif d.profile:
42+
profile = d.profile
43+
spline = self.get_first_child().shape
44+
else:
45+
shapes = list(self.child_shapes())
46+
spline, profile = shapes[0:2]
47+
48+
args = [
49+
coerce_shape(spline),
50+
coerce_shape(profile),
51+
self.join_types[d.join_type],
52+
d.global_axis,
53+
d.solid,
54+
d.require_profile_on_spline,
55+
d.tolerance,
56+
d.volume,
57+
d.parallel,
58+
]
59+
60+
# Make sure spline is a wire
61+
for i, arg in enumerate(args[0:2]):
62+
if isinstance(arg, TopoDS_Edge):
63+
args[i] = BRepBuilderAPI_MakeWire(arg).Wire()
64+
65+
evolved = BRepOffsetAPI_MakeEvolved(*args)
66+
self.shape = evolved.Shape()
67+
68+
def set_spline(self, spline):
69+
self.update_shape()
70+
71+
def set_profile(self, profile):
72+
self.update_shape()

declaracad/occ/impl/occ_factories.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ def occ_ellipse_factory():
9191
return OccEllipse
9292

9393

94+
def occ_evolved_factory():
95+
from .occ_evolved import OccEvolved
96+
97+
return OccEvolved
98+
99+
94100
def occ_face_factory():
95101
from .occ_face import OccFace
96102

@@ -427,6 +433,7 @@ def occ_export_factory():
427433
"Chamfer": occ_chamfer_factory,
428434
"Cut": occ_cut_factory,
429435
"Common": occ_common_factory,
436+
"Evolved": occ_evolved_factory,
430437
"Fuse": occ_fuse_factory,
431438
"Intersection": occ_intersection_factory,
432439
"Split": occ_split_factory,

examples/evolved.enaml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from math import pi
2+
from enaml.core.api import Looper
3+
from declaracad.occ.api import (
4+
Axis, Part, Evolved, Polyline, Polygon, Circle, Ellipse, Rectangle, Arc
5+
)
6+
7+
8+
enamldef Assembly(Part):
9+
name = "Evolved"
10+
Axis:
11+
pass
12+
13+
Evolved:
14+
Ellipse:
15+
major_radius = 30
16+
minor_radius = 40
17+
Polygon:
18+
points = [
19+
(0, 2, 0),
20+
(0, -2, 0),
21+
(0, 0, 5),
22+
]
23+
24+
Evolved:
25+
26+
Polyline: poly:
27+
closed = True
28+
points = [
29+
(0, 0),
30+
(0, 10),
31+
(0, 20, 10),
32+
(0, 0, 10),
33+
]
34+
Circle:
35+
direction = (1, 0)
36+
radius = 2

0 commit comments

Comments
 (0)