294
294
295
295
from OCP .ShapeCustom import ShapeCustom , ShapeCustom_RestrictionParameters
296
296
297
- from OCP .BRepAlgo import BRepAlgo
297
+ from OCP .BRepAlgo import BRepAlgo , BRepAlgo_NormalProjection
298
298
299
299
from OCP .ChFi2d import ChFi2d_FilletAPI # For Wire.Fillet()
300
300
@@ -2216,15 +2216,15 @@ def project(
2216
2216
self : T1D , face : "Face" , d : VectorLike , closest : bool = True
2217
2217
) -> Union [T1D , List [T1D ]]:
2218
2218
"""
2219
- Project onto a face along the specified direction
2219
+ Project onto a face along the specified direction.
2220
2220
"""
2221
2221
2222
- bldr = BRepProj_Projection (self .wrapped , face .wrapped , Vector (d ).toDir ())
2223
- shapes = Compound (bldr .Shape ())
2224
-
2225
2222
# select the closest projection if requested
2226
2223
rv : Union [T1D , List [T1D ]]
2227
2224
2225
+ bldr = BRepProj_Projection (self .wrapped , face .wrapped , Vector (d ).toDir ())
2226
+ shapes = Compound (bldr .Shape ())
2227
+
2228
2228
if closest :
2229
2229
2230
2230
dist_calc = BRepExtrema_DistShapeShape ()
@@ -3555,6 +3555,20 @@ def extend(
3555
3555
3556
3556
return self .__class__ (rv )
3557
3557
3558
+ def addHole (self , * inner : Wire | Edge ) -> Self :
3559
+ """
3560
+ Add one or more holes.
3561
+ """
3562
+
3563
+ bldr = BRepBuilderAPI_MakeFace (self .wrapped )
3564
+
3565
+ for w in inner :
3566
+ bldr .Add (
3567
+ TopoDS .Wire_s (w .wrapped if isinstance (w , Wire ) else wire (w ).wrapped )
3568
+ )
3569
+
3570
+ return self .__class__ (bldr .Face ()).fix ()
3571
+
3558
3572
3559
3573
class Shell (Shape ):
3560
3574
"""
@@ -5082,6 +5096,8 @@ def _adaptor_curve_to_edge(crv: Adaptor3d_Curve, p1: float, p2: float) -> TopoDS
5082
5096
5083
5097
#%% alternative constructors
5084
5098
5099
+ ShapeHistory = Dict [Union [Shape , str ], Shape ]
5100
+
5085
5101
5086
5102
@multimethod
5087
5103
def wire (* s : Shape ) -> Shape :
@@ -5131,21 +5147,54 @@ def face(s: Sequence[Shape]) -> Shape:
5131
5147
return face (* s )
5132
5148
5133
5149
5150
+ def _process_sewing_history (
5151
+ builder : BRepBuilderAPI_Sewing , faces : List [Face ], history : Optional [ShapeHistory ],
5152
+ ):
5153
+ """
5154
+ Reusable helper for processing sewing history.
5155
+ """
5156
+
5157
+ # fill history if provided
5158
+ if history is not None :
5159
+ # collect shapes present in the history dict
5160
+ for k , v in history .items ():
5161
+ if isinstance (k , str ):
5162
+ history [k ] = Face (builder .Modified (v .wrapped ))
5163
+
5164
+ # store all top-level shape relations
5165
+ for f in faces :
5166
+ history [f ] = Face (builder .Modified (f .wrapped ))
5167
+
5168
+
5134
5169
@multimethod
5135
- def shell (* s : Shape , tol : float = 1e-6 ) -> Shape :
5170
+ def shell (
5171
+ * s : Shape ,
5172
+ tol : float = 1e-6 ,
5173
+ manifold : bool = True ,
5174
+ ctx : Optional [Sequence [Shape ] | Shape ] = None ,
5175
+ history : Optional [ShapeHistory ] = None ,
5176
+ ) -> Shape :
5136
5177
"""
5137
- Build shell from faces.
5178
+ Build shell from faces. If ctx is specified, local sewing is performed.
5138
5179
"""
5139
5180
5140
- builder = BRepBuilderAPI_Sewing (tol )
5181
+ builder = BRepBuilderAPI_Sewing (tol , option4 = not manifold )
5182
+ if ctx :
5183
+ if isinstance (ctx , Shape ):
5184
+ builder .Load (ctx .wrapped )
5185
+ else :
5186
+ builder .Load (compound (ctx ).wrapped )
5187
+
5188
+ faces : list [Face ] = []
5141
5189
5142
5190
for el in s :
5143
5191
for f in _get (el , "Face" ):
5144
5192
builder .Add (f .wrapped )
5193
+ faces .append (f )
5145
5194
5146
5195
builder .Perform ()
5147
-
5148
5196
sewed = builder .SewedShape ()
5197
+ _process_sewing_history (builder , faces , history )
5149
5198
5150
5199
# for one face sewing will not produce a shell
5151
5200
if sewed .ShapeType () == TopAbs_ShapeEnum .TopAbs_FACE :
@@ -5162,16 +5211,24 @@ def shell(*s: Shape, tol: float = 1e-6) -> Shape:
5162
5211
5163
5212
5164
5213
@shell .register
5165
- def shell (s : Sequence [Shape ], tol : float = 1e-6 ) -> Shape :
5214
+ def shell (
5215
+ s : Sequence [Shape ],
5216
+ tol : float = 1e-6 ,
5217
+ manifold : bool = True ,
5218
+ ctx : Optional [Sequence [Shape ] | Shape ] = None ,
5219
+ history : Optional [ShapeHistory ] = None ,
5220
+ ) -> Shape :
5166
5221
"""
5167
- Build shell from a sequence of faces.
5222
+ Build shell from a sequence of faces. If ctx is specified, local sewing is performed.
5168
5223
"""
5169
5224
5170
- return shell (* s , tol = tol )
5225
+ return shell (* s , tol = tol , manifold = manifold , ctx = ctx , history = history )
5171
5226
5172
5227
5173
5228
@multimethod
5174
- def solid (s1 : Shape , * sn : Shape , tol : float = 1e-6 ) -> Shape :
5229
+ def solid (
5230
+ s1 : Shape , * sn : Shape , tol : float = 1e-6 , history : Optional [ShapeHistory ] = None ,
5231
+ ) -> Shape :
5175
5232
"""
5176
5233
Build solid from faces or shells.
5177
5234
"""
@@ -5186,7 +5243,7 @@ def solid(s1: Shape, *sn: Shape, tol: float = 1e-6) -> Shape:
5186
5243
shells = [el .wrapped for el in shells_faces if el .ShapeType () == "Shell" ]
5187
5244
if not shells :
5188
5245
faces = [el for el in shells_faces ]
5189
- shells = [shell (* faces , tol = tol ).wrapped ]
5246
+ shells = [shell (* faces , tol = tol , history = history ).wrapped ]
5190
5247
5191
5248
rvs = [builder .SolidFromShell (sh ) for sh in shells ]
5192
5249
@@ -5195,17 +5252,20 @@ def solid(s1: Shape, *sn: Shape, tol: float = 1e-6) -> Shape:
5195
5252
5196
5253
@solid .register
5197
5254
def solid (
5198
- s : Sequence [Shape ], inner : Optional [Sequence [Shape ]] = None , tol : float = 1e-6
5255
+ s : Sequence [Shape ],
5256
+ inner : Optional [Sequence [Shape ]] = None ,
5257
+ tol : float = 1e-6 ,
5258
+ history : Optional [ShapeHistory ] = None ,
5199
5259
) -> Shape :
5200
5260
"""
5201
5261
Build solid from a sequence of faces.
5202
5262
"""
5203
5263
5204
5264
builder = BRepBuilderAPI_MakeSolid ()
5205
- builder .Add (shell (* s , tol = tol ).wrapped )
5265
+ builder .Add (shell (* s , tol = tol , history = history ).wrapped )
5206
5266
5207
5267
if inner :
5208
- for sh in _get (shell (* inner , tol = tol ), "Shell" ):
5268
+ for sh in _get (shell (* inner , tol = tol , history = history ), "Shell" ):
5209
5269
builder .Add (sh .wrapped )
5210
5270
5211
5271
# fix orientations
@@ -5741,7 +5801,7 @@ def imprint(
5741
5801
* shapes : Shape ,
5742
5802
tol : float = 0.0 ,
5743
5803
glue : GlueLiteral = "full" ,
5744
- history : Optional [Dict [ Union [ Shape , str ], Shape ] ] = None ,
5804
+ history : Optional [ShapeHistory ] = None ,
5745
5805
) -> Shape :
5746
5806
"""
5747
5807
Imprint arbitrary number of shapes.
@@ -6199,6 +6259,29 @@ def loft(
6199
6259
return loft (s , cap , ruled , continuity , parametrization , degree , compat )
6200
6260
6201
6261
6262
+ def project (
6263
+ s : Shape ,
6264
+ base : Shape ,
6265
+ continuity : Literal ["C1" , "C2" , "C3" ] = "C2" ,
6266
+ degree : int = 3 ,
6267
+ maxseg : int = 30 ,
6268
+ tol : float = 1e-4 ,
6269
+ ):
6270
+ """
6271
+ Project s onto base using normal projection.
6272
+ """
6273
+
6274
+ bldr = BRepAlgo_NormalProjection (base .wrapped )
6275
+ bldr .SetParams (tol , tol ** (2 / 3 ), _to_geomabshape (continuity ), degree , maxseg )
6276
+
6277
+ for el in _get_edges (s ):
6278
+ bldr .Add (s .wrapped )
6279
+
6280
+ bldr .Build ()
6281
+
6282
+ return _compound_or_shape (bldr .Projection ())
6283
+
6284
+
6202
6285
#%% diagnotics
6203
6286
6204
6287
0 commit comments