231
231
GeomAbs_C2 ,
232
232
GeomAbs_Intersection ,
233
233
GeomAbs_JoinType ,
234
+ GeomAbs_IsoType ,
235
+ GeomAbs_CurveType ,
234
236
)
235
237
from OCP .BRepOffsetAPI import BRepOffsetAPI_MakeFilling
236
238
from OCP .BRepOffset import BRepOffset_MakeOffset , BRepOffset_Mode
244
246
from OCP .ShapeAnalysis import ShapeAnalysis_FreeBounds , ShapeAnalysis_Wire
245
247
from OCP .TopTools import TopTools_HSequenceOfShape
246
248
247
- from OCP .GCPnts import GCPnts_AbscissaPoint
249
+ from OCP .GCPnts import (
250
+ GCPnts_AbscissaPoint ,
251
+ GCPnts_QuasiUniformAbscissa ,
252
+ GCPnts_QuasiUniformDeflection ,
253
+ )
248
254
249
255
from OCP .GeomFill import (
250
256
GeomFill_Frenet ,
281
287
282
288
from OCP .BinTools import BinTools
283
289
290
+ from OCP .Adaptor3d import Adaptor3d_IsoCurve , Adaptor3d_Curve
291
+
292
+ from OCP .GeomAdaptor import GeomAdaptor_Surface
293
+
284
294
from math import pi , sqrt , inf , radians , cos
285
295
286
296
import warnings
@@ -1900,7 +1910,8 @@ def _curve_and_param(
1900
1910
def positionAt (
1901
1911
self : Mixin1DProtocol , d : float , mode : ParamMode = "length" ,
1902
1912
) -> Vector :
1903
- """Generate a position along the underlying curve.
1913
+ """
1914
+ Generate a position along the underlying curve.
1904
1915
1905
1916
:param d: distance or parameter value
1906
1917
:param mode: position calculation mode (default: length)
@@ -1914,7 +1925,8 @@ def positionAt(
1914
1925
def positions (
1915
1926
self : Mixin1DProtocol , ds : Iterable [float ], mode : ParamMode = "length" ,
1916
1927
) -> List [Vector ]:
1917
- """Generate positions along the underlying curve
1928
+ """
1929
+ Generate positions along the underlying curve.
1918
1930
1919
1931
:param ds: distance or parameter values
1920
1932
:param mode: position calculation mode (default: length)
@@ -1923,14 +1935,44 @@ def positions(
1923
1935
1924
1936
return [self .positionAt (d , mode ) for d in ds ]
1925
1937
1938
+ def sample (
1939
+ self : Mixin1DProtocol , n : Union [int , float ]
1940
+ ) -> Tuple [List [Vector ], List [float ]]:
1941
+ """
1942
+ Sample a curve based on a number of points or deflection.
1943
+
1944
+ :param n: Number of positions or deflection
1945
+ :return: A list of Vectors and a list of parameters.
1946
+ """
1947
+
1948
+ gcpnts : Union [GCPnts_QuasiUniformAbscissa , GCPnts_QuasiUniformDeflection ]
1949
+
1950
+ if isinstance (n , int ):
1951
+ crv = self ._geomAdaptor ()
1952
+ gcpnts = GCPnts_QuasiUniformAbscissa (crv , n + 1 if crv .IsClosed () else n )
1953
+ else :
1954
+ crv = self ._geomAdaptor ()
1955
+ gcpnts = GCPnts_QuasiUniformDeflection (crv , n )
1956
+
1957
+ N_pts = gcpnts .NbPoints ()
1958
+
1959
+ params = [
1960
+ gcpnts .Parameter (i )
1961
+ for i in range (1 , N_pts if crv .IsClosed () else N_pts + 1 )
1962
+ ]
1963
+ pnts = [Vector (crv .Value (p )) for p in params ]
1964
+
1965
+ return pnts , params
1966
+
1926
1967
def locationAt (
1927
1968
self : Mixin1DProtocol ,
1928
1969
d : float ,
1929
1970
mode : ParamMode = "length" ,
1930
1971
frame : FrameMode = "frenet" ,
1931
1972
planar : bool = False ,
1932
1973
) -> Location :
1933
- """Generate a location along the underlying curve.
1974
+ """
1975
+ Generate a location along the underlying curve.
1934
1976
1935
1977
:param d: distance or parameter value
1936
1978
:param mode: position calculation mode (default: length)
@@ -1973,7 +2015,8 @@ def locations(
1973
2015
frame : FrameMode = "frenet" ,
1974
2016
planar : bool = False ,
1975
2017
) -> List [Location ]:
1976
- """Generate location along the curve
2018
+ """
2019
+ Generate locations along the curve.
1977
2020
1978
2021
:param ds: distance or parameter values
1979
2022
:param mode: position calculation mode (default: length)
@@ -3188,6 +3231,35 @@ def trim(self, u0: Real, u1: Real, v0: Real, v1: Real, tol: Real = 1e-6) -> "Fac
3188
3231
3189
3232
return self .__class__ (bldr .Shape ())
3190
3233
3234
+ def isoline (self , param : Real , direction : Literal ["u" , "v" ] = "v" ) -> Edge :
3235
+ """
3236
+ Construct an isoline.
3237
+ """
3238
+
3239
+ u1 , u2 , v1 , v2 = self ._uvBounds ()
3240
+
3241
+ if direction == "u" :
3242
+ iso = GeomAbs_IsoType .GeomAbs_IsoU
3243
+ p1 , p2 = v1 , v2
3244
+ else :
3245
+ iso = GeomAbs_IsoType .GeomAbs_IsoV
3246
+ p1 , p2 = u1 , u2
3247
+
3248
+ adaptor = Adaptor3d_IsoCurve (
3249
+ GeomAdaptor_Surface (self ._geomAdaptor ()), iso , param
3250
+ )
3251
+
3252
+ return Edge (_adaptor_curve_to_edge (adaptor , p1 , p2 ))
3253
+
3254
+ def isolines (
3255
+ self , params : Iterable [Real ], direction : Literal ["u" , "v" ] = "v"
3256
+ ) -> List [Edge ]:
3257
+ """
3258
+ Construct multiple isolines.
3259
+ """
3260
+
3261
+ return [self .isoline (p , direction ) for p in params ]
3262
+
3191
3263
3192
3264
class Shell (Shape ):
3193
3265
"""
@@ -4622,6 +4694,14 @@ def _shapes_to_toptools_list(s: Iterable[Shape]) -> TopTools_ListOfShape:
4622
4694
return rv
4623
4695
4624
4696
4697
+ def _toptools_list_to_shapes (tl : TopTools_ListOfShape ) -> List [Shape ]:
4698
+ """
4699
+ Convert a TopTools list (OCCT specific) to a compound.
4700
+ """
4701
+
4702
+ return [_normalize (Shape .cast (el )) for el in tl ]
4703
+
4704
+
4625
4705
_geomabsshape_dict = dict (
4626
4706
C0 = GeomAbs_Shape .GeomAbs_C0 ,
4627
4707
C1 = GeomAbs_Shape .GeomAbs_C1 ,
@@ -4656,6 +4736,34 @@ def _to_parametrization(name: str) -> Approx_ParametrizationType:
4656
4736
return _parametrization_dict [name .lower ()]
4657
4737
4658
4738
4739
+ def _adaptor_curve_to_edge (crv : Adaptor3d_Curve , p1 : float , p2 : float ) -> TopoDS_Edge :
4740
+
4741
+ GCT = GeomAbs_CurveType
4742
+
4743
+ t = crv .GetType ()
4744
+
4745
+ if t == GCT .GeomAbs_BSplineCurve :
4746
+ bldr = BRepBuilderAPI_MakeEdge (crv .BSpline (), p1 , p2 )
4747
+ elif t == GCT .GeomAbs_BezierCurve :
4748
+ bldr = BRepBuilderAPI_MakeEdge (crv .Bezier (), p1 , p2 )
4749
+ elif t == GCT .GeomAbs_Circle :
4750
+ bldr = BRepBuilderAPI_MakeEdge (crv .Circle (), p1 , p2 )
4751
+ elif t == GCT .GeomAbs_Line :
4752
+ bldr = BRepBuilderAPI_MakeEdge (crv .Line (), p1 , p2 )
4753
+ elif t == GCT .GeomAbs_Ellipse :
4754
+ bldr = BRepBuilderAPI_MakeEdge (crv .Ellipse (), p1 , p2 )
4755
+ elif t == GCT .GeomAbs_Hyperbola :
4756
+ bldr = BRepBuilderAPI_MakeEdge (crv .Hyperbola (), p1 , p2 )
4757
+ elif t == GCT .GeomAbs_Parabola :
4758
+ bldr = BRepBuilderAPI_MakeEdge (crv .Parabola (), p1 , p2 )
4759
+ elif t == GCT .GeomAbs_OffsetCurve :
4760
+ bldr = BRepBuilderAPI_MakeEdge (crv .OffsetCurve (), p1 , p2 )
4761
+ else :
4762
+ raise ValueError (r"{t} is not a supported curve type" )
4763
+
4764
+ return bldr .Edge ()
4765
+
4766
+
4659
4767
#%% alternative constructors
4660
4768
4661
4769
@@ -5675,7 +5783,7 @@ def loft(
5675
5783
#%% diagnotics
5676
5784
5677
5785
5678
- def check (s : Shape ) -> bool :
5786
+ def check (s : Shape , results : Optional [ List [ Tuple [ List [ Shape ], Any ]]] = None ) -> bool :
5679
5787
"""
5680
5788
Check if a shape is valid.
5681
5789
"""
@@ -5688,4 +5796,13 @@ def check(s: Shape) -> bool:
5688
5796
5689
5797
rv = analyzer .IsValid ()
5690
5798
5799
+ # output detailed results if requested
5800
+ if results is not None :
5801
+ results .clear ()
5802
+
5803
+ for r in analyzer .Result ():
5804
+ results .append (
5805
+ (_toptools_list_to_shapes (r .GetFaultyShapes1 ()), r .GetCheckStatus ())
5806
+ )
5807
+
5691
5808
return rv
0 commit comments