| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | __title__ = "BOPTools.JoinAPI module" |
| | __author__ = "DeepSOIC" |
| | __url__ = "https://www.freecad.org" |
| | __doc__ = "JoinFeatures functions that operate on shapes." |
| |
|
| | import Part |
| | from . import ShapeMerge |
| | from .GeneralFuseResult import GeneralFuseResult |
| | from .Utils import compoundLeaves |
| |
|
| |
|
| | def shapeOfMaxSize(list_of_shapes): |
| | """shapeOfMaxSize(list_of_shapes): finds the shape that has the largest " |
| | "mass in the list and returns it. The shapes in the list must be of same dimension.""" |
| | |
| | ShapeMerge.dimensionOfShapes(list_of_shapes) |
| |
|
| | rel_precision = 1e-8 |
| |
|
| | |
| | max_size = -1e100 |
| | count_max = 0 |
| | shape_max = None |
| | for sh in list_of_shapes: |
| | v = abs(Part.cast_to_shape(sh).Mass) |
| | if v > max_size * (1 + rel_precision): |
| | max_size = v |
| | shape_max = sh |
| | count_max = 1 |
| | elif (1 - rel_precision) * max_size <= v and v <= (1 + rel_precision) * max_size: |
| | count_max = count_max + 1 |
| | if count_max > 1: |
| | raise ValueError("There is more than one largest piece!") |
| | return shape_max |
| |
|
| |
|
| | def connect(list_of_shapes, tolerance=0.0): |
| | """connect(list_of_shapes, tolerance = 0.0): connects solids (walled objects), shells and |
| | wires by throwing off small parts that result when splitting them at intersections. |
| | |
| | Compounds in list_of_shapes are automatically exploded, so self-intersecting compounds |
| | are valid for connect.""" |
| |
|
| | |
| | new_list_of_shapes = [] |
| | for sh in list_of_shapes: |
| | new_list_of_shapes.extend(compoundLeaves(sh)) |
| | list_of_shapes = new_list_of_shapes |
| |
|
| | |
| | dim = ShapeMerge.dimensionOfShapes(list_of_shapes) |
| | if dim == 0: |
| | raise TypeError("Cannot connect vertices!") |
| |
|
| | if len(list_of_shapes) < 2: |
| | return Part.makeCompound(list_of_shapes) |
| |
|
| | pieces, map = list_of_shapes[0].generalFuse(list_of_shapes[1:], tolerance) |
| | ao = GeneralFuseResult(list_of_shapes, (pieces, map)) |
| | ao.splitAggregates() |
| | |
| |
|
| | keepers = [] |
| | all_danglers = [] |
| |
|
| | |
| | for src in ao.source_shapes: |
| | danglers = [ |
| | piece for piece in ao.piecesFromSource(src) if len(ao.sourcesOfPiece(piece)) == 1 |
| | ] |
| | all_danglers.extend(danglers) |
| | largest = shapeOfMaxSize(danglers) |
| | if largest is not None: |
| | keepers.append(largest) |
| |
|
| | touch_test_list = Part.makeCompound(keepers) |
| | |
| | for ii in range(2, ao.largestOverlapCount() + 1): |
| | list_ii_pieces = [piece for piece in ao.pieces if len(ao.sourcesOfPiece(piece)) == ii] |
| | keepers_2_add = [] |
| | for piece in list_ii_pieces: |
| | if ShapeMerge.isConnected(piece, touch_test_list): |
| | keepers_2_add.append(piece) |
| | if len(keepers_2_add) == 0: |
| | break |
| | keepers.extend(keepers_2_add) |
| | touch_test_list = Part.makeCompound(keepers_2_add) |
| |
|
| | |
| | |
| | return ShapeMerge.mergeShapes(keepers) |
| |
|
| |
|
| | def connect_legacy(shape1, shape2, tolerance=0.0): |
| | """connect_legacy(shape1, shape2, tolerance = 0.0): alternative implementation of |
| | connect, without use of generalFuse. Slow. Provided for backwards compatibility, and |
| | for older OCC.""" |
| |
|
| | if tolerance > 0.0: |
| | import FreeCAD as App |
| |
|
| | App.Console.PrintWarning("connect_legacy does not support tolerance (yet).\n") |
| | cut1 = shape1.cut(shape2) |
| | cut1 = shapeOfMaxSize(cut1.childShapes()) |
| | cut2 = shape2.cut(shape1) |
| | cut2 = shapeOfMaxSize(cut2.childShapes()) |
| | return cut1.multiFuse([cut2, shape2.common(shape1)]) |
| |
|
| |
|
| | |
| | |
| |
|
| |
|
| | def embed_legacy(shape_base, shape_tool, tolerance=0.0): |
| | """embed_legacy(shape_base, shape_tool, tolerance = 0.0): alternative implementation of |
| | embed, without use of generalFuse. Slow. Provided for backwards compatibility, and |
| | for older OCC.""" |
| | if tolerance > 0.0: |
| | import FreeCAD as App |
| |
|
| | App.Console.PrintWarning("embed_legacy does not support tolerance (yet).\n") |
| |
|
| | |
| | pieces = compoundLeaves(shape_base.cut(shape_tool)) |
| | piece = shapeOfMaxSize(pieces) |
| | result = piece.fuse(shape_tool) |
| | dim = ShapeMerge.dimensionOfShapes(pieces) |
| | if dim == 2: |
| | |
| | result = ShapeMerge.mergeShapes(result.Faces) |
| | elif dim == 1: |
| | result = ShapeMerge.mergeShapes(result.Edges) |
| | return result |
| |
|
| |
|
| | def cutout_legacy(shape_base, shape_tool, tolerance=0.0): |
| | """cutout_legacy(shape_base, shape_tool, tolerance = 0.0): alternative implementation of |
| | cutout, without use of generalFuse. Slow. Provided for backwards compatibility, and |
| | for older OCC.""" |
| |
|
| | if tolerance > 0.0: |
| | import FreeCAD as App |
| |
|
| | App.Console.PrintWarning("cutout_legacy does not support tolerance (yet).\n") |
| | |
| | shapes_base = compoundLeaves(shape_base) |
| | if len(shapes_base) > 1: |
| | result = [] |
| | for sh in shapes_base: |
| | result.append(cutout(sh, shape_tool)) |
| | return Part.makeCompound(result) |
| |
|
| | shape_base = shapes_base[0] |
| | pieces = compoundLeaves(shape_base.cut(shape_tool)) |
| | return shapeOfMaxSize(pieces) |
| |
|