ScadPy 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- scadpy/__init__.py +5 -0
- scadpy/color/__init__.py +3 -0
- scadpy/color/constants/BEIGE.py +3 -0
- scadpy/color/constants/BLACK.py +3 -0
- scadpy/color/constants/BLUE.py +3 -0
- scadpy/color/constants/BROWN.py +3 -0
- scadpy/color/constants/DARK_GRAY.py +3 -0
- scadpy/color/constants/DEFAULT_COLOR.py +3 -0
- scadpy/color/constants/DEFAULT_OPACITY.py +1 -0
- scadpy/color/constants/GRAY.py +3 -0
- scadpy/color/constants/GREEN.py +3 -0
- scadpy/color/constants/ORANGE.py +3 -0
- scadpy/color/constants/RED.py +3 -0
- scadpy/color/constants/WHITE.py +3 -0
- scadpy/color/constants/YELLOW.py +3 -0
- scadpy/color/constants/__init__.py +29 -0
- scadpy/color/type/__init__.py +3 -0
- scadpy/color/type/color.py +3 -0
- scadpy/color/utils/__init__.py +3 -0
- scadpy/color/utils/get_random_color.py +36 -0
- scadpy/core/__init__.py +3 -0
- scadpy/core/assembly/__init__.py +5 -0
- scadpy/core/assembly/combinations/__init__.py +13 -0
- scadpy/core/assembly/combinations/concat_assemblies.py +50 -0
- scadpy/core/assembly/combinations/exclude_assemblies.py +135 -0
- scadpy/core/assembly/combinations/intersect_assemblies.py +128 -0
- scadpy/core/assembly/combinations/subtract_assemblies.py +151 -0
- scadpy/core/assembly/combinations/unify_assemblies.py +59 -0
- scadpy/core/assembly/topologies/__init__.py +41 -0
- scadpy/core/assembly/topologies/directed_edge/__init__.py +9 -0
- scadpy/core/assembly/topologies/directed_edge/get_assembly_directed_edge_directions.py +70 -0
- scadpy/core/assembly/topologies/directed_edge/get_assembly_directed_edge_to_edge.py +49 -0
- scadpy/core/assembly/topologies/directed_edge/get_assembly_directed_edge_to_vertex.py +54 -0
- scadpy/core/assembly/topologies/edge/__init__.py +9 -0
- scadpy/core/assembly/topologies/edge/get_assembly_edge_lengths.py +46 -0
- scadpy/core/assembly/topologies/edge/get_assembly_edge_midpoints.py +51 -0
- scadpy/core/assembly/topologies/edge/get_assembly_edge_normals.py +67 -0
- scadpy/core/assembly/topologies/face_corner/__init__.py +13 -0
- scadpy/core/assembly/topologies/face_corner/get_assembly_face_corner_angles.py +72 -0
- scadpy/core/assembly/topologies/face_corner/get_assembly_face_corner_normals.py +103 -0
- scadpy/core/assembly/topologies/face_corner/get_assembly_face_corner_to_incoming_directed_edge.py +65 -0
- scadpy/core/assembly/topologies/face_corner/get_assembly_face_corner_to_outgoing_directed_edge.py +65 -0
- scadpy/core/assembly/topologies/face_corner/get_assembly_face_directed_edge_to_corner.py +79 -0
- scadpy/core/assembly/topologies/part/__init__.py +5 -0
- scadpy/core/assembly/topologies/part/get_assembly_part_colors.py +55 -0
- scadpy/core/assembly/topologies/vertex/__init__.py +7 -0
- scadpy/core/assembly/topologies/vertex/get_assembly_vertex_coordinates.py +70 -0
- scadpy/core/assembly/topologies/vertex/get_assembly_vertex_to_part.py +62 -0
- scadpy/core/assembly/transformations/__init__.py +19 -0
- scadpy/core/assembly/transformations/color_assembly.py +24 -0
- scadpy/core/assembly/transformations/mirror_vertex_coordinates.py +68 -0
- scadpy/core/assembly/transformations/pull_vertex_coordinates.py +64 -0
- scadpy/core/assembly/transformations/push_vertex_coordinates.py +64 -0
- scadpy/core/assembly/transformations/resize_vertex_coordinates.py +121 -0
- scadpy/core/assembly/transformations/rotate_vertex_coordinates.py +73 -0
- scadpy/core/assembly/transformations/scale_vertex_coordinates.py +76 -0
- scadpy/core/assembly/transformations/translate_vertex_coordinates.py +70 -0
- scadpy/core/assembly/types/__init__.py +7 -0
- scadpy/core/assembly/types/assembly.py +14 -0
- scadpy/core/assembly/types/topology_filter.py +6 -0
- scadpy/core/assembly/utils/__init__.py +9 -0
- scadpy/core/assembly/utils/lookup_pairs.py +56 -0
- scadpy/core/assembly/utils/resolve_topology_filter.py +84 -0
- scadpy/core/assembly/utils/transform_filtered_parts.py +55 -0
- scadpy/core/component/__init__.py +3 -0
- scadpy/core/component/exporters/__init__.py +7 -0
- scadpy/core/component/exporters/map_component_to_html_file.py +47 -0
- scadpy/core/component/exporters/map_component_to_screen.py +63 -0
- scadpy/core/component/features/__init__.py +5 -0
- scadpy/core/component/features/get_component_bounds.py +38 -0
- scadpy/core/component/utils/__init__.py +9 -0
- scadpy/core/component/utils/blend_component_colors.py +77 -0
- scadpy/core/component/utils/get_intersecting_component_index_groups.py +108 -0
- scadpy/core/part/__init__.py +3 -0
- scadpy/core/part/combinations/__init__.py +11 -0
- scadpy/core/part/combinations/concat_parts.py +48 -0
- scadpy/core/part/combinations/intersect_parts.py +147 -0
- scadpy/core/part/combinations/subtract_parts.py +94 -0
- scadpy/core/part/combinations/unify_parts.py +143 -0
- scadpy/core/part/types/__init__.py +5 -0
- scadpy/core/part/types/part.py +34 -0
- scadpy/core/part/utils/__init__.py +5 -0
- scadpy/core/part/utils/blend_part_colors.py +32 -0
- scadpy/d2/__init__.py +2 -0
- scadpy/d2/shape/__init__.py +9 -0
- scadpy/d2/shape/combinations/__init__.py +21 -0
- scadpy/d2/shape/combinations/are_shape_parts_intersecting.py +49 -0
- scadpy/d2/shape/combinations/concat_shape.py +48 -0
- scadpy/d2/shape/combinations/exclude_shape.py +71 -0
- scadpy/d2/shape/combinations/intersect_shape.py +64 -0
- scadpy/d2/shape/combinations/intersect_shape_parts.py +71 -0
- scadpy/d2/shape/combinations/subtract_shape.py +72 -0
- scadpy/d2/shape/combinations/subtract_shape_parts.py +66 -0
- scadpy/d2/shape/combinations/unify_shape.py +51 -0
- scadpy/d2/shape/combinations/unify_shape_parts.py +74 -0
- scadpy/d2/shape/exporters/__init__.py +17 -0
- scadpy/d2/shape/exporters/map_shape_to_dxf.py +43 -0
- scadpy/d2/shape/exporters/map_shape_to_dxf_file.py +38 -0
- scadpy/d2/shape/exporters/map_shape_to_html.py +117 -0
- scadpy/d2/shape/exporters/map_shape_to_html_file.py +58 -0
- scadpy/d2/shape/exporters/map_shape_to_screen.py +51 -0
- scadpy/d2/shape/exporters/map_shape_to_svg.py +40 -0
- scadpy/d2/shape/exporters/map_shape_to_svg_file.py +38 -0
- scadpy/d2/shape/features/__init__.py +9 -0
- scadpy/d2/shape/features/get_shape_bounds.py +40 -0
- scadpy/d2/shape/features/get_shape_part_bounds.py +37 -0
- scadpy/d2/shape/features/is_shape_empty.py +38 -0
- scadpy/d2/shape/importers/__init__.py +13 -0
- scadpy/d2/shape/importers/map_dxf_to_shape.py +55 -0
- scadpy/d2/shape/importers/map_geometries_to_shape.py +45 -0
- scadpy/d2/shape/importers/map_geometry_to_shape.py +43 -0
- scadpy/d2/shape/importers/map_parts_to_shape.py +62 -0
- scadpy/d2/shape/importers/map_svg_to_shape.py +55 -0
- scadpy/d2/shape/primitives/__init__.py +6 -0
- scadpy/d2/shape/primitives/circle.py +68 -0
- scadpy/d2/shape/primitives/polygon.py +86 -0
- scadpy/d2/shape/primitives/rectangle.py +85 -0
- scadpy/d2/shape/primitives/square.py +57 -0
- scadpy/d2/shape/topologies/__init__.py +53 -0
- scadpy/d2/shape/topologies/corner/__init__.py +15 -0
- scadpy/d2/shape/topologies/corner/are_shape_corners_convex.py +75 -0
- scadpy/d2/shape/topologies/corner/get_shape_corner_angles.py +58 -0
- scadpy/d2/shape/topologies/corner/get_shape_corner_normals.py +82 -0
- scadpy/d2/shape/topologies/corner/get_shape_corner_to_incoming_directed_edge.py +39 -0
- scadpy/d2/shape/topologies/corner/get_shape_corner_to_outgoing_directed_edge.py +39 -0
- scadpy/d2/shape/topologies/corner/get_shape_corner_to_vertex.py +65 -0
- scadpy/d2/shape/topologies/directed_edge/__init__.py +11 -0
- scadpy/d2/shape/topologies/directed_edge/get_shape_directed_edge_directions.py +44 -0
- scadpy/d2/shape/topologies/directed_edge/get_shape_directed_edge_to_corner.py +41 -0
- scadpy/d2/shape/topologies/directed_edge/get_shape_directed_edge_to_edge.py +51 -0
- scadpy/d2/shape/topologies/directed_edge/get_shape_directed_edge_to_vertex.py +63 -0
- scadpy/d2/shape/topologies/edge/__init__.py +11 -0
- scadpy/d2/shape/topologies/edge/get_shape_edge_lengths.py +43 -0
- scadpy/d2/shape/topologies/edge/get_shape_edge_midpoints.py +46 -0
- scadpy/d2/shape/topologies/edge/get_shape_edge_normals.py +40 -0
- scadpy/d2/shape/topologies/edge/get_shape_edge_to_vertex.py +71 -0
- scadpy/d2/shape/topologies/ring/__init__.py +7 -0
- scadpy/d2/shape/topologies/ring/get_shape_ring_to_part.py +46 -0
- scadpy/d2/shape/topologies/ring/get_shape_ring_types.py +46 -0
- scadpy/d2/shape/topologies/vertex/__init__.py +11 -0
- scadpy/d2/shape/topologies/vertex/get_shape_part_vertex_coordinates.py +62 -0
- scadpy/d2/shape/topologies/vertex/get_shape_vertex_coordinates.py +44 -0
- scadpy/d2/shape/topologies/vertex/get_shape_vertex_to_part.py +42 -0
- scadpy/d2/shape/topologies/vertex/get_shape_vertex_to_ring.py +63 -0
- scadpy/d2/shape/transformations/__init__.py +43 -0
- scadpy/d2/shape/transformations/chamfer_shape.py +259 -0
- scadpy/d2/shape/transformations/color_shape.py +46 -0
- scadpy/d2/shape/transformations/convexify_shape.py +79 -0
- scadpy/d2/shape/transformations/fill_shape.py +68 -0
- scadpy/d2/shape/transformations/fillet_shape.py +289 -0
- scadpy/d2/shape/transformations/grow_shape.py +82 -0
- scadpy/d2/shape/transformations/linear_cut_shape.py +116 -0
- scadpy/d2/shape/transformations/linear_extrude_shape.py +60 -0
- scadpy/d2/shape/transformations/linear_slice_shape.py +144 -0
- scadpy/d2/shape/transformations/mirror_shape.py +53 -0
- scadpy/d2/shape/transformations/pull_shape.py +67 -0
- scadpy/d2/shape/transformations/push_shape.py +67 -0
- scadpy/d2/shape/transformations/radial_extrude_shape.py +285 -0
- scadpy/d2/shape/transformations/radial_slice_shape.py +132 -0
- scadpy/d2/shape/transformations/recoordinate_shape.py +82 -0
- scadpy/d2/shape/transformations/resize_shape.py +91 -0
- scadpy/d2/shape/transformations/rotate_shape.py +63 -0
- scadpy/d2/shape/transformations/scale_shape.py +58 -0
- scadpy/d2/shape/transformations/shrink_shape.py +69 -0
- scadpy/d2/shape/transformations/translate_shape.py +54 -0
- scadpy/d2/shape/types/__init__.py +3 -0
- scadpy/d2/shape/types/shape.py +792 -0
- scadpy/d2/shape/types/utils/__init__.py +5 -0
- scadpy/d2/shape/types/utils/shapely_base_geometry_to_shapely_polygons.py +25 -0
- scadpy/d2/shape/utils/__init__.py +5 -0
- scadpy/d2/shape/utils/shapely_base_geometry_to_shapely_polygons.py +55 -0
- scadpy/d2/utils/__init__.py +3 -0
- scadpy/d2/utils/resolve_vector_2d.py +50 -0
- scadpy/d3/__init__.py +2 -0
- scadpy/d3/solid/__init__.py +8 -0
- scadpy/d3/solid/combinations/__init__.py +21 -0
- scadpy/d3/solid/combinations/are_solid_parts_intersecting.py +51 -0
- scadpy/d3/solid/combinations/concat_solid.py +48 -0
- scadpy/d3/solid/combinations/exclude_solid.py +71 -0
- scadpy/d3/solid/combinations/intersect_solid.py +64 -0
- scadpy/d3/solid/combinations/intersect_solid_parts.py +73 -0
- scadpy/d3/solid/combinations/subtract_solid.py +72 -0
- scadpy/d3/solid/combinations/subtract_solid_parts.py +68 -0
- scadpy/d3/solid/combinations/unify_solid.py +51 -0
- scadpy/d3/solid/combinations/unify_solid_parts.py +73 -0
- scadpy/d3/solid/exporters/__init__.py +11 -0
- scadpy/d3/solid/exporters/map_solid_to_html.py +318 -0
- scadpy/d3/solid/exporters/map_solid_to_html_file.py +58 -0
- scadpy/d3/solid/exporters/map_solid_to_screen.py +51 -0
- scadpy/d3/solid/exporters/map_solid_to_stl_file.py +48 -0
- scadpy/d3/solid/features/__init__.py +11 -0
- scadpy/d3/solid/features/get_solid_bounds.py +37 -0
- scadpy/d3/solid/features/get_solid_part_bounds.py +37 -0
- scadpy/d3/solid/features/get_solid_part_colors.py +39 -0
- scadpy/d3/solid/features/is_solid_empty.py +36 -0
- scadpy/d3/solid/importers/__init__.py +11 -0
- scadpy/d3/solid/importers/map_geometries_to_solid.py +42 -0
- scadpy/d3/solid/importers/map_geometry_to_solid.py +42 -0
- scadpy/d3/solid/importers/map_parts_to_solid.py +66 -0
- scadpy/d3/solid/importers/map_stl_to_solid.py +37 -0
- scadpy/d3/solid/primitives/__init__.py +7 -0
- scadpy/d3/solid/primitives/cone.py +70 -0
- scadpy/d3/solid/primitives/cuboid.py +75 -0
- scadpy/d3/solid/primitives/cylinder.py +73 -0
- scadpy/d3/solid/primitives/polyhedron.py +60 -0
- scadpy/d3/solid/primitives/sphere.py +58 -0
- scadpy/d3/solid/topologies/__init__.py +8 -0
- scadpy/d3/solid/topologies/triangle/__init__.py +5 -0
- scadpy/d3/solid/topologies/triangle/get_solid_triangle_to_vertex.py +49 -0
- scadpy/d3/solid/topologies/vertex/__init__.py +7 -0
- scadpy/d3/solid/topologies/vertex/get_solid_vertex_coordinates.py +39 -0
- scadpy/d3/solid/topologies/vertex/get_solid_vertex_to_part.py +37 -0
- scadpy/d3/solid/transformations/__init__.py +23 -0
- scadpy/d3/solid/transformations/color_solid.py +46 -0
- scadpy/d3/solid/transformations/convexify_solid.py +64 -0
- scadpy/d3/solid/transformations/mirror_solid.py +53 -0
- scadpy/d3/solid/transformations/pull_solid.py +67 -0
- scadpy/d3/solid/transformations/push_solid.py +67 -0
- scadpy/d3/solid/transformations/recoordinate_solid.py +68 -0
- scadpy/d3/solid/transformations/resize_solid.py +92 -0
- scadpy/d3/solid/transformations/rotate_solid.py +93 -0
- scadpy/d3/solid/transformations/scale_solid.py +58 -0
- scadpy/d3/solid/transformations/translate_solid.py +54 -0
- scadpy/d3/solid/types/__init__.py +3 -0
- scadpy/d3/solid/types/solid.py +448 -0
- scadpy/d3/utils/__init__.py +3 -0
- scadpy/d3/utils/resolve_vector_3d.py +50 -0
- scadpy/utils/__init__.py +6 -0
- scadpy/utils/resolve_vector.py +64 -0
- scadpy/utils/x.py +38 -0
- scadpy/utils/y.py +38 -0
- scadpy/utils/z.py +38 -0
- scadpy-0.1.0.dist-info/METADATA +282 -0
- scadpy-0.1.0.dist-info/RECORD +236 -0
- scadpy-0.1.0.dist-info/WHEEL +4 -0
- scadpy-0.1.0.dist-info/licenses/LICENSE.md +43 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from shapely.geometry import MultiPolygon, Polygon
|
|
2
|
+
from shapely.geometry.base import BaseGeometry
|
|
3
|
+
from shapely.geometry.polygon import orient
|
|
4
|
+
from typeguard import typechecked
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@typechecked
|
|
8
|
+
def shapely_base_geometry_to_shapely_polygons(
|
|
9
|
+
base_geometry: BaseGeometry,
|
|
10
|
+
) -> list[Polygon]:
|
|
11
|
+
if base_geometry.is_empty:
|
|
12
|
+
return []
|
|
13
|
+
|
|
14
|
+
if isinstance(base_geometry, Polygon):
|
|
15
|
+
# normalize orientation: exterior CCW, interiors CW (shapely convention)
|
|
16
|
+
return [orient(base_geometry, sign=1.0)]
|
|
17
|
+
|
|
18
|
+
if isinstance(base_geometry, MultiPolygon):
|
|
19
|
+
return [
|
|
20
|
+
polygon
|
|
21
|
+
for geom in base_geometry.geoms
|
|
22
|
+
for polygon in shapely_base_geometry_to_shapely_polygons(geom)
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
return []
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from shapely.geometry import MultiPolygon, Polygon
|
|
2
|
+
from shapely.geometry.base import BaseGeometry
|
|
3
|
+
from typeguard import typechecked
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@typechecked
|
|
7
|
+
def shapely_base_geometry_to_shapely_polygons(
|
|
8
|
+
base_geometry: BaseGeometry,
|
|
9
|
+
) -> list[Polygon]:
|
|
10
|
+
"""Recursively extract all polygons from a Shapely geometry.
|
|
11
|
+
|
|
12
|
+
Handles :class:`~shapely.geometry.Polygon` and
|
|
13
|
+
:class:`~shapely.geometry.MultiPolygon`; returns an empty list for empty
|
|
14
|
+
or unsupported geometry types.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
base_geometry : BaseGeometry
|
|
19
|
+
Any Shapely geometry.
|
|
20
|
+
|
|
21
|
+
Returns
|
|
22
|
+
-------
|
|
23
|
+
list[Polygon]
|
|
24
|
+
Flat list of all non-empty polygons found in *base_geometry*.
|
|
25
|
+
|
|
26
|
+
Examples
|
|
27
|
+
--------
|
|
28
|
+
>>> from shapely.geometry import MultiPolygon, Polygon
|
|
29
|
+
>>> from scadpy.d2.shape.utils import (
|
|
30
|
+
... shapely_base_geometry_to_shapely_polygons,
|
|
31
|
+
... )
|
|
32
|
+
|
|
33
|
+
>>> polygons = shapely_base_geometry_to_shapely_polygons(
|
|
34
|
+
... MultiPolygon([
|
|
35
|
+
... Polygon([(0, 0), (1, 0), (1, 1)]),
|
|
36
|
+
... Polygon([(2, 0), (3, 0), (3, 1)]),
|
|
37
|
+
... ])
|
|
38
|
+
... )
|
|
39
|
+
>>> len(polygons)
|
|
40
|
+
2
|
|
41
|
+
"""
|
|
42
|
+
if base_geometry.is_empty:
|
|
43
|
+
return []
|
|
44
|
+
|
|
45
|
+
if isinstance(base_geometry, Polygon):
|
|
46
|
+
return [base_geometry]
|
|
47
|
+
|
|
48
|
+
if isinstance(base_geometry, MultiPolygon):
|
|
49
|
+
return [
|
|
50
|
+
polygon
|
|
51
|
+
for geom in base_geometry.geoms
|
|
52
|
+
for polygon in shapely_base_geometry_to_shapely_polygons(geom)
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
return []
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from collections.abc import Iterable
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from numpy.typing import NDArray
|
|
5
|
+
from typeguard import typechecked
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@typechecked
|
|
9
|
+
def resolve_vector_2d(
|
|
10
|
+
values: float | Iterable[float],
|
|
11
|
+
default_value: float,
|
|
12
|
+
) -> NDArray[np.float64]:
|
|
13
|
+
"""
|
|
14
|
+
Resolves input into a 2D vector (NumPy array of length 2).
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
values : float or Iterable[float]
|
|
19
|
+
The input values to resolve into a 2D vector. It can be:
|
|
20
|
+
- A single numeric value, repeated to fill the vector.
|
|
21
|
+
- An iterable of numeric values, extended or truncated to length 2.
|
|
22
|
+
default_value : float
|
|
23
|
+
The value used to pad the vector if `values` has fewer than 2 elements.
|
|
24
|
+
|
|
25
|
+
Returns
|
|
26
|
+
-------
|
|
27
|
+
NDArray[np.float64]
|
|
28
|
+
A NumPy array of shape (2,) containing the resolved 2D vector.
|
|
29
|
+
|
|
30
|
+
Notes
|
|
31
|
+
-----
|
|
32
|
+
- If `values` is a single number, the result will be `[values, values]`.
|
|
33
|
+
- If `values` has one element, the result will be `[values[0], default_value]`.
|
|
34
|
+
- If `values` has more than 2 elements, only the first two will be kept.
|
|
35
|
+
|
|
36
|
+
Examples
|
|
37
|
+
--------
|
|
38
|
+
>>> from scadpy import resolve_vector_2d
|
|
39
|
+
>>> resolve_vector_2d(5, 0)
|
|
40
|
+
array([5., 5.])
|
|
41
|
+
|
|
42
|
+
>>> resolve_vector_2d([1], 0)
|
|
43
|
+
array([1., 0.])
|
|
44
|
+
|
|
45
|
+
>>> resolve_vector_2d([3, 4, 5], 0)
|
|
46
|
+
array([3., 4.])
|
|
47
|
+
"""
|
|
48
|
+
from scadpy.utils.resolve_vector import resolve_vector
|
|
49
|
+
|
|
50
|
+
return resolve_vector(values, default_value, 2)
|
scadpy/d3/__init__.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
from .combinations import * # noqa: F403
|
|
2
|
+
from .exporters import * # noqa: F403
|
|
3
|
+
from .features import * # noqa: F403
|
|
4
|
+
from .topologies import * # noqa: F403
|
|
5
|
+
from .importers import * # noqa: F403
|
|
6
|
+
from .primitives import * # noqa: F403
|
|
7
|
+
from .transformations import * # noqa: F403
|
|
8
|
+
from .types import * # noqa: F403
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
__all__ = [
|
|
2
|
+
"are_solid_parts_intersecting",
|
|
3
|
+
"concat_solid",
|
|
4
|
+
"exclude_solid",
|
|
5
|
+
"intersect_solid",
|
|
6
|
+
"intersect_solid_parts",
|
|
7
|
+
"subtract_solid",
|
|
8
|
+
"subtract_solid_parts",
|
|
9
|
+
"unify_solid",
|
|
10
|
+
"unify_solid_parts",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
from .are_solid_parts_intersecting import are_solid_parts_intersecting
|
|
14
|
+
from .concat_solid import concat_solid
|
|
15
|
+
from .exclude_solid import exclude_solid
|
|
16
|
+
from .intersect_solid import intersect_solid
|
|
17
|
+
from .intersect_solid_parts import intersect_solid_parts
|
|
18
|
+
from .subtract_solid import subtract_solid
|
|
19
|
+
from .subtract_solid_parts import subtract_solid_parts
|
|
20
|
+
from .unify_solid import unify_solid
|
|
21
|
+
from .unify_solid_parts import unify_solid_parts
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from trimesh import Trimesh
|
|
6
|
+
from trimesh.boolean import boolean_manifold # pyright: ignore[reportUnknownVariableType]
|
|
7
|
+
from typeguard import typechecked
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from scadpy.core.part import Part
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@typechecked
|
|
14
|
+
def are_solid_parts_intersecting(part1: Part[Trimesh], part2: Part[Trimesh]) -> bool:
|
|
15
|
+
"""Return whether two solid parts intersect geometrically.
|
|
16
|
+
|
|
17
|
+
Parameters
|
|
18
|
+
----------
|
|
19
|
+
part1 : Part[Trimesh]
|
|
20
|
+
The first solid part.
|
|
21
|
+
part2 : Part[Trimesh]
|
|
22
|
+
The second solid part.
|
|
23
|
+
|
|
24
|
+
Returns
|
|
25
|
+
-------
|
|
26
|
+
bool
|
|
27
|
+
True if the two parts intersect (shared volume > 0), False otherwise.
|
|
28
|
+
|
|
29
|
+
Examples
|
|
30
|
+
--------
|
|
31
|
+
>>> from scadpy import cuboid, are_solid_parts_intersecting
|
|
32
|
+
|
|
33
|
+
>>> are_solid_parts_intersecting(
|
|
34
|
+
... part1=cuboid(2)._parts[0],
|
|
35
|
+
... part2=cuboid(2)._parts[0],
|
|
36
|
+
... )
|
|
37
|
+
True
|
|
38
|
+
>>> are_solid_parts_intersecting(
|
|
39
|
+
... part1=cuboid(1)._parts[0],
|
|
40
|
+
... part2=cuboid(1).translate(10)._parts[0],
|
|
41
|
+
... )
|
|
42
|
+
False
|
|
43
|
+
"""
|
|
44
|
+
return bool(
|
|
45
|
+
boolean_manifold( # pyright: ignore[reportAny]
|
|
46
|
+
[part1.geometry, part2.geometry],
|
|
47
|
+
operation="intersection",
|
|
48
|
+
check_volume=False,
|
|
49
|
+
).volume
|
|
50
|
+
!= 0
|
|
51
|
+
)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Sequence
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from typeguard import typechecked
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from scadpy import Solid
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@typechecked
|
|
13
|
+
def concat_solid(solids: Sequence[Solid]) -> Solid:
|
|
14
|
+
"""Concatenate a sequence of solids into a single solid without any boolean operation.
|
|
15
|
+
|
|
16
|
+
All parts from all input solids are merged into a single solid. Parts that
|
|
17
|
+
overlap are not merged geometrically — use :func:`unify_solid` for that.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
solids : Sequence[Solid]
|
|
22
|
+
The solids to concatenate.
|
|
23
|
+
|
|
24
|
+
Returns
|
|
25
|
+
-------
|
|
26
|
+
Solid
|
|
27
|
+
A new solid containing all parts from all input solids.
|
|
28
|
+
|
|
29
|
+
Examples
|
|
30
|
+
--------
|
|
31
|
+
>>> from scadpy import cuboid, sphere, concat_solid
|
|
32
|
+
|
|
33
|
+
>>> concat_solid( # doctest: +SKIP
|
|
34
|
+
... solids=[cuboid(4), sphere(radius=2).translate([3, 2, 0])]
|
|
35
|
+
... )
|
|
36
|
+
|
|
37
|
+
.. render-example::
|
|
38
|
+
:name: concat_solid
|
|
39
|
+
:example: concat_solid(solids=[cuboid(4), sphere(radius=2).translate([3, 2, 0])])
|
|
40
|
+
"""
|
|
41
|
+
from scadpy import Solid
|
|
42
|
+
from scadpy.core.assembly import concat_assemblies
|
|
43
|
+
|
|
44
|
+
return concat_assemblies(
|
|
45
|
+
assemblies=solids,
|
|
46
|
+
get_assembly_parts=lambda assembly: assembly._parts,
|
|
47
|
+
concat_parts=Solid.from_parts,
|
|
48
|
+
)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Sequence
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from typeguard import typechecked
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from scadpy import Solid
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@typechecked
|
|
13
|
+
def exclude_solid(solids: Sequence[Solid]) -> Solid:
|
|
14
|
+
"""Compute the symmetric difference (XOR) of a sequence of solids.
|
|
15
|
+
|
|
16
|
+
Keeps only the regions that belong to exactly one of the input solids.
|
|
17
|
+
Regions shared by two or more solids are removed.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
solids : Sequence[Solid]
|
|
22
|
+
The solids to compute the symmetric difference of.
|
|
23
|
+
|
|
24
|
+
Returns
|
|
25
|
+
-------
|
|
26
|
+
Solid
|
|
27
|
+
A new solid containing only the non-overlapping regions of the input solids.
|
|
28
|
+
|
|
29
|
+
Examples
|
|
30
|
+
--------
|
|
31
|
+
>>> from scadpy import cuboid, exclude_solid, x
|
|
32
|
+
|
|
33
|
+
>>> exclude_solid( # doctest: +SKIP
|
|
34
|
+
... solids=[cuboid(4), cuboid(4).translate(x(2))]
|
|
35
|
+
... )
|
|
36
|
+
|
|
37
|
+
.. render-example::
|
|
38
|
+
:name: exclude_solid
|
|
39
|
+
:example: exclude_solid(solids=[cuboid(4), cuboid(4).translate(x(2))])
|
|
40
|
+
:ghost: concat_solid(solids=[cuboid(4), cuboid(4).translate(x(2))])
|
|
41
|
+
"""
|
|
42
|
+
from scadpy import (
|
|
43
|
+
Solid,
|
|
44
|
+
are_solid_parts_intersecting,
|
|
45
|
+
get_solid_part_bounds,
|
|
46
|
+
intersect_solid_parts,
|
|
47
|
+
subtract_solid_parts,
|
|
48
|
+
unify_solid_parts,
|
|
49
|
+
)
|
|
50
|
+
from scadpy.core.assembly import exclude_assemblies
|
|
51
|
+
|
|
52
|
+
return exclude_assemblies(
|
|
53
|
+
assemblies=solids,
|
|
54
|
+
get_assembly_parts=lambda assembly: assembly._parts,
|
|
55
|
+
get_part_bounds=get_solid_part_bounds,
|
|
56
|
+
are_parts_intersecting=are_solid_parts_intersecting,
|
|
57
|
+
subtract_parts=lambda part_base, part_cutter: subtract_solid_parts(
|
|
58
|
+
to_be_subtracted=part_base,
|
|
59
|
+
to_subtract=part_cutter,
|
|
60
|
+
make_assembly_from_parts=Solid.from_parts,
|
|
61
|
+
),
|
|
62
|
+
intersect_parts=lambda parts: intersect_solid_parts(
|
|
63
|
+
parts=parts,
|
|
64
|
+
make_assembly_from_parts=Solid.from_parts,
|
|
65
|
+
),
|
|
66
|
+
unify_parts=lambda parts: unify_solid_parts(
|
|
67
|
+
parts=parts,
|
|
68
|
+
make_assembly_from_parts=Solid.from_parts,
|
|
69
|
+
),
|
|
70
|
+
concat_parts=Solid.from_parts,
|
|
71
|
+
)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Sequence
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from typeguard import typechecked
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from scadpy import Solid
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@typechecked
|
|
13
|
+
def intersect_solid(solids: Sequence[Solid]) -> Solid:
|
|
14
|
+
"""Compute the intersection of a sequence of solids.
|
|
15
|
+
|
|
16
|
+
Only the regions shared by all input solids are kept.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
solids : Sequence[Solid]
|
|
21
|
+
The solids to intersect.
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
Solid
|
|
26
|
+
A new solid containing only the regions present in all input solids.
|
|
27
|
+
|
|
28
|
+
Examples
|
|
29
|
+
--------
|
|
30
|
+
>>> from scadpy import cuboid, sphere, intersect_solid
|
|
31
|
+
|
|
32
|
+
>>> intersect_solid( # doctest: +SKIP
|
|
33
|
+
... solids=[cuboid(4), sphere(radius=2).translate(1)]
|
|
34
|
+
... )
|
|
35
|
+
|
|
36
|
+
.. render-example::
|
|
37
|
+
:name: intersect_solid
|
|
38
|
+
:example: intersect_solid(solids=[cuboid(4), sphere(radius=2).translate(1)])
|
|
39
|
+
:ghost: cuboid(4) + sphere(radius=2).translate(1)
|
|
40
|
+
"""
|
|
41
|
+
from scadpy import (
|
|
42
|
+
Solid,
|
|
43
|
+
are_solid_parts_intersecting,
|
|
44
|
+
get_solid_part_bounds,
|
|
45
|
+
intersect_solid_parts,
|
|
46
|
+
unify_solid_parts,
|
|
47
|
+
)
|
|
48
|
+
from scadpy.core.assembly import intersect_assemblies
|
|
49
|
+
|
|
50
|
+
return intersect_assemblies(
|
|
51
|
+
assemblies=solids,
|
|
52
|
+
get_assembly_parts=lambda assembly: assembly._parts,
|
|
53
|
+
get_part_bounds=get_solid_part_bounds,
|
|
54
|
+
are_parts_intersecting=are_solid_parts_intersecting,
|
|
55
|
+
intersect_parts=lambda parts: intersect_solid_parts(
|
|
56
|
+
parts=parts,
|
|
57
|
+
make_assembly_from_parts=Solid.from_parts,
|
|
58
|
+
),
|
|
59
|
+
unify_parts=lambda parts: unify_solid_parts(
|
|
60
|
+
parts=parts,
|
|
61
|
+
make_assembly_from_parts=Solid.from_parts,
|
|
62
|
+
),
|
|
63
|
+
concat_parts=Solid.from_parts,
|
|
64
|
+
)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable, Sequence
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from trimesh import Trimesh
|
|
7
|
+
from trimesh.boolean import boolean_manifold # pyright: ignore[reportUnknownVariableType]
|
|
8
|
+
from typeguard import typechecked
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from scadpy.core.part import Part
|
|
12
|
+
from scadpy.d3.solid import Solid
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@typechecked
|
|
16
|
+
def intersect_solid_parts(
|
|
17
|
+
parts: Sequence[Part[Trimesh]],
|
|
18
|
+
make_assembly_from_parts: Callable[[Sequence[Part[Trimesh]]], Solid],
|
|
19
|
+
) -> Solid:
|
|
20
|
+
"""Intersect a sequence of solid parts and return the resulting solid.
|
|
21
|
+
|
|
22
|
+
Shortcut for :func:`intersect_parts`.
|
|
23
|
+
See :func:`intersect_parts` for full documentation.
|
|
24
|
+
|
|
25
|
+
Parameters
|
|
26
|
+
----------
|
|
27
|
+
parts : Sequence[Part[Trimesh]]
|
|
28
|
+
The solid parts to intersect.
|
|
29
|
+
make_assembly_from_parts : Callable[[Sequence[Part[Trimesh]]], Solid]
|
|
30
|
+
Factory function to build the resulting Solid from a sequence of parts.
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
-------
|
|
34
|
+
Solid
|
|
35
|
+
A new solid containing the geometric intersection of the input parts.
|
|
36
|
+
|
|
37
|
+
Examples
|
|
38
|
+
--------
|
|
39
|
+
>>> from scadpy import cuboid, sphere, intersect_solid_parts, Solid
|
|
40
|
+
|
|
41
|
+
>>> intersect_solid_parts( # doctest: +SKIP
|
|
42
|
+
... parts=(
|
|
43
|
+
... list(cuboid(4)._parts)
|
|
44
|
+
... + list(sphere(radius=2).translate([2, 2, 2])._parts)
|
|
45
|
+
... ),
|
|
46
|
+
... make_assembly_from_parts=Solid.from_parts,
|
|
47
|
+
... )
|
|
48
|
+
|
|
49
|
+
.. render-example::
|
|
50
|
+
:name: intersect_solid_parts_example
|
|
51
|
+
:example: intersect_solid_parts(parts=list(cuboid(4)._parts) + list(sphere(radius=2).translate([2, 2, 2])._parts), make_assembly_from_parts=Solid.from_parts)
|
|
52
|
+
:ghost: concat_solid(solids=[cuboid(4), sphere(radius=2).translate([2, 2, 2])])
|
|
53
|
+
"""
|
|
54
|
+
from scadpy import (
|
|
55
|
+
Part,
|
|
56
|
+
are_solid_parts_intersecting,
|
|
57
|
+
get_solid_part_bounds,
|
|
58
|
+
)
|
|
59
|
+
from scadpy.core.part import intersect_parts
|
|
60
|
+
|
|
61
|
+
return intersect_parts(
|
|
62
|
+
parts=parts,
|
|
63
|
+
get_part_color=lambda p: p.color,
|
|
64
|
+
get_part_magnitude=lambda p: p.geometry.volume, # pyright: ignore[reportAny]
|
|
65
|
+
get_part_bounds=get_solid_part_bounds,
|
|
66
|
+
are_parts_intersecting=are_solid_parts_intersecting,
|
|
67
|
+
get_part_geometry=lambda p: p.geometry,
|
|
68
|
+
intersect_geometries=lambda g: boolean_manifold(
|
|
69
|
+
g, operation="intersection", check_volume=False
|
|
70
|
+
).split(), # pyright: ignore[reportUnknownMemberType]
|
|
71
|
+
make_part_from_geometry=Part[Trimesh].from_geometry,
|
|
72
|
+
make_assembly_from_parts=make_assembly_from_parts,
|
|
73
|
+
)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from typeguard import typechecked
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from scadpy import Solid
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@typechecked
|
|
12
|
+
def subtract_solid(to_be_subtracted: Solid, to_subtract: Solid) -> Solid:
|
|
13
|
+
"""Subtract one solid from another using boolean difference.
|
|
14
|
+
|
|
15
|
+
The geometry of ``to_subtract`` is removed from ``to_be_subtracted``.
|
|
16
|
+
|
|
17
|
+
Parameters
|
|
18
|
+
----------
|
|
19
|
+
to_be_subtracted : Solid
|
|
20
|
+
The solid to subtract from.
|
|
21
|
+
to_subtract : Solid
|
|
22
|
+
The solid to subtract.
|
|
23
|
+
|
|
24
|
+
Returns
|
|
25
|
+
-------
|
|
26
|
+
Solid
|
|
27
|
+
A new solid with the geometry of ``to_subtract`` removed from ``to_be_subtracted``.
|
|
28
|
+
|
|
29
|
+
Examples
|
|
30
|
+
--------
|
|
31
|
+
>>> from scadpy import cuboid, sphere, subtract_solid
|
|
32
|
+
|
|
33
|
+
>>> subtract_solid( # doctest: +SKIP
|
|
34
|
+
... to_be_subtracted=cuboid(4), to_subtract=sphere(radius=2)
|
|
35
|
+
... )
|
|
36
|
+
|
|
37
|
+
.. render-example::
|
|
38
|
+
:name: subtract_solid
|
|
39
|
+
:example: subtract_solid(to_be_subtracted=cuboid(4), to_subtract=sphere(radius=2))
|
|
40
|
+
:ghost: cuboid(4)
|
|
41
|
+
"""
|
|
42
|
+
from scadpy import (
|
|
43
|
+
Solid,
|
|
44
|
+
are_solid_parts_intersecting,
|
|
45
|
+
get_solid_part_bounds,
|
|
46
|
+
intersect_solid_parts,
|
|
47
|
+
subtract_solid_parts,
|
|
48
|
+
unify_solid_parts,
|
|
49
|
+
)
|
|
50
|
+
from scadpy.core.assembly import subtract_assemblies
|
|
51
|
+
|
|
52
|
+
return subtract_assemblies(
|
|
53
|
+
to_be_subtracted=to_be_subtracted,
|
|
54
|
+
to_subtract=to_subtract,
|
|
55
|
+
get_assembly_parts=lambda assembly: assembly._parts,
|
|
56
|
+
get_part_bounds=get_solid_part_bounds,
|
|
57
|
+
are_parts_intersecting=are_solid_parts_intersecting,
|
|
58
|
+
subtract_parts=lambda part_base, part_cutter: subtract_solid_parts(
|
|
59
|
+
to_be_subtracted=part_base,
|
|
60
|
+
to_subtract=part_cutter,
|
|
61
|
+
make_assembly_from_parts=Solid.from_parts,
|
|
62
|
+
),
|
|
63
|
+
intersect_parts=lambda parts: intersect_solid_parts(
|
|
64
|
+
parts=parts,
|
|
65
|
+
make_assembly_from_parts=Solid.from_parts,
|
|
66
|
+
),
|
|
67
|
+
unify_parts=lambda parts: unify_solid_parts(
|
|
68
|
+
parts=parts,
|
|
69
|
+
make_assembly_from_parts=Solid.from_parts,
|
|
70
|
+
),
|
|
71
|
+
concat_parts=Solid.from_parts,
|
|
72
|
+
)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable, Sequence
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from trimesh import Trimesh
|
|
7
|
+
from trimesh.boolean import boolean_manifold # pyright: ignore[reportUnknownVariableType]
|
|
8
|
+
from typeguard import typechecked
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from scadpy.core.part import Part
|
|
12
|
+
from scadpy.d3.solid import Solid
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@typechecked
|
|
16
|
+
def subtract_solid_parts(
|
|
17
|
+
to_be_subtracted: Part[Trimesh],
|
|
18
|
+
to_subtract: Part[Trimesh],
|
|
19
|
+
make_assembly_from_parts: Callable[[Sequence[Part[Trimesh]]], Solid],
|
|
20
|
+
) -> Solid:
|
|
21
|
+
"""Subtract one solid part from another and return the resulting solid.
|
|
22
|
+
|
|
23
|
+
Shortcut for :func:`subtract_parts`.
|
|
24
|
+
See :func:`subtract_parts` for full documentation.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
to_be_subtracted : Part[Trimesh]
|
|
29
|
+
The part to subtract from.
|
|
30
|
+
to_subtract : Part[Trimesh]
|
|
31
|
+
The part to subtract.
|
|
32
|
+
make_assembly_from_parts : Callable[[list[Part[Trimesh]]], Solid]
|
|
33
|
+
Factory function to build the resulting Solid from a sequence of parts.
|
|
34
|
+
|
|
35
|
+
Returns
|
|
36
|
+
-------
|
|
37
|
+
Solid
|
|
38
|
+
A new solid with the geometry of ``to_subtract`` removed from ``to_be_subtracted``.
|
|
39
|
+
|
|
40
|
+
Examples
|
|
41
|
+
--------
|
|
42
|
+
>>> from scadpy import cuboid, sphere, subtract_solid_parts, Solid
|
|
43
|
+
|
|
44
|
+
>>> subtract_solid_parts( # doctest: +SKIP
|
|
45
|
+
... to_be_subtracted=cuboid(4)._parts[0],
|
|
46
|
+
... to_subtract=sphere(radius=2)._parts[0],
|
|
47
|
+
... make_assembly_from_parts=Solid.from_parts,
|
|
48
|
+
... )
|
|
49
|
+
|
|
50
|
+
.. render-example::
|
|
51
|
+
:name: subtract_solid_parts_example
|
|
52
|
+
:example: subtract_solid_parts(to_be_subtracted=cuboid(4)._parts[0], to_subtract=sphere(radius=2)._parts[0], make_assembly_from_parts=Solid.from_parts)
|
|
53
|
+
:ghost: concat_solid(solids=[cuboid(4), sphere(radius=2)])
|
|
54
|
+
"""
|
|
55
|
+
from scadpy import Part
|
|
56
|
+
from scadpy.core.part import subtract_parts
|
|
57
|
+
|
|
58
|
+
return subtract_parts(
|
|
59
|
+
to_be_subtracted=to_be_subtracted,
|
|
60
|
+
to_subtract=to_subtract,
|
|
61
|
+
get_part_color=lambda p: p.color,
|
|
62
|
+
get_part_geometry=lambda p: p.geometry,
|
|
63
|
+
subtract_geometries=lambda g1, g2: boolean_manifold(
|
|
64
|
+
[g1, g2], operation="difference", check_volume=False
|
|
65
|
+
).split(), # pyright: ignore[reportUnknownMemberType]
|
|
66
|
+
make_part_from_geometry=Part[Trimesh].from_geometry,
|
|
67
|
+
make_assembly_from_parts=make_assembly_from_parts,
|
|
68
|
+
)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Sequence
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from typeguard import typechecked
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from scadpy import Solid
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@typechecked
|
|
13
|
+
def unify_solid(solids: Sequence[Solid]) -> Solid:
|
|
14
|
+
"""Unite a sequence of solids into a single solid using boolean union.
|
|
15
|
+
|
|
16
|
+
All overlapping parts across the input solids are merged geometrically.
|
|
17
|
+
Use :func:`concat_solid` if you want to combine solids without merging overlaps.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
solids : Sequence[Solid]
|
|
22
|
+
The solids to unite.
|
|
23
|
+
|
|
24
|
+
Returns
|
|
25
|
+
-------
|
|
26
|
+
Solid
|
|
27
|
+
A new solid containing the geometric union of all input solids.
|
|
28
|
+
|
|
29
|
+
Examples
|
|
30
|
+
--------
|
|
31
|
+
>>> from scadpy import cuboid, sphere, unify_solid, x
|
|
32
|
+
|
|
33
|
+
>>> unify_solid( # doctest: +SKIP
|
|
34
|
+
... solids=[cuboid(4), sphere(radius=2).translate(x(2))]
|
|
35
|
+
... )
|
|
36
|
+
|
|
37
|
+
.. render-example::
|
|
38
|
+
:name: unify_solid
|
|
39
|
+
:example: unify_solid(solids=[cuboid(4), sphere(radius=2).translate(x(2))])
|
|
40
|
+
"""
|
|
41
|
+
from scadpy import Solid, unify_solid_parts
|
|
42
|
+
from scadpy.core.assembly import unify_assemblies
|
|
43
|
+
|
|
44
|
+
return unify_assemblies(
|
|
45
|
+
assemblies=solids,
|
|
46
|
+
get_assembly_parts=lambda assembly: assembly._parts,
|
|
47
|
+
unify_parts=lambda parts: unify_solid_parts(
|
|
48
|
+
parts=parts,
|
|
49
|
+
make_assembly_from_parts=Solid.from_parts,
|
|
50
|
+
),
|
|
51
|
+
)
|