@@ -4222,7 +4222,7 @@ def _get_edges(s: Shape) -> Iterable[Shape]:
4222
4222
4223
4223
def _get_wire_lists (s : Sequence [Shape ]) -> List [List [Wire ]]:
4224
4224
"""
4225
- Get lists or wires for sweeping or lofting.
4225
+ Get lists of wires for sweeping or lofting.
4226
4226
"""
4227
4227
4228
4228
wire_lists : List [List [Wire ]] = []
@@ -4237,6 +4237,23 @@ def _get_wire_lists(s: Sequence[Shape]) -> List[List[Wire]]:
4237
4237
return wire_lists
4238
4238
4239
4239
4240
+ def _get_face_lists (s : Sequence [Shape ]) -> List [List [Face ]]:
4241
+ """
4242
+ Get lists of faces for sweeping or lofting.
4243
+ """
4244
+
4245
+ face_lists : List [List [Face ]] = []
4246
+
4247
+ for el in s :
4248
+ if not face_lists :
4249
+ face_lists = [[f ] for f in el .Faces ()]
4250
+ else :
4251
+ for face_list , f in zip (face_lists , el .Faces ()):
4252
+ face_list .append (f )
4253
+
4254
+ return face_lists
4255
+
4256
+
4240
4257
def _normalize (s : Shape ) -> Shape :
4241
4258
"""
4242
4259
Apply some normalizations:
@@ -4482,7 +4499,7 @@ def rect(w: float, h: float) -> Shape:
4482
4499
@multimethod
4483
4500
def spline (* pts : VectorLike , tol : float = 1e-6 , periodic : bool = False ) -> Shape :
4484
4501
"""
4485
- Construct a polygon (closed polyline) from points.
4502
+ Construct a spline from points.
4486
4503
"""
4487
4504
4488
4505
data = _pts_to_harray (pts )
@@ -4910,74 +4927,165 @@ def offset(s: Shape, t: float, cap=True, tol: float = 1e-6) -> Shape:
4910
4927
@multimethod
4911
4928
def sweep (s : Shape , path : Shape , cap : bool = False ) -> Shape :
4912
4929
"""
4913
- Sweep edge or wire along a path.
4930
+ Sweep edge, wire or face along a path. For faces cap has no effect.
4931
+ Do not mix faces with other types.
4914
4932
"""
4915
4933
4916
4934
spine = _get_one_wire (path )
4917
4935
4918
4936
results = []
4919
4937
4920
- for w in _get_wires (s ):
4921
- builder = BRepOffsetAPI_MakePipeShell (spine .wrapped )
4922
- builder .Add (w .wrapped , False , False )
4923
- builder .Build ()
4938
+ # try to get faces
4939
+ faces = s .Faces ()
4924
4940
4925
- if cap :
4926
- builder .MakeSolid ()
4941
+ # if faces were supplied
4942
+ if faces :
4943
+ for f in faces :
4944
+ tmp = sweep (f .outerWire (), path , True )
4927
4945
4928
- results .append (builder .Shape ())
4946
+ # if needed subtract two sweeps
4947
+ inner_wires = f .innerWires ()
4948
+ if inner_wires :
4949
+ tmp -= sweep (compound (inner_wires ), path , True )
4950
+
4951
+ results .append (tmp .wrapped )
4952
+
4953
+ # otherwise sweep wires
4954
+ else :
4955
+ for w in _get_wires (s ):
4956
+ builder = BRepOffsetAPI_MakePipeShell (spine .wrapped )
4957
+ builder .Add (w .wrapped , False , False )
4958
+ builder .Build ()
4959
+
4960
+ if cap :
4961
+ builder .MakeSolid ()
4962
+
4963
+ results .append (builder .Shape ())
4929
4964
4930
4965
return _compound_or_shape (results )
4931
4966
4932
4967
4933
4968
@sweep .register
4934
4969
def sweep (s : Sequence [Shape ], path : Shape , cap : bool = False ) -> Shape :
4935
4970
"""
4936
- Sweep edges or wires along a path, chaining sections are supported.
4971
+ Sweep edges, wires or faces along a path, multiple sections are supported.
4972
+ For faces cap has no effect. Do not mix faces with other types.
4937
4973
"""
4938
4974
4939
4975
spine = _get_one_wire (path )
4940
4976
4941
4977
results = []
4942
4978
4943
- # construct sweeps
4944
- for el in _get_wire_lists (s ):
4979
+ # try to construct sweeps using faces
4980
+ for el in _get_face_lists (s ):
4981
+ # build outer part
4945
4982
builder = BRepOffsetAPI_MakePipeShell (spine .wrapped )
4946
4983
4947
- for w in el :
4948
- builder .Add (w .wrapped , False , False )
4984
+ for f in el :
4985
+ builder .Add (f . outerWire () .wrapped , False , False )
4949
4986
4950
4987
builder .Build ()
4988
+ builder .MakeSolid ()
4951
4989
4952
- if cap :
4953
- builder . MakeSolid ()
4990
+ # build inner parts
4991
+ builders_inner = []
4954
4992
4955
- results .append (builder .Shape ())
4993
+ # initialize builders
4994
+ for w in el [0 ].innerWires ():
4995
+ builder_inner = BRepOffsetAPI_MakePipeShell (spine .wrapped )
4996
+ builder_inner .Add (w .wrapped , False , False )
4997
+ builders_inner .append (builder_inner )
4998
+
4999
+ # add remaining sections
5000
+ for f in el [1 :]:
5001
+ for builder_inner , w in zip (builders_inner , f .innerWires ()):
5002
+ builder_inner .Add (w .wrapped , False , False )
5003
+
5004
+ # actually build
5005
+ inner_parts = []
5006
+
5007
+ for builder_inner in builders_inner :
5008
+ builder_inner .Build ()
5009
+ builder_inner .MakeSolid ()
5010
+ inner_parts .append (Shape (builder_inner .Shape ()))
5011
+
5012
+ results .append ((Shape (builder .Shape ()) - compound (inner_parts )).wrapped )
5013
+
5014
+ # if no faces were provided try with wires
5015
+ if not results :
5016
+ # construct sweeps
5017
+ for el in _get_wire_lists (s ):
5018
+ builder = BRepOffsetAPI_MakePipeShell (spine .wrapped )
5019
+
5020
+ for w in el :
5021
+ builder .Add (w .wrapped , False , False )
5022
+
5023
+ builder .Build ()
5024
+
5025
+ if cap :
5026
+ builder .MakeSolid ()
5027
+
5028
+ results .append (builder .Shape ())
4956
5029
4957
5030
return _compound_or_shape (results )
4958
5031
4959
5032
4960
5033
@multimethod
4961
5034
def loft (s : Sequence [Shape ], cap : bool = False , ruled : bool = False ) -> Shape :
4962
5035
"""
4963
- Loft edges or wires .
5036
+ Loft edges, wires or faces. For faces cap has no effect. Do not mix faces with other types .
4964
5037
"""
4965
5038
4966
5039
results = []
4967
-
4968
- # construct lofts
4969
5040
builder = BRepOffsetAPI_ThruSections ()
4970
5041
4971
- for el in _get_wire_lists (s ):
4972
- builder .Init (cap , ruled )
5042
+ # try to construct lofts using faces
5043
+ for el in _get_face_lists (s ):
5044
+ # build outer part
5045
+ builder .Init (True , ruled )
4973
5046
4974
- for w in el :
4975
- builder .AddWire (w .wrapped )
5047
+ for f in el :
5048
+ builder .AddWire (f . outerWire () .wrapped )
4976
5049
4977
5050
builder .Build ()
4978
5051
builder .Check ()
4979
5052
4980
- results .append (builder .Shape ())
5053
+ builders_inner = []
5054
+
5055
+ # initialize builders
5056
+ for w in el [0 ].innerWires ():
5057
+ builder_inner = BRepOffsetAPI_ThruSections ()
5058
+ builder_inner .Init (True , ruled )
5059
+ builder_inner .AddWire (w .wrapped )
5060
+ builders_inner .append (builder_inner )
5061
+
5062
+ # add remaining sections
5063
+ for f in el [1 :]:
5064
+ for builder_inner , w in zip (builders_inner , f .innerWires ()):
5065
+ builder_inner .AddWire (w .wrapped )
5066
+
5067
+ # actually build
5068
+ inner_parts = []
5069
+
5070
+ for builder_inner in builders_inner :
5071
+ builder_inner .Build ()
5072
+ builder_inner .Check ()
5073
+ inner_parts .append (Shape (builder_inner .Shape ()))
5074
+
5075
+ results .append ((Shape (builder .Shape ()) - compound (inner_parts )).wrapped )
5076
+
5077
+ # otherwise construct using wires
5078
+ if not results :
5079
+ for el in _get_wire_lists (s ):
5080
+ builder .Init (cap , ruled )
5081
+
5082
+ for w in el :
5083
+ builder .AddWire (w .wrapped )
5084
+
5085
+ builder .Build ()
5086
+ builder .Check ()
5087
+
5088
+ results .append (builder .Shape ())
4981
5089
4982
5090
return _compound_or_shape (results )
4983
5091
0 commit comments