19
19
20
20
from io import BytesIO
21
21
22
+
22
23
from vtkmodules .vtkCommonDataModel import vtkPolyData
23
24
from vtkmodules .vtkFiltersCore import vtkTriangleFilter , vtkPolyDataNormals
24
25
59
60
)
60
61
61
62
# Array of points (used for B-spline construction):
62
- from OCP .TColgp import TColgp_HArray1OfPnt , TColgp_HArray2OfPnt , TColgp_Array1OfPnt
63
+ from OCP .TColgp import (
64
+ TColgp_HArray1OfPnt ,
65
+ TColgp_HArray2OfPnt ,
66
+ TColgp_Array1OfPnt ,
67
+ TColgp_HArray1OfPnt2d ,
68
+ )
63
69
64
70
# Array of vectors (used for B-spline interpolation):
65
71
from OCP .TColgp import TColgp_Array1OfVec
162
168
)
163
169
from OCP .Geom2d import Geom2d_Line
164
170
171
+ from OCP .Geom2dAPI import Geom2dAPI_Interpolate
172
+
165
173
from OCP .BRepLib import BRepLib , BRepLib_FindSurface
166
174
167
175
from OCP .BRepOffsetAPI import (
260
268
261
269
from OCP .ShapeAnalysis import (
262
270
ShapeAnalysis_FreeBounds ,
271
+ ShapeAnalysis_Edge ,
263
272
ShapeAnalysis_Wire ,
264
273
ShapeAnalysis_Surface ,
265
274
)
@@ -1827,6 +1836,9 @@ def _curve_and_param(
1827
1836
) -> Tuple [Union [BRepAdaptor_Curve , BRepAdaptor_CompCurve ], float ]:
1828
1837
...
1829
1838
1839
+ def bounds (self ) -> Tuple [float , float ]:
1840
+ ...
1841
+
1830
1842
def paramAt (self , d : float ) -> float :
1831
1843
...
1832
1844
@@ -1857,6 +1869,13 @@ def paramsLength(self, locations: Iterable[float]) -> List[float]:
1857
1869
class Mixin1D (object ):
1858
1870
def _bounds (self : Mixin1DProtocol ) -> Tuple [float , float ]:
1859
1871
1872
+ return self .bounds ()
1873
+
1874
+ def bounds (self : Mixin1DProtocol ) -> Tuple [float , float ]:
1875
+ """
1876
+ Parametric bounds of the curve.
1877
+ """
1878
+
1860
1879
curve = self ._geomAdaptor ()
1861
1880
return curve .FirstParameter (), curve .LastParameter ()
1862
1881
@@ -2370,6 +2389,13 @@ def trim(self, u0: Real, u1: Real) -> "Edge":
2370
2389
2371
2390
return self .__class__ (bldr .Shape ())
2372
2391
2392
+ def hasPCurve (self , f : "Face" ) -> bool :
2393
+ """
2394
+ Check if self has a pcurve defined on f.
2395
+ """
2396
+
2397
+ return ShapeAnalysis_Edge ().HasPCurve (self .wrapped , f .wrapped )
2398
+
2373
2399
@classmethod
2374
2400
def makeCircle (
2375
2401
cls ,
@@ -3043,6 +3069,13 @@ def _geomAdaptor(self) -> Geom_Surface:
3043
3069
3044
3070
def _uvBounds (self ) -> Tuple [float , float , float , float ]:
3045
3071
3072
+ return self .uvBounds ()
3073
+
3074
+ def uvBounds (self ) -> Tuple [float , float , float , float ]:
3075
+ """
3076
+ Parametric bounds (u_min, u_max, v_min, v_max).
3077
+ """
3078
+
3046
3079
return BRepTools .UVBounds_s (self .wrapped )
3047
3080
3048
3081
def paramAt (self , pt : VectorLike ) -> Tuple [float , float ]:
@@ -3494,14 +3527,9 @@ def thicken(self, thickness: float) -> "Solid":
3494
3527
return Solid (builder .Shape ())
3495
3528
3496
3529
@classmethod
3497
- def constructOn (cls , f : "Face" , outer : "Wire" , * inner : "Wire" ) -> "Face" :
3498
-
3499
- bldr = BRepBuilderAPI_MakeFace (f ._geomAdaptor (), outer .wrapped )
3500
-
3501
- for w in inner :
3502
- bldr .Add (TopoDS .Wire_s (w .wrapped ))
3530
+ def constructOn (cls , f : "Face" , outer : "Wire" , * inner : "Wire" ) -> Self :
3503
3531
3504
- return cls ( bldr . Face ()). fix ( )
3532
+ return f . trim ( outer , * inner )
3505
3533
3506
3534
def project (self , other : "Face" , d : VectorLike ) -> "Face" :
3507
3535
@@ -3519,9 +3547,10 @@ def toArcs(self, tolerance: float = 1e-3) -> "Face":
3519
3547
3520
3548
return self .__class__ (BRepAlgo .ConvertFace_s (self .wrapped , tolerance ))
3521
3549
3522
- def trim (self , u0 : Real , u1 : Real , v0 : Real , v1 : Real , tol : Real = 1e-6 ) -> "Face" :
3550
+ @multimethod
3551
+ def trim (self , u0 : Real , u1 : Real , v0 : Real , v1 : Real , tol : Real = 1e-6 ) -> Self :
3523
3552
"""
3524
- Trim the face in the parametric space to (u0, u1).
3553
+ Trim the face in the (u,v) space to (u0, u1)x(v1, v2 ).
3525
3554
3526
3555
NB: this operation is done on the base geometry.
3527
3556
"""
@@ -3530,6 +3559,59 @@ def trim(self, u0: Real, u1: Real, v0: Real, v1: Real, tol: Real = 1e-6) -> "Fac
3530
3559
3531
3560
return self .__class__ (bldr .Shape ())
3532
3561
3562
+ @trim .register
3563
+ def _ (
3564
+ self ,
3565
+ pt1 : Tuple [Real , Real ],
3566
+ pt2 : Tuple [Real , Real ],
3567
+ pt3 : Tuple [Real , Real ],
3568
+ * pts : Tuple [Real , Real ],
3569
+ ) -> Self :
3570
+ """
3571
+ Trim the face using a polyline defined in the (u,v) space.
3572
+ """
3573
+
3574
+ segs_uv = []
3575
+ geom = self ._geomAdaptor ()
3576
+
3577
+ # build (u,v) segments
3578
+ for el1 , el2 in zip ((pt1 , pt2 , pt3 , * pts ), (pt2 , pt3 , * pts , pt1 )):
3579
+ segs_uv .append (GCE2d_MakeSegment (gp_Pnt2d (* el1 ), gp_Pnt2d (* el2 )).Value ())
3580
+
3581
+ # convert to edges
3582
+ edges = []
3583
+
3584
+ for seg in segs_uv :
3585
+ edges .append (BRepBuilderAPI_MakeEdge (seg , geom ).Edge ())
3586
+
3587
+ # convert to a wire
3588
+ builder = BRepBuilderAPI_MakeWire ()
3589
+
3590
+ tmp = TopTools_ListOfShape ()
3591
+ for edge in edges :
3592
+ tmp .Append (edge )
3593
+
3594
+ builder .Add (tmp )
3595
+
3596
+ w = builder .Wire ()
3597
+ BRepLib .BuildCurves3d_s (w )
3598
+
3599
+ # construct the final trimmed face
3600
+ return self .constructOn (self , Wire (w ))
3601
+
3602
+ @trim .register
3603
+ def _ (self , outer : Wire , * inner : Wire ) -> Self :
3604
+ """
3605
+ Trim using wires. The provided wires need to have a pcurve on self.
3606
+ """
3607
+
3608
+ bldr = BRepBuilderAPI_MakeFace (self ._geomAdaptor (), outer .wrapped )
3609
+
3610
+ for w in inner :
3611
+ bldr .Add (TopoDS .Wire_s (w .wrapped ))
3612
+
3613
+ return self .__class__ (bldr .Face ()).fix ()
3614
+
3533
3615
def isoline (self , param : Real , direction : Literal ["u" , "v" ] = "v" ) -> Edge :
3534
3616
"""
3535
3617
Construct an isoline.
@@ -4875,22 +4957,23 @@ def _get_wires(s: Shape) -> Iterable[Shape]:
4875
4957
raise ValueError (f"Required type(s): Edge, Wire; encountered { t } " )
4876
4958
4877
4959
4878
- def _get_edges (s : Shape ) -> Iterable [Shape ]:
4960
+ def _get_edges (* shapes : Shape ) -> Iterable [Shape ]:
4879
4961
"""
4880
- Get wires or wires from edges .
4962
+ Get edges or edges from wires .
4881
4963
"""
4882
4964
4883
- t = s .ShapeType ()
4884
-
4885
- if t == "Edge" :
4886
- yield s
4887
- elif t == "Wire" :
4888
- yield from _get_edges (s .edges ())
4889
- elif t == "Compound" :
4890
- for el in s :
4891
- yield from _get_edges (el )
4892
- else :
4893
- raise ValueError (f"Required type(s): Edge, Wire; encountered { t } " )
4965
+ for s in shapes :
4966
+ t = s .ShapeType ()
4967
+
4968
+ if t == "Edge" :
4969
+ yield s
4970
+ elif t == "Wire" :
4971
+ yield from _get_edges (s .edges ())
4972
+ elif t == "Compound" :
4973
+ for el in s :
4974
+ yield from _get_edges (el )
4975
+ else :
4976
+ raise ValueError (f"Required type(s): Edge, Wire; encountered { t } " )
4894
4977
4895
4978
4896
4979
def _get_wire_lists (s : Sequence [Shape ]) -> List [List [Union [Wire , Vertex ]]]:
@@ -5017,7 +5100,7 @@ def _compound_or_shape(s: Union[TopoDS_Shape, List[TopoDS_Shape]]) -> Shape:
5017
5100
5018
5101
def _pts_to_harray (pts : Sequence [VectorLike ]) -> TColgp_HArray1OfPnt :
5019
5102
"""
5020
- Convert a sequence of Vecotor to a TColgp harray (OCCT specific).
5103
+ Convert a sequence of Vector to a TColgp harray (OCCT specific).
5021
5104
"""
5022
5105
5023
5106
rv = TColgp_HArray1OfPnt (1 , len (pts ))
@@ -5028,6 +5111,19 @@ def _pts_to_harray(pts: Sequence[VectorLike]) -> TColgp_HArray1OfPnt:
5028
5111
return rv
5029
5112
5030
5113
5114
+ def _pts_to_harray2D (pts : Sequence [Tuple [Real , Real ]]) -> TColgp_HArray1OfPnt2d :
5115
+ """
5116
+ Convert a sequence of 2d points to a TColgp harray (OCCT specific).
5117
+ """
5118
+
5119
+ rv = TColgp_HArray1OfPnt2d (1 , len (pts ))
5120
+
5121
+ for i , p in enumerate (pts ):
5122
+ rv .SetValue (i + 1 , gp_Pnt2d (* p ))
5123
+
5124
+ return rv
5125
+
5126
+
5031
5127
def _floats_to_harray (vals : Sequence [float ]) -> TColStd_HArray1OfReal :
5032
5128
"""
5033
5129
Convert a sequence of floats to a TColstd harray (OCCT specific).
@@ -5129,6 +5225,91 @@ def _adaptor_curve_to_edge(crv: Adaptor3d_Curve, p1: float, p2: float) -> TopoDS
5129
5225
ShapeHistory = Dict [Union [Shape , str ], Shape ]
5130
5226
5131
5227
5228
+ @multimethod
5229
+ def edgeOn (
5230
+ base : Shape ,
5231
+ pts : Sequence [Tuple [Real , Real ]],
5232
+ periodic : bool = False ,
5233
+ tol : float = 1e-6 ,
5234
+ ) -> Shape :
5235
+ """
5236
+ Build an edge on a face from points in (u,v) space.
5237
+ """
5238
+
5239
+ f = _get_one (base , "Face" )
5240
+
5241
+ # interpolate the u,v points
5242
+ spline_bldr = Geom2dAPI_Interpolate (_pts_to_harray2D (pts ), periodic , tol )
5243
+ spline_bldr .Perform ()
5244
+
5245
+ # build the final edge
5246
+ rv = BRepBuilderAPI_MakeEdge (spline_bldr .Curve (), f ._geomAdaptor ()).Edge ()
5247
+ BRepLib .BuildCurves3d_s (rv )
5248
+
5249
+ return _compound_or_shape (rv )
5250
+
5251
+
5252
+ @edgeOn .register
5253
+ def _ (
5254
+ fbase : Shape , edg : Shape , * edgs : Shape , tol : float = 1e-6 , N : int = 20 ,
5255
+ ):
5256
+ """
5257
+ Map one or more edges onto a base face in the u,v space.
5258
+ """
5259
+
5260
+ f = _get_one (fbase , "Face" )
5261
+
5262
+ rvs : List [TopoDS_Shape ] = []
5263
+
5264
+ for el in _get_edges (edg , * edgs ):
5265
+
5266
+ # sample the original curve
5267
+ pts3D , params = el .sample (N )
5268
+
5269
+ # convert to 2D points ignoring the z coord
5270
+ pts = [(el .x , el .y ) for el in pts3D ]
5271
+
5272
+ # handle periodicity
5273
+ t0 , t1 = el ._bounds ()
5274
+ el_crv = el ._geomAdaptor ()
5275
+
5276
+ periodic = False
5277
+
5278
+ # periodic (and closed)
5279
+ if el_crv .IsPeriodic () and el_crv .IsClosed ():
5280
+ periodic = True
5281
+ params .append (t0 + el_crv .Period ())
5282
+
5283
+ # only closed
5284
+ elif el_crv .IsClosed ():
5285
+ pts .append (pts [0 ])
5286
+ params .append (t1 )
5287
+
5288
+ # interpolate the u,v points
5289
+ spline_bldr = Geom2dAPI_Interpolate (
5290
+ _pts_to_harray2D (pts ), _floats_to_harray (params ), periodic , tol
5291
+ )
5292
+ spline_bldr .Perform ()
5293
+
5294
+ # build the final edge
5295
+ rv = BRepBuilderAPI_MakeEdge (spline_bldr .Curve (), f ._geomAdaptor ()).Edge ()
5296
+ BRepLib .BuildCurves3d_s (rv )
5297
+
5298
+ rvs .append (rv )
5299
+
5300
+ return _compound_or_shape (rvs )
5301
+
5302
+
5303
+ def wireOn (base : Shape , w : Shape , tol = 1e-6 , N = 20 ) -> Shape :
5304
+ """
5305
+ Map a wire onto a base face in the u,v space.
5306
+ """
5307
+
5308
+ rvs = [edgeOn (base , e , tol = tol , N = N ) for e in w .Edges ()]
5309
+
5310
+ return wire (rvs )
5311
+
5312
+
5132
5313
@multimethod
5133
5314
def wire (* s : Shape ) -> Shape :
5134
5315
"""
@@ -5177,6 +5358,36 @@ def face(s: Sequence[Shape]) -> Shape:
5177
5358
return face (* s )
5178
5359
5179
5360
5361
+ def faceOn (base : Shape , * fcs : Shape , tol = 1e-6 , N = 20 ) -> Shape :
5362
+ """
5363
+ Build face(s) on base by mapping planar face(s) onto the (u,v) space of base.
5364
+ """
5365
+
5366
+ rv : Shape
5367
+ rvs = []
5368
+
5369
+ # get a face
5370
+ fbase = _get_one (base , "Face" )
5371
+
5372
+ # iterate over all faces
5373
+ for el in fcs :
5374
+ for fc in el .Faces ():
5375
+ # construct pcurves and trim in one go
5376
+ rvs .append (
5377
+ fbase .trim (
5378
+ wireOn (fbase , fc .outerWire (), tol = tol , N = N ),
5379
+ * (wireOn (fbase , w , tol = tol , N = N ) for w in fc .innerWires ()),
5380
+ )
5381
+ )
5382
+
5383
+ if len (rvs ) == 1 :
5384
+ rv = rvs [0 ]
5385
+ else :
5386
+ rv = compound (rvs )
5387
+
5388
+ return rv
5389
+
5390
+
5180
5391
def _process_sewing_history (
5181
5392
builder : BRepBuilderAPI_Sewing , faces : List [Face ], history : Optional [ShapeHistory ],
5182
5393
):
0 commit comments