@@ -1170,7 +1170,7 @@ def split_with_line(self, line, tolerance):
1170
1170
return None
1171
1171
1172
1172
# get BooleanPolygons of the polygon and the line segment
1173
- move_vec = line_2d .v .rotate (math .pi / 2 ).normalize () * (tolerance / 10 )
1173
+ move_vec = line_2d .v .rotate (math .pi / 2 ).normalize () * (tolerance / 2 )
1174
1174
line_verts = (line_2d .p1 , line_2d .p2 , line_2d .p2 .move (move_vec ),
1175
1175
line_2d .p1 .move (move_vec ))
1176
1176
line_poly = [(pb .BooleanPoint (pt .x , pt .y ) for pt in line_verts )]
@@ -1189,7 +1189,7 @@ def split_with_line(self, line, tolerance):
1189
1189
return None # typically a tolerance issue causing failure
1190
1190
1191
1191
# rebuild the Face3D from the results and return them
1192
- return Face3D ._from_bool_poly (poly1_result , prim_pl )
1192
+ return Face3D ._from_bool_poly (poly1_result , prim_pl , tolerance )
1193
1193
1194
1194
def split_with_polyline (self , polyline , tolerance ):
1195
1195
"""Split this face into two or more Face3D given an open Polyline3D.
@@ -1243,7 +1243,7 @@ def split_with_polyline(self, polyline, tolerance):
1243
1243
return None
1244
1244
1245
1245
# get BooleanPolygons of the polygon and the polyline
1246
- off_p_line = polyline_2d .offset (tolerance / 10 )
1246
+ off_p_line = polyline_2d .offset (tolerance / 2 )
1247
1247
P_line_verts = polyline_2d .vertices + tuple (reversed (off_p_line .vertices ))
1248
1248
line_poly = [(pb .BooleanPoint (pt .x , pt .y ) for pt in P_line_verts )]
1249
1249
face_polys = [(pb .BooleanPoint (pt .x , pt .y ) for pt in bnd_poly .vertices )]
@@ -1261,89 +1261,7 @@ def split_with_polyline(self, polyline, tolerance):
1261
1261
return None # typically a tolerance issue causing failure
1262
1262
1263
1263
# rebuild the Face3D from the results and return them
1264
- return Face3D ._from_bool_poly (poly1_result , prim_pl )
1265
-
1266
- def split_with_lines (self , lines , tolerance ):
1267
- """Split this face into two or more Face3D given multiple LineSegment3D.
1268
-
1269
- Using this method is distinct from looping over the Face3D.split_with_line
1270
- in that this method will resolve cases where multiple segments branch out
1271
- from nodes in a network of input lines. So, if three line segments
1272
- meet at a point in the middle of this Face3D and each extend past the
1273
- edges of this Face3D, this method can split the Face3D in 3 parts whereas
1274
- looping over the Face3D.split_with_line will not do this given that each
1275
- individual segment cannot split the Face3D.
1276
-
1277
- If the input lines together do not intersect this Face3D in a manner
1278
- that splits it into two or more pieces, None will be returned.
1279
-
1280
- Args:
1281
- lines: A list of LineSegment3D objects in the plane of this Face3D,
1282
- which will be used to split it into two or more pieces.
1283
- tolerance: The maximum difference between point values for them to be
1284
- considered distinct from one another.
1285
-
1286
- Returns:
1287
- A list of Face3D for the result of splitting this Face3D with the
1288
- input lines. Will be None if the line is not in the plane of the
1289
- Face3D or if it does not split the Face3D into two or more pieces.
1290
- """
1291
- # first check that the lines are in the plane of the Face3D
1292
- rel_line_3ds = []
1293
- for line in lines :
1294
- if self .plane .distance_to_point (line .p1 ) <= tolerance or \
1295
- self .plane .distance_to_point (line .p1 ) <= tolerance :
1296
- rel_line_3ds .append (line )
1297
- if len (rel_line_3ds ) == 0 :
1298
- return None
1299
- # extend the endpoints of the lines so that tolerance will split it
1300
- ext_rel_line_3ds = []
1301
- for line in rel_line_3ds :
1302
- tvc = line .v .normalize () * (tolerance / 2 )
1303
- line = LineSegment3D .from_end_points (line .p1 .move (- tvc ), line .p2 .move (tvc ))
1304
- ext_rel_line_3ds .append (line )
1305
-
1306
- # change the line and face to be in 2D and check that it can split the Face
1307
- prim_pl = self .plane
1308
- bnd_poly = self .boundary_polygon2d
1309
- rel_line_2ds = []
1310
- for line in ext_rel_line_3ds :
1311
- line_2d = LineSegment2D .from_end_points (
1312
- prim_pl .xyz_to_xy (line .p1 ), prim_pl .xyz_to_xy (line .p2 ))
1313
- if Polygon2D .overlapping_bounding_rect (bnd_poly , line_2d , tolerance ):
1314
- rel_line_2ds .append (line_2d )
1315
- if len (rel_line_2ds ) == 0 :
1316
- return None
1317
-
1318
- # get BooleanPolygon of the face
1319
- face_polys = [(pb .BooleanPoint (pt .x , pt .y ) for pt in bnd_poly .vertices )]
1320
- if self .has_holes :
1321
- for hole in self .hole_polygon2d :
1322
- face_polys .append ((pb .BooleanPoint (pt .x , pt .y ) for pt in hole .vertices ))
1323
- b_poly1 = pb .BooleanPolygon (face_polys )
1324
-
1325
- # loop through the segments and split the faces' boolean polygon
1326
- int_tol = tolerance / 100000
1327
- for line_2d in rel_line_2ds :
1328
- move_vec1 = line_2d .v .rotate (math .pi / 2 ) * (tolerance / 20 )
1329
- move_vec2 = move_vec1 .reverse ()
1330
- line_verts = (line_2d .p1 .move (move_vec1 ), line_2d .p2 .move (move_vec1 ),
1331
- line_2d .p2 .move (move_vec2 ), line_2d .p1 .move (move_vec2 ))
1332
- line_poly = [(pb .BooleanPoint (pt .x , pt .y ) for pt in line_verts )]
1333
- b_poly2 = pb .BooleanPolygon (line_poly )
1334
- try :
1335
- b_poly1 = pb .difference (b_poly1 , b_poly2 , int_tol )
1336
- except Exception :
1337
- return None # typically a tolerance issue causing failure
1338
-
1339
- # rebuild the Face3D from the results and clean up the result
1340
- split_result = Face3D ._from_bool_poly (b_poly1 , prim_pl )
1341
- if len (split_result ) == 1 : # nothing was split
1342
- return None # return None as the result is probably less clean than input
1343
- final_result = []
1344
- for face in split_result :
1345
- final_result .append (face .remove_duplicate_vertices (tolerance ))
1346
- return final_result
1264
+ return Face3D ._from_bool_poly (poly1_result , prim_pl , tolerance )
1347
1265
1348
1266
def intersect_line_ray (self , line_ray ):
1349
1267
"""Get the intersection between this face and the input LineSegment3D or Ray3D.
@@ -2484,7 +2402,7 @@ def coplanar_union_all(faces, tolerance, angle_tolerance):
2484
2402
return union_faces
2485
2403
2486
2404
@staticmethod
2487
- def _from_bool_poly (bool_polygon , plane ):
2405
+ def _from_bool_poly (bool_polygon , plane , snap_tolerance = None ):
2488
2406
"""Get a list of Face3D from a BooleanPolygon.
2489
2407
2490
2408
This method will automatically check whether any of the regions is meant
@@ -2493,6 +2411,9 @@ def _from_bool_poly(bool_polygon, plane):
2493
2411
Args:
2494
2412
bool_polygon: A BooleanPolygon to be interpreted to Face3D.
2495
2413
plane: The Plane in which the resulting Face3Ds exist.
2414
+ snap_tolerance: An optional tolerance value to be used to snap the
2415
+ polygons together before turning them into Face3D. If None,
2416
+ no snapping will occur.
2496
2417
"""
2497
2418
# serialize the BooleanPolygon into Polygon2D
2498
2419
polys = [Polygon2D (tuple (Point2D (pt .x , pt .y ) for pt in new_poly ))
@@ -2502,6 +2423,9 @@ def _from_bool_poly(bool_polygon, plane):
2502
2423
if len (polys ) == 1 :
2503
2424
verts_3d = tuple (plane .xy_to_xyz (pt ) for pt in polys [0 ].vertices )
2504
2425
return [Face3D (verts_3d , plane )]
2426
+ # snap the polygons together if requested
2427
+ if snap_tolerance is not None :
2428
+ polys = Polygon2D .snap_polygons (polys , snap_tolerance )
2505
2429
# sort the polygons by area and check if any are inside the others
2506
2430
polys .sort (key = lambda x : x .area , reverse = True )
2507
2431
poly_groups = [[polys [0 ]]]
0 commit comments