@@ -236,8 +236,8 @@ def split(self, keepTop: bool = False, keepBottom: bool = False) -> "Workplane":
236
236
237
237
:param boolean keepTop: True to keep the top, False or None to discard it
238
238
:param boolean keepBottom: True to keep the bottom, False or None to discard it
239
- :raises: ValueError if keepTop and keepBottom are both false.
240
- :raises: ValueError if there is not a solid in the current stack or the parent chain
239
+ :raises ValueError: if keepTop and keepBottom are both false.
240
+ :raises ValueError: if there is no solid in the current stack or parent chain
241
241
:returns: CQ object with the desired objects on the stack.
242
242
243
243
The most common operation splits a solid and keeps one half. This sample creates
@@ -250,11 +250,11 @@ def split(self, keepTop: bool = False, keepBottom: bool = False) -> "Workplane":
250
250
c = c.faces(">Y").workplane(-0.5).split(keepTop=True)
251
251
"""
252
252
253
- solid = self .findSolid ()
254
-
255
253
if (not keepTop ) and (not keepBottom ):
256
254
raise ValueError ("You have to keep at least one half" )
257
255
256
+ solid = self .findSolid ()
257
+
258
258
maxDim = solid .BoundingBox ().DiagonalLength * 10.0
259
259
topCutBox = self .rect (maxDim , maxDim )._extrude (maxDim )
260
260
bottomCutBox = self .rect (maxDim , maxDim )._extrude (- maxDim )
@@ -291,18 +291,20 @@ def combineSolids(
291
291
combined and returned on the stack of the new object.
292
292
"""
293
293
# loop through current stack objects, and combine them
294
- toCombine = self .solids ().vals ()
294
+ toCombine = cast ( List [ Solid ], self .solids ().vals () )
295
295
296
296
if otherCQToCombine :
297
- for obj in otherCQToCombine .solids ().vals ():
297
+ otherSolids = cast (List [Solid ], otherCQToCombine .solids ().vals ())
298
+ for obj in otherSolids :
298
299
toCombine .append (obj )
299
300
300
301
if len (toCombine ) < 1 :
301
302
raise ValueError ("Cannot Combine: at least one solid required!" )
302
303
303
304
# get context solid and we don't want to find our own objects
304
- ctxSolid = self .findSolid (searchStack = False , searchParents = True )
305
-
305
+ ctxSolid = self ._findType (
306
+ (Solid , Compound ), searchStack = False , searchParents = True
307
+ )
306
308
if ctxSolid is None :
307
309
ctxSolid = toCombine .pop (0 )
308
310
@@ -676,10 +678,9 @@ def findSolid(
676
678
Finds the first solid object in the chain, searching from the current node
677
679
backwards through parents until one is found.
678
680
679
- :param searchStack: should objects on the stack be searched first.
681
+ :param searchStack: should objects on the stack be searched first?
680
682
:param searchParents: should parents be searched?
681
- :raises: ValueError if no solid is found in the current object or its parents,
682
- and errorOnEmpty is True
683
+ :raises ValueError: if no solid is found
683
684
684
685
This function is very important for chains that are modifying a single parent object,
685
686
most often a solid.
@@ -692,7 +693,15 @@ def findSolid(
692
693
results with an object already on the stack.
693
694
"""
694
695
695
- return self ._findType ((Solid , Compound ), searchStack , searchParents )
696
+ found = self ._findType ((Solid , Compound ), searchStack , searchParents )
697
+
698
+ if found is None :
699
+ message = "on the stack or " if searchStack else ""
700
+ raise ValueError (
701
+ "Cannot find a solid {}in the parent chain" .format (message )
702
+ )
703
+
704
+ return found
696
705
697
706
def findFace (self , searchStack : bool = True , searchParents : bool = True ) -> Face :
698
707
"""
@@ -701,11 +710,16 @@ def findFace(self, searchStack: bool = True, searchParents: bool = True) -> Face
701
710
702
711
:param searchStack: should objects on the stack be searched first.
703
712
:param searchParents: should parents be searched?
704
- :raises: ValueError if no face is found in the current object or its parents,
705
- and errorOnEmpty is True
713
+ :returns: A face or None if no face is found.
706
714
"""
707
715
708
- return self ._findType (Face , searchStack , searchParents )
716
+ found = self ._findType (Face , searchStack , searchParents )
717
+
718
+ if found is None :
719
+ message = "on the stack or " if searchStack else ""
720
+ raise ValueError ("Cannot find a face {}in the parent chain" .format (message ))
721
+
722
+ return found
709
723
710
724
def _selectObjects (
711
725
self ,
@@ -1104,7 +1118,7 @@ def shell(
1104
1118
:param thickness: a positive float, representing the thickness of the desired shell.
1105
1119
Negative values shell inwards, positive values shell outwards.
1106
1120
:param kind: kind of joints, intersetion or arc (default: arc).
1107
- :raises: ValueError if the current stack contains objects that are not faces of a solid
1121
+ :raises ValueError: if the current stack contains objects that are not faces of a solid
1108
1122
further up in the chain.
1109
1123
:returns: a CQ object with the resulting shelled solid selected.
1110
1124
@@ -1148,15 +1162,14 @@ def fillet(self, radius: float) -> "Workplane":
1148
1162
1149
1163
:param radius: the radius of the fillet, must be > zero
1150
1164
:type radius: positive float
1151
- :raises: ValueError if at least one edge is not selected
1152
- :raises: ValueError if the solid containing the edge is not in the chain
1165
+ :raises ValueError: if at least one edge is not selected
1166
+ :raises ValueError: if the solid containing the edge is not in the chain
1153
1167
:returns: cq object with the resulting solid selected.
1154
1168
1155
1169
This example will create a unit cube, with the top edges filleted::
1156
1170
1157
1171
s = Workplane().box(1,1,1).faces("+Z").edges().fillet(0.1)
1158
1172
"""
1159
- # TODO: we will need much better edge selectors for this to work
1160
1173
# TODO: ensure that edges selected actually belong to the solid in the chain, otherwise,
1161
1174
# TODO: we segfault
1162
1175
@@ -1185,8 +1198,8 @@ def chamfer(self, length: float, length2: Optional[float] = None) -> "Workplane"
1185
1198
:param length2: optional parameter for asymmetrical chamfer
1186
1199
:type length: positive float
1187
1200
:type length2: positive float
1188
- :raises: ValueError if at least one edge is not selected
1189
- :raises: ValueError if the solid containing the edge is not in the chain
1201
+ :raises ValueError: if at least one edge is not selected
1202
+ :raises ValueError: if the solid containing the edge is not in the chain
1190
1203
:returns: cq object with the resulting solid selected.
1191
1204
1192
1205
This example will create a unit cube, with the top edges chamfered::
@@ -2501,17 +2514,16 @@ def close(self) -> "Workplane":
2501
2514
def largestDimension (self ) -> float :
2502
2515
"""
2503
2516
Finds the largest dimension in the stack.
2517
+
2504
2518
Used internally to create thru features, this is how you can compute
2505
2519
how long or wide a feature must be to make sure to cut through all of the material
2520
+
2521
+ :raises ValueError: if no solids or compounds are found
2506
2522
:return: A value representing the largest dimension of the first solid on the stack
2507
2523
"""
2508
2524
# Get all the solids contained within this CQ object
2509
2525
compound = self .findSolid ()
2510
2526
2511
- # Protect against this being called on something like a blank workplane
2512
- if not compound :
2513
- return - 1
2514
-
2515
2527
return compound .BoundingBox ().DiagonalLength
2516
2528
2517
2529
def cutEach (
@@ -2526,12 +2538,10 @@ def cutEach(
2526
2538
:param fcn: a function suitable for use in the eachpoint method: ie, that accepts a vector
2527
2539
:param useLocalCoords: same as for :py:meth:`eachpoint`
2528
2540
:param boolean clean: call :py:meth:`clean` afterwards to have a clean shape
2541
+ :raises ValueError: if no solids or compounds are found in the stack or parent chain
2529
2542
:return: a CQ object that contains the resulting solid
2530
- :raises: an error if there is not a context solid to cut from
2531
2543
"""
2532
2544
ctxSolid = self .findSolid ()
2533
- if ctxSolid is None :
2534
- raise ValueError ("Must have a solid in the chain to cut from!" )
2535
2545
2536
2546
# will contain all of the counterbores as a single compound
2537
2547
results = cast (List [Shape ], self .eachpoint (fcn , useLocalCoords ).vals ())
@@ -2920,7 +2930,9 @@ def _combineWithBase(self, obj: Shape) -> "Workplane":
2920
2930
:return: a new object that represents the result of combining the base object with obj,
2921
2931
or obj if one could not be found
2922
2932
"""
2923
- baseSolid = self .findSolid (searchParents = True )
2933
+ baseSolid = self ._findType (
2934
+ (Solid , Compound ), searchStack = True , searchParents = True
2935
+ )
2924
2936
r = obj
2925
2937
if baseSolid is not None :
2926
2938
r = baseSolid .fuse (obj )
@@ -2936,7 +2948,9 @@ def _cutFromBase(self, obj: Shape) -> "Workplane":
2936
2948
:return: a new object that represents the result of combining the base object with obj,
2937
2949
or obj if one could not be found
2938
2950
"""
2939
- baseSolid = self .findSolid (searchParents = True )
2951
+ baseSolid = self ._findType (
2952
+ (Solid , Compound ), searchStack = True , searchParents = True
2953
+ )
2940
2954
r = obj
2941
2955
if baseSolid is not None :
2942
2956
r = baseSolid .cut (obj )
@@ -2989,21 +3003,23 @@ def union(
2989
3003
"""
2990
3004
2991
3005
# first collect all of the items together
2992
- newS : Sequence [Shape ]
3006
+ newS : List [Shape ]
2993
3007
if isinstance (toUnion , CQ ):
2994
3008
newS = cast (List [Shape ], toUnion .solids ().vals ())
2995
3009
if len (newS ) < 1 :
2996
3010
raise ValueError (
2997
3011
"CQ object must have at least one solid on the stack to union!"
2998
3012
)
2999
3013
elif isinstance (toUnion , (Solid , Compound )):
3000
- newS = ( toUnion ,)
3014
+ newS = [ toUnion ]
3001
3015
else :
3002
3016
raise ValueError ("Cannot union type '{}'" .format (type (toUnion )))
3003
3017
3004
3018
# now combine with existing solid, if there is one
3005
3019
# look for parents to cut from
3006
- solidRef = self .findSolid (searchStack = True , searchParents = True )
3020
+ solidRef = self ._findType (
3021
+ (Solid , Compound ), searchStack = True , searchParents = True
3022
+ )
3007
3023
if solidRef is not None :
3008
3024
r = solidRef .fuse (* newS , glue = glue , tol = tol )
3009
3025
elif len (newS ) > 1 :
@@ -3044,16 +3060,13 @@ def cut(
3044
3060
:param toCut: object to cut
3045
3061
:type toCut: a solid object, or a CQ object having a solid,
3046
3062
:param boolean clean: call :py:meth:`clean` afterwards to have a clean shape
3047
- :raises: ValueError if there is no solid to subtract from in the chain
3063
+ :raises ValueError: if there is no solid to subtract from in the chain
3048
3064
:return: a CQ object with the resulting object selected
3049
3065
"""
3050
3066
3051
3067
# look for parents to cut from
3052
3068
solidRef = self .findSolid (searchStack = True , searchParents = True )
3053
3069
3054
- if solidRef is None :
3055
- raise ValueError ("Cannot find solid to cut from" )
3056
-
3057
3070
solidToCut : Sequence [Shape ]
3058
3071
3059
3072
if isinstance (toCut , CQ ):
@@ -3092,16 +3105,13 @@ def intersect(
3092
3105
:param toIntersect: object to intersect
3093
3106
:type toIntersect: a solid object, or a CQ object having a solid,
3094
3107
:param boolean clean: call :py:meth:`clean` afterwards to have a clean shape
3095
- :raises: ValueError if there is no solid to intersect with in the chain
3108
+ :raises ValueError: if there is no solid to intersect with in the chain
3096
3109
:return: a CQ object with the resulting object selected
3097
3110
"""
3098
3111
3099
3112
# look for parents to intersect with
3100
3113
solidRef = self .findSolid (searchStack = True , searchParents = True )
3101
3114
3102
- if solidRef is None :
3103
- raise ValueError ("Cannot find solid to intersect with" )
3104
-
3105
3115
solidToIntersect : Sequence [Shape ]
3106
3116
3107
3117
if isinstance (toIntersect , CQ ):
@@ -3145,7 +3155,7 @@ def cutBlind(
3145
3155
<0 means in the negative direction
3146
3156
:param boolean clean: call :py:meth:`clean` afterwards to have a clean shape
3147
3157
:param float taper: angle for optional tapered extrusion
3148
- :raises: ValueError if there is no solid to subtract from in the chain
3158
+ :raises ValueError: if there is no solid to subtract from in the chain
3149
3159
:return: a CQ object with the resulting object selected
3150
3160
3151
3161
see :py:meth:`cutThruAll` to cut material from the entire part
@@ -3157,7 +3167,6 @@ def cutBlind(
3157
3167
toCut = self ._extrude (distanceToCut , taper = taper )
3158
3168
3159
3169
# now find a solid in the chain
3160
-
3161
3170
solidRef = self .findSolid ()
3162
3171
3163
3172
s = solidRef .cut (toCut )
@@ -3176,7 +3185,7 @@ def cutThruAll(self, clean: bool = True, taper: float = 0) -> "Workplane":
3176
3185
from. cutThruAll always removes material from a part.
3177
3186
3178
3187
:param boolean clean: call :py:meth:`clean` afterwards to have a clean shape
3179
- :raises: ValueError if there is no solid to subtract from in the chain
3188
+ :raises ValueError: if there is no solid to subtract from in the chain
3180
3189
:return: a CQ object with the resulting object selected
3181
3190
3182
3191
see :py:meth:`cutBlind` to cut material to a limited depth
@@ -3185,6 +3194,7 @@ def cutThruAll(self, clean: bool = True, taper: float = 0) -> "Workplane":
3185
3194
self .ctx .pendingWires = []
3186
3195
3187
3196
solidRef = self .findSolid ()
3197
+
3188
3198
rv = []
3189
3199
for solid in solidRef .Solids ():
3190
3200
s = solid .dprism (None , wires , thruAll = True , additive = False , taper = - taper )
@@ -3209,7 +3219,9 @@ def loft(
3209
3219
r : Shape = Solid .makeLoft (wiresToLoft , ruled )
3210
3220
3211
3221
if combine :
3212
- parentSolid = self .findSolid (searchStack = False , searchParents = True )
3222
+ parentSolid = self ._findType (
3223
+ (Solid , Compound ), searchStack = False , searchParents = True
3224
+ )
3213
3225
if parentSolid is not None :
3214
3226
r = parentSolid .fuse (r )
3215
3227
@@ -3751,14 +3763,12 @@ def section(self, height: float = 0.0) -> "Workplane":
3751
3763
Slices current solid at the given height.
3752
3764
3753
3765
:param float height: height to slice at (default: 0)
3766
+ :raises ValueError: if no solids or compounds are found
3754
3767
:return: a CQ object with the resulting face(s).
3755
3768
"""
3756
3769
3757
3770
solidRef = self .findSolid (searchStack = True , searchParents = True )
3758
3771
3759
- if solidRef is None :
3760
- raise ValueError ("Cannot find solid to slice" )
3761
-
3762
3772
plane = Face .makePlane (
3763
3773
basePnt = self .plane .origin + self .plane .zDir * height , dir = self .plane .zDir
3764
3774
)
0 commit comments