321321
322322from OCP .OSD import OSD_ThreadPool
323323
324+ from OCP .Bnd import Bnd_OBB
325+ from OCP .BRepBndLib import BRepBndLib
326+
324327from math import pi , sqrt , inf , radians , cos
325328
326329import warnings
@@ -1432,12 +1435,12 @@ def split(self, *splitters: "Shape") -> "Shape":
14321435
14331436 return self ._bool_op ((self ,), splitters , split_op )
14341437
1435- def distance (self , other : "Shape" ) -> float :
1438+ def distance (self , other : "Shape" , tol : float = 1e-6 ) -> float :
14361439 """
14371440 Minimal distance between two shapes
14381441 """
14391442
1440- dist_calc = BRepExtrema_DistShapeShape (self .wrapped , other .wrapped )
1443+ dist_calc = BRepExtrema_DistShapeShape (self .wrapped , other .wrapped , tol )
14411444 dist_calc .SetMultiThread (True )
14421445
14431446 return dist_calc .Value ()
@@ -2396,6 +2399,13 @@ def hasPCurve(self, f: "Face") -> bool:
23962399
23972400 return ShapeAnalysis_Edge ().HasPCurve (self .wrapped , f .wrapped )
23982401
2402+ def reversed (self ) -> "Edge" :
2403+ """
2404+ Return a reversed version of self.
2405+ """
2406+
2407+ return self .__class__ (self .wrapped .Reversed ())
2408+
23992409 @classmethod
24002410 def makeCircle (
24012411 cls ,
@@ -5466,6 +5476,10 @@ def shell(
54665476 return shell (* s , tol = tol , manifold = manifold , ctx = ctx , history = history )
54675477
54685478
5479+ # add an alias
5480+ sew = shell
5481+
5482+
54695483@multimethod
54705484def solid (
54715485 s1 : Shape , * sn : Shape , tol : float = 1e-6 , history : Optional [ShapeHistory ] = None ,
@@ -5842,7 +5856,7 @@ def text(
58425856 font_i , NCollection_Utf8String (txt ), theHAlign = theHAlign , theVAlign = theVAlign
58435857 )
58445858
5845- return clean (compound (_compound_or_shape (rv ).faces ()).fuse ())
5859+ return clean (compound (_compound_or_shape (rv ).Faces ()).fuse ())
58465860
58475861
58485862@text .register
@@ -5865,7 +5879,7 @@ def text(
58655879 L = spine .Length ()
58665880
58675881 rv = []
5868- for el in text (txt , size , font , path , kind , halign , valign ):
5882+ for el in text (txt , size , font , path , kind , halign , valign ). Faces () :
58695883 pos = el .BoundingBox ().center .x
58705884
58715885 # position
@@ -5899,7 +5913,7 @@ def text(
58995913 tmp = text (txt , size , spine , False , font , path , kind , halign , valign )
59005914
59015915 rv = []
5902- for f in tmp .faces ():
5916+ for f in tmp .Faces ():
59035917 rv .append (f .project (base , f .normalAt ()))
59045918
59055919 return _normalize (compound (rv ))
@@ -6170,7 +6184,7 @@ def chamfer(s: Shape, e: Shape, d: float) -> Shape:
61706184 return _compound_or_shape (builder .Shape ())
61716185
61726186
6173- def extrude (s : Shape , d : VectorLike ) -> Shape :
6187+ def extrude (s : Shape , d : VectorLike , both : bool = False ) -> Shape :
61746188 """
61756189 Extrude a shape.
61766190 """
@@ -6179,7 +6193,11 @@ def extrude(s: Shape, d: VectorLike) -> Shape:
61796193
61806194 for el in _get (s , ("Vertex" , "Edge" , "Wire" , "Face" )):
61816195
6182- builder = BRepPrimAPI_MakePrism (el .wrapped , Vector (d ).wrapped )
6196+ if both :
6197+ builder = BRepPrimAPI_MakePrism (el .moved (- d ).wrapped , 2 * Vector (d ).wrapped )
6198+ else :
6199+ builder = BRepPrimAPI_MakePrism (el .wrapped , Vector (d ).wrapped )
6200+
61836201 builder .Build ()
61846202
61856203 results .append (builder .Shape ())
@@ -6257,6 +6275,30 @@ def _offset(t):
62576275 return rv
62586276
62596277
6278+ def offset2D (
6279+ s : Shape , t : float , kind : Literal ["arc" , "intersection" , "tangent" ] = "arc"
6280+ ) -> Shape :
6281+ """
6282+ 2D Offset edges, wires or faces.
6283+ """
6284+
6285+ kind_dict = {
6286+ "arc" : GeomAbs_JoinType .GeomAbs_Arc ,
6287+ "intersection" : GeomAbs_JoinType .GeomAbs_Intersection ,
6288+ "tangent" : GeomAbs_JoinType .GeomAbs_Tangent ,
6289+ }
6290+
6291+ bldr = BRepOffsetAPI_MakeOffset ()
6292+ bldr .Init (kind_dict [kind ])
6293+
6294+ for el in _get_wires (s ):
6295+ bldr .AddWire (el .wrapped )
6296+
6297+ bldr .Perform (t )
6298+
6299+ return _compound_or_shape (bldr .Shape ())
6300+
6301+
62606302@multimethod
62616303def sweep (
62626304 s : Shape , path : Shape , aux : Optional [Shape ] = None , cap : bool = False
@@ -6500,6 +6542,7 @@ def loft(
65006542 return loft (s , cap , ruled , continuity , parametrization , degree , compat )
65016543
65026544
6545+ @multimethod
65036546def project (
65046547 s : Shape ,
65056548 base : Shape ,
@@ -6523,6 +6566,26 @@ def project(
65236566 return _compound_or_shape (bldr .Projection ())
65246567
65256568
6569+ @project .register
6570+ def project (
6571+ s : Shape , base : Shape , direction : VectorLike ,
6572+ ):
6573+ """
6574+ Project s onto base using cylindrical projection.
6575+ """
6576+
6577+ results = []
6578+
6579+ for el in _get_wires (s ):
6580+ bldr = BRepProj_Projection (el .wrapped , base .wrapped , Vector (direction ).toDir ())
6581+
6582+ while bldr .More ():
6583+ results .append (_compound_or_shape (bldr .Current ()))
6584+ bldr .Next ()
6585+
6586+ return _normalize (compound (results ))
6587+
6588+
65266589#%% diagnotics
65276590
65286591
@@ -6575,7 +6638,7 @@ def isSubshape(s1: Shape, s2: Shape) -> bool:
65756638#%% properties
65766639
65776640
6578- def closest (s1 : Shape , s2 : Shape ) -> Tuple [Vector , Vector ]:
6641+ def closest (s1 : Shape , s2 : Shape , tol : float = 1e-6 ) -> Tuple [Vector , Vector ]:
65796642 """
65806643 Closest points between two shapes.
65816644 """
@@ -6587,7 +6650,36 @@ def closest(s1: Shape, s2: Shape) -> Tuple[Vector, Vector]:
65876650 ext .LoadS1 (s1 .wrapped )
65886651 ext .LoadS2 (s2 .wrapped )
65896652
6653+ ext .SetDeflection (tol )
6654+ import OCP
6655+
6656+ ext .SetAlgo (OCP .Extrema .Extrema_ExtAlgo .Extrema_ExtAlgo_Grad )
6657+
65906658 # perform
6591- assert ext .Perform ()
6659+ ext .Perform ()
65926660
65936661 return Vector (ext .PointOnShape1 (1 )), Vector (ext .PointOnShape2 (1 ))
6662+
6663+
6664+ def obb (s : Shape ) -> Shape :
6665+
6666+ # construct the OBB
6667+ bbox = Bnd_OBB ()
6668+ BRepBndLib .AddOBB_s (
6669+ s .wrapped , bbox , theIsTriangulationUsed = False , theIsOptimal = True
6670+ )
6671+
6672+ # convert to a shape
6673+ center = Vector (bbox .Center ())
6674+ xdir = Vector (bbox .XDirection ())
6675+ ydir = Vector (bbox .YDirection ())
6676+ zdir = Vector (bbox .ZDirection ())
6677+
6678+ dx = bbox .XHSize ()
6679+ dy = bbox .YHSize ()
6680+ dz = bbox .ZHSize ()
6681+
6682+ ax = gp_Ax2 (center .toPnt (), zdir .toDir (), xdir .toDir ())
6683+ ax .SetLocation ((center - dx * xdir - dy * ydir - dz * zdir ).toPnt ())
6684+
6685+ return Shape .cast (BRepPrimAPI_MakeBox (ax , 2.0 * dx , 2.0 * dy , 2.0 * dz ).Shape ())
0 commit comments