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,66 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from shapely.geometry.polygon import Polygon
|
|
7
|
+
from typeguard import typechecked
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from scadpy.core.part import Part
|
|
11
|
+
from scadpy.d2.shape import Shape
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@typechecked
|
|
15
|
+
def subtract_shape_parts(
|
|
16
|
+
to_be_subtracted: Part[Polygon],
|
|
17
|
+
to_subtract: Part[Polygon],
|
|
18
|
+
make_assembly_from_parts: Callable[[list[Part[Polygon]]], Shape],
|
|
19
|
+
) -> Shape:
|
|
20
|
+
"""Subtract one shape part from another and return the resulting shape.
|
|
21
|
+
|
|
22
|
+
Shortcut for :func:`subtract_parts`.
|
|
23
|
+
See :func:`subtract_parts` for full documentation.
|
|
24
|
+
|
|
25
|
+
Parameters
|
|
26
|
+
----------
|
|
27
|
+
to_be_subtracted : Part[Polygon]
|
|
28
|
+
The part to subtract from.
|
|
29
|
+
to_subtract : Part[Polygon]
|
|
30
|
+
The part to subtract.
|
|
31
|
+
make_assembly_from_parts : Callable[[list[Part[Polygon]]], Shape]
|
|
32
|
+
Factory function to build the resulting Shape from a sequence of parts.
|
|
33
|
+
|
|
34
|
+
Returns
|
|
35
|
+
-------
|
|
36
|
+
Shape
|
|
37
|
+
A new shape with the geometry of ``to_subtract`` removed from ``to_be_subtracted``.
|
|
38
|
+
|
|
39
|
+
Examples
|
|
40
|
+
--------
|
|
41
|
+
>>> from scadpy import square, circle, subtract_shape_parts, Shape
|
|
42
|
+
|
|
43
|
+
>>> subtract_shape_parts(
|
|
44
|
+
... to_be_subtracted=square(4)._parts[0],
|
|
45
|
+
... to_subtract=circle(radius=1)._parts[0],
|
|
46
|
+
... make_assembly_from_parts=Shape.from_parts,
|
|
47
|
+
... ) # doctest: +SKIP
|
|
48
|
+
|
|
49
|
+
.. render-example::
|
|
50
|
+
:name: subtract_shape_parts_example
|
|
51
|
+
:example: subtract_shape_parts(to_be_subtracted=square(4)._parts[0], to_subtract=circle(radius=1)._parts[0], make_assembly_from_parts=Shape.from_parts)
|
|
52
|
+
:ghost: square(4)
|
|
53
|
+
"""
|
|
54
|
+
from scadpy import Part, shapely_base_geometry_to_shapely_polygons, subtract_parts
|
|
55
|
+
|
|
56
|
+
return subtract_parts(
|
|
57
|
+
to_be_subtracted=to_be_subtracted,
|
|
58
|
+
to_subtract=to_subtract,
|
|
59
|
+
get_part_color=lambda p: p.color,
|
|
60
|
+
get_part_geometry=lambda p: p.geometry,
|
|
61
|
+
subtract_geometries=lambda p_1, p_2: (
|
|
62
|
+
shapely_base_geometry_to_shapely_polygons(p_1 - p_2)
|
|
63
|
+
),
|
|
64
|
+
make_part_from_geometry=Part[Polygon].from_geometry,
|
|
65
|
+
make_assembly_from_parts=make_assembly_from_parts,
|
|
66
|
+
)
|
|
@@ -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 Shape
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@typechecked
|
|
13
|
+
def unify_shape(shapes: Sequence[Shape]) -> Shape:
|
|
14
|
+
"""Unite a sequence of shapes into a single shape using boolean union.
|
|
15
|
+
|
|
16
|
+
All overlapping parts across the input shapes are merged geometrically.
|
|
17
|
+
Use :func:`concat_shape` if you want to combine shapes without merging overlaps.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
shapes : Sequence[Shape]
|
|
22
|
+
The shapes to unite.
|
|
23
|
+
|
|
24
|
+
Returns
|
|
25
|
+
-------
|
|
26
|
+
Shape
|
|
27
|
+
A new shape containing the geometric union of all input shapes.
|
|
28
|
+
|
|
29
|
+
Examples
|
|
30
|
+
--------
|
|
31
|
+
>>> from scadpy import square, circle, unify_shape
|
|
32
|
+
|
|
33
|
+
>>> unify_shape( # doctest: +SKIP
|
|
34
|
+
... shapes=[square(4), circle(radius=2).translate([2, 0])]
|
|
35
|
+
... )
|
|
36
|
+
|
|
37
|
+
.. render-example::
|
|
38
|
+
:name: unify_shape
|
|
39
|
+
:example: unify_shape(shapes=[square(4), circle(radius=2).translate([2, 0])])
|
|
40
|
+
"""
|
|
41
|
+
from scadpy import Shape, unify_shape_parts
|
|
42
|
+
from scadpy.core.assembly import unify_assemblies
|
|
43
|
+
|
|
44
|
+
return unify_assemblies(
|
|
45
|
+
assemblies=shapes,
|
|
46
|
+
get_assembly_parts=lambda assembly: assembly._parts,
|
|
47
|
+
unify_parts=lambda parts: unify_shape_parts(
|
|
48
|
+
parts=parts,
|
|
49
|
+
make_assembly_from_parts=Shape.from_parts,
|
|
50
|
+
),
|
|
51
|
+
)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable, Sequence
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from shapely.geometry.polygon import Polygon
|
|
7
|
+
from shapely.ops import unary_union
|
|
8
|
+
from typeguard import typechecked
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from scadpy.core.part import Part
|
|
12
|
+
from scadpy.d2.shape import Shape
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@typechecked
|
|
16
|
+
def unify_shape_parts(
|
|
17
|
+
parts: Sequence[Part[Polygon]],
|
|
18
|
+
make_assembly_from_parts: Callable[[Sequence[Part[Polygon]]], Shape],
|
|
19
|
+
) -> Shape:
|
|
20
|
+
"""Unite a sequence of shape parts and return the resulting shape.
|
|
21
|
+
|
|
22
|
+
Shortcut for :func:`unify_parts`.
|
|
23
|
+
See :func:`unify_parts` for full documentation.
|
|
24
|
+
|
|
25
|
+
Parameters
|
|
26
|
+
----------
|
|
27
|
+
parts : Sequence[Part[Polygon]]
|
|
28
|
+
The shape parts to unite.
|
|
29
|
+
make_assembly_from_parts : Callable[[Sequence[Part[Polygon]]], Shape]
|
|
30
|
+
Factory function to build the resulting Shape from a sequence of parts.
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
-------
|
|
34
|
+
Shape
|
|
35
|
+
A new shape containing the geometric union of the input parts.
|
|
36
|
+
|
|
37
|
+
Examples
|
|
38
|
+
--------
|
|
39
|
+
>>> from scadpy import square, circle, unify_shape_parts, Shape
|
|
40
|
+
|
|
41
|
+
>>> unify_shape_parts( # doctest: +SKIP
|
|
42
|
+
... parts=(
|
|
43
|
+
... list(square(3)._parts)
|
|
44
|
+
... + list(circle(radius=1.5).translate([2, 2])._parts)
|
|
45
|
+
... ),
|
|
46
|
+
... make_assembly_from_parts=Shape.from_parts,
|
|
47
|
+
... )
|
|
48
|
+
|
|
49
|
+
.. render-example::
|
|
50
|
+
:name: unify_shape_parts_example
|
|
51
|
+
:example: unify_shape_parts(parts=list(square(3)._parts) + list(circle(radius=1.5).translate([2, 2])._parts), make_assembly_from_parts=Shape.from_parts)
|
|
52
|
+
:ghost: concat_shape(shapes=[square(3), circle(radius=1.5).translate([2, 2])])
|
|
53
|
+
"""
|
|
54
|
+
from scadpy import (
|
|
55
|
+
Part,
|
|
56
|
+
are_shape_parts_intersecting,
|
|
57
|
+
get_shape_part_bounds,
|
|
58
|
+
shapely_base_geometry_to_shapely_polygons,
|
|
59
|
+
unify_parts,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
return unify_parts(
|
|
63
|
+
parts=parts,
|
|
64
|
+
get_part_color=lambda p: p.color,
|
|
65
|
+
get_part_magnitude=lambda p: p.geometry.area,
|
|
66
|
+
get_part_bounds=get_shape_part_bounds,
|
|
67
|
+
are_parts_intersecting=are_shape_parts_intersecting,
|
|
68
|
+
get_part_geometry=lambda p: p.geometry,
|
|
69
|
+
unify_geometries=lambda g: shapely_base_geometry_to_shapely_polygons(
|
|
70
|
+
unary_union(g)
|
|
71
|
+
),
|
|
72
|
+
make_part_from_geometry=Part[Polygon].from_geometry,
|
|
73
|
+
make_assembly_from_parts=make_assembly_from_parts,
|
|
74
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
__all__ = [
|
|
2
|
+
"map_shape_to_dxf",
|
|
3
|
+
"map_shape_to_dxf_file",
|
|
4
|
+
"map_shape_to_html",
|
|
5
|
+
"map_shape_to_html_file",
|
|
6
|
+
"map_shape_to_screen",
|
|
7
|
+
"map_shape_to_svg",
|
|
8
|
+
"map_shape_to_svg_file",
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
from .map_shape_to_dxf import map_shape_to_dxf
|
|
12
|
+
from .map_shape_to_dxf_file import map_shape_to_dxf_file
|
|
13
|
+
from .map_shape_to_html import map_shape_to_html
|
|
14
|
+
from .map_shape_to_html_file import map_shape_to_html_file
|
|
15
|
+
from .map_shape_to_screen import map_shape_to_screen
|
|
16
|
+
from .map_shape_to_svg import map_shape_to_svg
|
|
17
|
+
from .map_shape_to_svg_file import map_shape_to_svg_file
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
import trimesh
|
|
6
|
+
from shapely.geometry import MultiPolygon
|
|
7
|
+
from trimesh.path.exchange.dxf import export_dxf
|
|
8
|
+
from typeguard import typechecked
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from scadpy import Shape
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@typechecked
|
|
15
|
+
def map_shape_to_dxf(shape: Shape) -> str:
|
|
16
|
+
"""Export a shape to a DXF string.
|
|
17
|
+
|
|
18
|
+
Each part of the shape is exported as a closed polyline. Polygon
|
|
19
|
+
holes are exported as separate polylines.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
shape : Shape
|
|
24
|
+
The shape to export.
|
|
25
|
+
|
|
26
|
+
Returns
|
|
27
|
+
-------
|
|
28
|
+
str
|
|
29
|
+
A DXF document as a string.
|
|
30
|
+
|
|
31
|
+
Examples
|
|
32
|
+
--------
|
|
33
|
+
>>> from scadpy import square, circle, map_shape_to_dxf
|
|
34
|
+
|
|
35
|
+
>>> dxf = map_shape_to_dxf(square(4) - circle(1))
|
|
36
|
+
>>> dxf.startswith("999")
|
|
37
|
+
True
|
|
38
|
+
"""
|
|
39
|
+
geometries = [part.geometry for part in shape._parts]
|
|
40
|
+
if not geometries:
|
|
41
|
+
return ""
|
|
42
|
+
|
|
43
|
+
return export_dxf(trimesh.load_path(MultiPolygon(geometries)))
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from typeguard import typechecked
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from scadpy import Shape
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@typechecked
|
|
13
|
+
def map_shape_to_dxf_file(shape: Shape, path: str | Path) -> int:
|
|
14
|
+
"""Save a shape as a DXF file.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
shape : Shape
|
|
19
|
+
The shape to export.
|
|
20
|
+
path : str or Path
|
|
21
|
+
Destination file path.
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
int
|
|
26
|
+
Number of characters written.
|
|
27
|
+
|
|
28
|
+
Examples
|
|
29
|
+
--------
|
|
30
|
+
>>> from scadpy import square, circle, map_shape_to_dxf_file
|
|
31
|
+
|
|
32
|
+
>>> map_shape_to_dxf_file( # doctest: +SKIP
|
|
33
|
+
... shape=square(4) - circle(1), path="output.dxf"
|
|
34
|
+
... )
|
|
35
|
+
"""
|
|
36
|
+
from scadpy import map_shape_to_dxf
|
|
37
|
+
|
|
38
|
+
return Path(path).write_text(map_shape_to_dxf(shape), encoding="utf-8")
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from io import StringIO
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
import matplotlib.pyplot as plt
|
|
7
|
+
from IPython.core.display import HTML
|
|
8
|
+
from shapely.plotting import plot_polygon
|
|
9
|
+
from typeguard import typechecked
|
|
10
|
+
|
|
11
|
+
from scadpy.color.constants import BLACK, WHITE
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from scadpy import Color, Shape
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@typechecked
|
|
18
|
+
def map_shape_to_html(
|
|
19
|
+
shape: Shape,
|
|
20
|
+
background_color: Color = WHITE,
|
|
21
|
+
foreground_color: Color = BLACK,
|
|
22
|
+
) -> HTML:
|
|
23
|
+
"""
|
|
24
|
+
Render a shape assembly as an SVG HTML object using matplotlib and shapely.
|
|
25
|
+
|
|
26
|
+
This function extracts all parts from the assembly, converts each to a Shapely
|
|
27
|
+
polygon, and plots them with their associated colors. The resulting figure is
|
|
28
|
+
exported as SVG and wrapped in an IPython HTML object for display in notebooks
|
|
29
|
+
or web interfaces.
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
----------
|
|
33
|
+
shape : Shape
|
|
34
|
+
The shape to render.
|
|
35
|
+
background_color : Color, default=WHITE
|
|
36
|
+
The background color of the rendered output.
|
|
37
|
+
foreground_color : Color, default=BLACK
|
|
38
|
+
The foreground color (axes, grid) of the rendered output.
|
|
39
|
+
|
|
40
|
+
Returns
|
|
41
|
+
-------
|
|
42
|
+
HTML
|
|
43
|
+
An IPython HTML object containing the SVG rendering of the shape.
|
|
44
|
+
|
|
45
|
+
Examples
|
|
46
|
+
--------
|
|
47
|
+
>>> from IPython.core.display import HTML
|
|
48
|
+
>>> from scadpy import square, map_shape_to_html
|
|
49
|
+
|
|
50
|
+
>>> html = map_shape_to_html(shape=square(4))
|
|
51
|
+
>>> isinstance(html, HTML)
|
|
52
|
+
True
|
|
53
|
+
"""
|
|
54
|
+
foreground_color_hex = "#{:02X}{:02X}{:02X}".format(
|
|
55
|
+
*(int(x * 255) for x in foreground_color[:-1])
|
|
56
|
+
)
|
|
57
|
+
background_color_hex = "#{:02X}{:02X}{:02X}".format(
|
|
58
|
+
*(int(x * 255) for x in background_color[:-1])
|
|
59
|
+
)
|
|
60
|
+
x_min, y_min, x_max, y_max = shape.bounds
|
|
61
|
+
|
|
62
|
+
width = x_max - x_min
|
|
63
|
+
height = y_max - y_min
|
|
64
|
+
|
|
65
|
+
if width > height:
|
|
66
|
+
difference = width - height
|
|
67
|
+
y_max = y_max + difference / 2
|
|
68
|
+
y_min = y_min - difference / 2
|
|
69
|
+
height = width
|
|
70
|
+
else:
|
|
71
|
+
difference = height - width
|
|
72
|
+
x_max = x_max + difference / 2
|
|
73
|
+
x_min = x_min - difference / 2
|
|
74
|
+
width = height
|
|
75
|
+
|
|
76
|
+
if width == 0 or height == 0:
|
|
77
|
+
width = max(width, 1.0)
|
|
78
|
+
height = max(height, 1.0)
|
|
79
|
+
|
|
80
|
+
aspect_ratio = height / width
|
|
81
|
+
fig_width = 5
|
|
82
|
+
fig_height = fig_width * aspect_ratio
|
|
83
|
+
fig, ax = plt.subplots(figsize=(fig_width, fig_height))
|
|
84
|
+
|
|
85
|
+
fig.patch.set_facecolor(background_color_hex)
|
|
86
|
+
ax.set_facecolor(background_color_hex)
|
|
87
|
+
ax.tick_params(axis="both", colors=foreground_color_hex)
|
|
88
|
+
|
|
89
|
+
for spine in ax.spines.values():
|
|
90
|
+
spine.set_edgecolor(foreground_color_hex)
|
|
91
|
+
|
|
92
|
+
for part in shape._parts:
|
|
93
|
+
color = part.color
|
|
94
|
+
edge_color = tuple((c + b) / 2 for c, b in zip(color[:3], background_color[:3]))
|
|
95
|
+
plot_polygon(
|
|
96
|
+
part.geometry,
|
|
97
|
+
ax=ax,
|
|
98
|
+
add_points=False,
|
|
99
|
+
facecolor=(color[0], color[1], color[2], color[3]),
|
|
100
|
+
edgecolor=(*edge_color, 1.0),
|
|
101
|
+
linewidth=2,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
padding = 0.1 * width
|
|
105
|
+
ax.set_xlim(x_min - padding, x_max + padding)
|
|
106
|
+
ax.set_ylim(y_min - padding, y_max + padding)
|
|
107
|
+
|
|
108
|
+
ax.set_aspect("equal")
|
|
109
|
+
ax.grid(True, alpha=0.3, linewidth=0.5)
|
|
110
|
+
ax.axhline(y=0, color=foreground_color_hex, linewidth=1, alpha=0.3)
|
|
111
|
+
ax.axvline(x=0, color=foreground_color_hex, linewidth=1, alpha=0.3)
|
|
112
|
+
|
|
113
|
+
svg_output = StringIO()
|
|
114
|
+
plt.savefig(svg_output, format="svg", bbox_inches="tight", pad_inches=0)
|
|
115
|
+
plt.close()
|
|
116
|
+
|
|
117
|
+
return HTML(svg_output.getvalue())
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from scadpy.color.constants import BLACK, WHITE
|
|
6
|
+
from typeguard import typechecked
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from scadpy import Color, Shape
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@typechecked
|
|
13
|
+
def map_shape_to_html_file(
|
|
14
|
+
shape: Shape,
|
|
15
|
+
path: str,
|
|
16
|
+
background_color: Color = WHITE,
|
|
17
|
+
foreground_color: Color = BLACK,
|
|
18
|
+
) -> int:
|
|
19
|
+
"""Save a shape as an HTML file.
|
|
20
|
+
|
|
21
|
+
Shortcut for :func:`map_component_to_html_file`.
|
|
22
|
+
See :func:`map_component_to_html_file` for full documentation.
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
shape : Shape
|
|
27
|
+
The shape to save.
|
|
28
|
+
path : str
|
|
29
|
+
The file path where the HTML will be written.
|
|
30
|
+
background_color : Color, default=WHITE
|
|
31
|
+
The background color of the rendered output.
|
|
32
|
+
foreground_color : Color, default=BLACK
|
|
33
|
+
The foreground color (axes, grid) of the rendered output.
|
|
34
|
+
|
|
35
|
+
Returns
|
|
36
|
+
-------
|
|
37
|
+
int
|
|
38
|
+
The number of characters written to the file.
|
|
39
|
+
|
|
40
|
+
Examples
|
|
41
|
+
--------
|
|
42
|
+
>>> from scadpy import square, map_shape_to_html_file
|
|
43
|
+
|
|
44
|
+
>>> map_shape_to_html_file( # doctest: +SKIP
|
|
45
|
+
... shape=square(4), path="output.html"
|
|
46
|
+
... )
|
|
47
|
+
"""
|
|
48
|
+
from scadpy import map_component_to_html_file, map_shape_to_html
|
|
49
|
+
|
|
50
|
+
return map_component_to_html_file(
|
|
51
|
+
component=shape,
|
|
52
|
+
path=path,
|
|
53
|
+
to_html=lambda component: map_shape_to_html(
|
|
54
|
+
shape=component,
|
|
55
|
+
background_color=background_color,
|
|
56
|
+
foreground_color=foreground_color,
|
|
57
|
+
),
|
|
58
|
+
)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from scadpy.color.constants import BLACK, WHITE
|
|
6
|
+
from typeguard import typechecked
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from scadpy import Color, Shape
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@typechecked
|
|
13
|
+
def map_shape_to_screen(
|
|
14
|
+
shape: Shape,
|
|
15
|
+
background_color: Color = WHITE,
|
|
16
|
+
foreground_color: Color = BLACK,
|
|
17
|
+
) -> None:
|
|
18
|
+
"""Display a shape in a Qt-based window.
|
|
19
|
+
|
|
20
|
+
Shortcut for :func:`map_component_to_screen`.
|
|
21
|
+
See :func:`map_component_to_screen` for full documentation.
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
shape : Shape
|
|
26
|
+
The shape to display.
|
|
27
|
+
background_color : Color, default=WHITE
|
|
28
|
+
The background color of the rendered window.
|
|
29
|
+
foreground_color : Color, default=BLACK
|
|
30
|
+
The foreground color (axes, grid) of the rendered window.
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
-------
|
|
34
|
+
None
|
|
35
|
+
|
|
36
|
+
Examples
|
|
37
|
+
--------
|
|
38
|
+
>>> from scadpy import square, map_shape_to_screen
|
|
39
|
+
|
|
40
|
+
>>> map_shape_to_screen(shape=square(4)) # doctest: +SKIP
|
|
41
|
+
"""
|
|
42
|
+
from scadpy import map_component_to_screen, map_shape_to_html
|
|
43
|
+
|
|
44
|
+
map_component_to_screen(
|
|
45
|
+
component=shape,
|
|
46
|
+
to_html=lambda component: map_shape_to_html(
|
|
47
|
+
shape=component,
|
|
48
|
+
background_color=background_color,
|
|
49
|
+
foreground_color=foreground_color,
|
|
50
|
+
),
|
|
51
|
+
)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
import trimesh
|
|
6
|
+
from shapely.geometry import MultiPolygon
|
|
7
|
+
from trimesh.path.exchange.svg_io import export_svg
|
|
8
|
+
from typeguard import typechecked
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from scadpy import Shape
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@typechecked
|
|
15
|
+
def map_shape_to_svg(shape: Shape) -> str:
|
|
16
|
+
"""Export a shape to an SVG string.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
shape : Shape
|
|
21
|
+
The shape to export.
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
str
|
|
26
|
+
A self-contained SVG document as a string.
|
|
27
|
+
|
|
28
|
+
Examples
|
|
29
|
+
--------
|
|
30
|
+
>>> from scadpy import square, circle, map_shape_to_svg
|
|
31
|
+
|
|
32
|
+
>>> svg = map_shape_to_svg(square(4) - circle(1))
|
|
33
|
+
>>> svg.startswith("<svg")
|
|
34
|
+
True
|
|
35
|
+
"""
|
|
36
|
+
geometries = [part.geometry for part in shape._parts]
|
|
37
|
+
if not geometries:
|
|
38
|
+
return '<svg xmlns="http://www.w3.org/2000/svg"/>'
|
|
39
|
+
|
|
40
|
+
return export_svg(trimesh.load_path(MultiPolygon(geometries)))
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from typeguard import typechecked
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from scadpy import Shape
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@typechecked
|
|
13
|
+
def map_shape_to_svg_file(shape: Shape, path: str | Path) -> int:
|
|
14
|
+
"""Save a shape as an SVG file.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
shape : Shape
|
|
19
|
+
The shape to export.
|
|
20
|
+
path : str or Path
|
|
21
|
+
Destination file path.
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
int
|
|
26
|
+
Number of characters written.
|
|
27
|
+
|
|
28
|
+
Examples
|
|
29
|
+
--------
|
|
30
|
+
>>> from scadpy import square, circle, map_shape_to_svg_file
|
|
31
|
+
|
|
32
|
+
>>> map_shape_to_svg_file( # doctest: +SKIP
|
|
33
|
+
... shape=square(4) - circle(1), path="output.svg"
|
|
34
|
+
... )
|
|
35
|
+
"""
|
|
36
|
+
from scadpy import map_shape_to_svg
|
|
37
|
+
|
|
38
|
+
return Path(path).write_text(map_shape_to_svg(shape), encoding="utf-8")
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from numpy.typing import NDArray
|
|
7
|
+
from typeguard import typechecked
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from scadpy import Shape
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@typechecked
|
|
14
|
+
def get_shape_bounds(shape: Shape) -> NDArray[np.float64]:
|
|
15
|
+
"""
|
|
16
|
+
Return the axis-aligned bounding box of the shape.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
shape : Shape
|
|
21
|
+
The shape to compute bounds for.
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
NDArray[np.float64]
|
|
26
|
+
1D array ``[min_x, min_y, max_x, max_y]``.
|
|
27
|
+
Returns zeros if the shape is empty.
|
|
28
|
+
|
|
29
|
+
Examples
|
|
30
|
+
--------
|
|
31
|
+
>>> from shapely.geometry import Polygon
|
|
32
|
+
>>> from scadpy import Shape, get_shape_bounds
|
|
33
|
+
|
|
34
|
+
>>> polygon = Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])
|
|
35
|
+
>>> get_shape_bounds(Shape.from_geometry(polygon))
|
|
36
|
+
array([0., 0., 2., 2.])
|
|
37
|
+
"""
|
|
38
|
+
from scadpy import get_component_bounds
|
|
39
|
+
|
|
40
|
+
return get_component_bounds(shape.vertex_coordinates)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from numpy.typing import NDArray
|
|
7
|
+
from shapely.geometry.polygon import Polygon
|
|
8
|
+
from typeguard import typechecked
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from scadpy.core.part import Part
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@typechecked
|
|
15
|
+
def get_shape_part_bounds(part: Part[Polygon]) -> NDArray[np.float64]:
|
|
16
|
+
"""Return the 2D bounding box of a shape part as [minx, miny, maxx, maxy].
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
part : Part[Polygon]
|
|
21
|
+
The shape part to compute the bounding box of.
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
NDArray[np.float64]
|
|
26
|
+
Array of shape (4,) containing [minx, miny, maxx, maxy].
|
|
27
|
+
|
|
28
|
+
Examples
|
|
29
|
+
--------
|
|
30
|
+
>>> from scadpy import square, get_shape_part_bounds
|
|
31
|
+
>>> bounds = get_shape_part_bounds(part=square(2)._parts[0])
|
|
32
|
+
>>> bounds.shape
|
|
33
|
+
(4,)
|
|
34
|
+
"""
|
|
35
|
+
from scadpy import get_component_bounds, get_shape_part_vertex_coordinates
|
|
36
|
+
|
|
37
|
+
return get_component_bounds(get_shape_part_vertex_coordinates(part))
|