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.
Files changed (236) hide show
  1. scadpy/__init__.py +5 -0
  2. scadpy/color/__init__.py +3 -0
  3. scadpy/color/constants/BEIGE.py +3 -0
  4. scadpy/color/constants/BLACK.py +3 -0
  5. scadpy/color/constants/BLUE.py +3 -0
  6. scadpy/color/constants/BROWN.py +3 -0
  7. scadpy/color/constants/DARK_GRAY.py +3 -0
  8. scadpy/color/constants/DEFAULT_COLOR.py +3 -0
  9. scadpy/color/constants/DEFAULT_OPACITY.py +1 -0
  10. scadpy/color/constants/GRAY.py +3 -0
  11. scadpy/color/constants/GREEN.py +3 -0
  12. scadpy/color/constants/ORANGE.py +3 -0
  13. scadpy/color/constants/RED.py +3 -0
  14. scadpy/color/constants/WHITE.py +3 -0
  15. scadpy/color/constants/YELLOW.py +3 -0
  16. scadpy/color/constants/__init__.py +29 -0
  17. scadpy/color/type/__init__.py +3 -0
  18. scadpy/color/type/color.py +3 -0
  19. scadpy/color/utils/__init__.py +3 -0
  20. scadpy/color/utils/get_random_color.py +36 -0
  21. scadpy/core/__init__.py +3 -0
  22. scadpy/core/assembly/__init__.py +5 -0
  23. scadpy/core/assembly/combinations/__init__.py +13 -0
  24. scadpy/core/assembly/combinations/concat_assemblies.py +50 -0
  25. scadpy/core/assembly/combinations/exclude_assemblies.py +135 -0
  26. scadpy/core/assembly/combinations/intersect_assemblies.py +128 -0
  27. scadpy/core/assembly/combinations/subtract_assemblies.py +151 -0
  28. scadpy/core/assembly/combinations/unify_assemblies.py +59 -0
  29. scadpy/core/assembly/topologies/__init__.py +41 -0
  30. scadpy/core/assembly/topologies/directed_edge/__init__.py +9 -0
  31. scadpy/core/assembly/topologies/directed_edge/get_assembly_directed_edge_directions.py +70 -0
  32. scadpy/core/assembly/topologies/directed_edge/get_assembly_directed_edge_to_edge.py +49 -0
  33. scadpy/core/assembly/topologies/directed_edge/get_assembly_directed_edge_to_vertex.py +54 -0
  34. scadpy/core/assembly/topologies/edge/__init__.py +9 -0
  35. scadpy/core/assembly/topologies/edge/get_assembly_edge_lengths.py +46 -0
  36. scadpy/core/assembly/topologies/edge/get_assembly_edge_midpoints.py +51 -0
  37. scadpy/core/assembly/topologies/edge/get_assembly_edge_normals.py +67 -0
  38. scadpy/core/assembly/topologies/face_corner/__init__.py +13 -0
  39. scadpy/core/assembly/topologies/face_corner/get_assembly_face_corner_angles.py +72 -0
  40. scadpy/core/assembly/topologies/face_corner/get_assembly_face_corner_normals.py +103 -0
  41. scadpy/core/assembly/topologies/face_corner/get_assembly_face_corner_to_incoming_directed_edge.py +65 -0
  42. scadpy/core/assembly/topologies/face_corner/get_assembly_face_corner_to_outgoing_directed_edge.py +65 -0
  43. scadpy/core/assembly/topologies/face_corner/get_assembly_face_directed_edge_to_corner.py +79 -0
  44. scadpy/core/assembly/topologies/part/__init__.py +5 -0
  45. scadpy/core/assembly/topologies/part/get_assembly_part_colors.py +55 -0
  46. scadpy/core/assembly/topologies/vertex/__init__.py +7 -0
  47. scadpy/core/assembly/topologies/vertex/get_assembly_vertex_coordinates.py +70 -0
  48. scadpy/core/assembly/topologies/vertex/get_assembly_vertex_to_part.py +62 -0
  49. scadpy/core/assembly/transformations/__init__.py +19 -0
  50. scadpy/core/assembly/transformations/color_assembly.py +24 -0
  51. scadpy/core/assembly/transformations/mirror_vertex_coordinates.py +68 -0
  52. scadpy/core/assembly/transformations/pull_vertex_coordinates.py +64 -0
  53. scadpy/core/assembly/transformations/push_vertex_coordinates.py +64 -0
  54. scadpy/core/assembly/transformations/resize_vertex_coordinates.py +121 -0
  55. scadpy/core/assembly/transformations/rotate_vertex_coordinates.py +73 -0
  56. scadpy/core/assembly/transformations/scale_vertex_coordinates.py +76 -0
  57. scadpy/core/assembly/transformations/translate_vertex_coordinates.py +70 -0
  58. scadpy/core/assembly/types/__init__.py +7 -0
  59. scadpy/core/assembly/types/assembly.py +14 -0
  60. scadpy/core/assembly/types/topology_filter.py +6 -0
  61. scadpy/core/assembly/utils/__init__.py +9 -0
  62. scadpy/core/assembly/utils/lookup_pairs.py +56 -0
  63. scadpy/core/assembly/utils/resolve_topology_filter.py +84 -0
  64. scadpy/core/assembly/utils/transform_filtered_parts.py +55 -0
  65. scadpy/core/component/__init__.py +3 -0
  66. scadpy/core/component/exporters/__init__.py +7 -0
  67. scadpy/core/component/exporters/map_component_to_html_file.py +47 -0
  68. scadpy/core/component/exporters/map_component_to_screen.py +63 -0
  69. scadpy/core/component/features/__init__.py +5 -0
  70. scadpy/core/component/features/get_component_bounds.py +38 -0
  71. scadpy/core/component/utils/__init__.py +9 -0
  72. scadpy/core/component/utils/blend_component_colors.py +77 -0
  73. scadpy/core/component/utils/get_intersecting_component_index_groups.py +108 -0
  74. scadpy/core/part/__init__.py +3 -0
  75. scadpy/core/part/combinations/__init__.py +11 -0
  76. scadpy/core/part/combinations/concat_parts.py +48 -0
  77. scadpy/core/part/combinations/intersect_parts.py +147 -0
  78. scadpy/core/part/combinations/subtract_parts.py +94 -0
  79. scadpy/core/part/combinations/unify_parts.py +143 -0
  80. scadpy/core/part/types/__init__.py +5 -0
  81. scadpy/core/part/types/part.py +34 -0
  82. scadpy/core/part/utils/__init__.py +5 -0
  83. scadpy/core/part/utils/blend_part_colors.py +32 -0
  84. scadpy/d2/__init__.py +2 -0
  85. scadpy/d2/shape/__init__.py +9 -0
  86. scadpy/d2/shape/combinations/__init__.py +21 -0
  87. scadpy/d2/shape/combinations/are_shape_parts_intersecting.py +49 -0
  88. scadpy/d2/shape/combinations/concat_shape.py +48 -0
  89. scadpy/d2/shape/combinations/exclude_shape.py +71 -0
  90. scadpy/d2/shape/combinations/intersect_shape.py +64 -0
  91. scadpy/d2/shape/combinations/intersect_shape_parts.py +71 -0
  92. scadpy/d2/shape/combinations/subtract_shape.py +72 -0
  93. scadpy/d2/shape/combinations/subtract_shape_parts.py +66 -0
  94. scadpy/d2/shape/combinations/unify_shape.py +51 -0
  95. scadpy/d2/shape/combinations/unify_shape_parts.py +74 -0
  96. scadpy/d2/shape/exporters/__init__.py +17 -0
  97. scadpy/d2/shape/exporters/map_shape_to_dxf.py +43 -0
  98. scadpy/d2/shape/exporters/map_shape_to_dxf_file.py +38 -0
  99. scadpy/d2/shape/exporters/map_shape_to_html.py +117 -0
  100. scadpy/d2/shape/exporters/map_shape_to_html_file.py +58 -0
  101. scadpy/d2/shape/exporters/map_shape_to_screen.py +51 -0
  102. scadpy/d2/shape/exporters/map_shape_to_svg.py +40 -0
  103. scadpy/d2/shape/exporters/map_shape_to_svg_file.py +38 -0
  104. scadpy/d2/shape/features/__init__.py +9 -0
  105. scadpy/d2/shape/features/get_shape_bounds.py +40 -0
  106. scadpy/d2/shape/features/get_shape_part_bounds.py +37 -0
  107. scadpy/d2/shape/features/is_shape_empty.py +38 -0
  108. scadpy/d2/shape/importers/__init__.py +13 -0
  109. scadpy/d2/shape/importers/map_dxf_to_shape.py +55 -0
  110. scadpy/d2/shape/importers/map_geometries_to_shape.py +45 -0
  111. scadpy/d2/shape/importers/map_geometry_to_shape.py +43 -0
  112. scadpy/d2/shape/importers/map_parts_to_shape.py +62 -0
  113. scadpy/d2/shape/importers/map_svg_to_shape.py +55 -0
  114. scadpy/d2/shape/primitives/__init__.py +6 -0
  115. scadpy/d2/shape/primitives/circle.py +68 -0
  116. scadpy/d2/shape/primitives/polygon.py +86 -0
  117. scadpy/d2/shape/primitives/rectangle.py +85 -0
  118. scadpy/d2/shape/primitives/square.py +57 -0
  119. scadpy/d2/shape/topologies/__init__.py +53 -0
  120. scadpy/d2/shape/topologies/corner/__init__.py +15 -0
  121. scadpy/d2/shape/topologies/corner/are_shape_corners_convex.py +75 -0
  122. scadpy/d2/shape/topologies/corner/get_shape_corner_angles.py +58 -0
  123. scadpy/d2/shape/topologies/corner/get_shape_corner_normals.py +82 -0
  124. scadpy/d2/shape/topologies/corner/get_shape_corner_to_incoming_directed_edge.py +39 -0
  125. scadpy/d2/shape/topologies/corner/get_shape_corner_to_outgoing_directed_edge.py +39 -0
  126. scadpy/d2/shape/topologies/corner/get_shape_corner_to_vertex.py +65 -0
  127. scadpy/d2/shape/topologies/directed_edge/__init__.py +11 -0
  128. scadpy/d2/shape/topologies/directed_edge/get_shape_directed_edge_directions.py +44 -0
  129. scadpy/d2/shape/topologies/directed_edge/get_shape_directed_edge_to_corner.py +41 -0
  130. scadpy/d2/shape/topologies/directed_edge/get_shape_directed_edge_to_edge.py +51 -0
  131. scadpy/d2/shape/topologies/directed_edge/get_shape_directed_edge_to_vertex.py +63 -0
  132. scadpy/d2/shape/topologies/edge/__init__.py +11 -0
  133. scadpy/d2/shape/topologies/edge/get_shape_edge_lengths.py +43 -0
  134. scadpy/d2/shape/topologies/edge/get_shape_edge_midpoints.py +46 -0
  135. scadpy/d2/shape/topologies/edge/get_shape_edge_normals.py +40 -0
  136. scadpy/d2/shape/topologies/edge/get_shape_edge_to_vertex.py +71 -0
  137. scadpy/d2/shape/topologies/ring/__init__.py +7 -0
  138. scadpy/d2/shape/topologies/ring/get_shape_ring_to_part.py +46 -0
  139. scadpy/d2/shape/topologies/ring/get_shape_ring_types.py +46 -0
  140. scadpy/d2/shape/topologies/vertex/__init__.py +11 -0
  141. scadpy/d2/shape/topologies/vertex/get_shape_part_vertex_coordinates.py +62 -0
  142. scadpy/d2/shape/topologies/vertex/get_shape_vertex_coordinates.py +44 -0
  143. scadpy/d2/shape/topologies/vertex/get_shape_vertex_to_part.py +42 -0
  144. scadpy/d2/shape/topologies/vertex/get_shape_vertex_to_ring.py +63 -0
  145. scadpy/d2/shape/transformations/__init__.py +43 -0
  146. scadpy/d2/shape/transformations/chamfer_shape.py +259 -0
  147. scadpy/d2/shape/transformations/color_shape.py +46 -0
  148. scadpy/d2/shape/transformations/convexify_shape.py +79 -0
  149. scadpy/d2/shape/transformations/fill_shape.py +68 -0
  150. scadpy/d2/shape/transformations/fillet_shape.py +289 -0
  151. scadpy/d2/shape/transformations/grow_shape.py +82 -0
  152. scadpy/d2/shape/transformations/linear_cut_shape.py +116 -0
  153. scadpy/d2/shape/transformations/linear_extrude_shape.py +60 -0
  154. scadpy/d2/shape/transformations/linear_slice_shape.py +144 -0
  155. scadpy/d2/shape/transformations/mirror_shape.py +53 -0
  156. scadpy/d2/shape/transformations/pull_shape.py +67 -0
  157. scadpy/d2/shape/transformations/push_shape.py +67 -0
  158. scadpy/d2/shape/transformations/radial_extrude_shape.py +285 -0
  159. scadpy/d2/shape/transformations/radial_slice_shape.py +132 -0
  160. scadpy/d2/shape/transformations/recoordinate_shape.py +82 -0
  161. scadpy/d2/shape/transformations/resize_shape.py +91 -0
  162. scadpy/d2/shape/transformations/rotate_shape.py +63 -0
  163. scadpy/d2/shape/transformations/scale_shape.py +58 -0
  164. scadpy/d2/shape/transformations/shrink_shape.py +69 -0
  165. scadpy/d2/shape/transformations/translate_shape.py +54 -0
  166. scadpy/d2/shape/types/__init__.py +3 -0
  167. scadpy/d2/shape/types/shape.py +792 -0
  168. scadpy/d2/shape/types/utils/__init__.py +5 -0
  169. scadpy/d2/shape/types/utils/shapely_base_geometry_to_shapely_polygons.py +25 -0
  170. scadpy/d2/shape/utils/__init__.py +5 -0
  171. scadpy/d2/shape/utils/shapely_base_geometry_to_shapely_polygons.py +55 -0
  172. scadpy/d2/utils/__init__.py +3 -0
  173. scadpy/d2/utils/resolve_vector_2d.py +50 -0
  174. scadpy/d3/__init__.py +2 -0
  175. scadpy/d3/solid/__init__.py +8 -0
  176. scadpy/d3/solid/combinations/__init__.py +21 -0
  177. scadpy/d3/solid/combinations/are_solid_parts_intersecting.py +51 -0
  178. scadpy/d3/solid/combinations/concat_solid.py +48 -0
  179. scadpy/d3/solid/combinations/exclude_solid.py +71 -0
  180. scadpy/d3/solid/combinations/intersect_solid.py +64 -0
  181. scadpy/d3/solid/combinations/intersect_solid_parts.py +73 -0
  182. scadpy/d3/solid/combinations/subtract_solid.py +72 -0
  183. scadpy/d3/solid/combinations/subtract_solid_parts.py +68 -0
  184. scadpy/d3/solid/combinations/unify_solid.py +51 -0
  185. scadpy/d3/solid/combinations/unify_solid_parts.py +73 -0
  186. scadpy/d3/solid/exporters/__init__.py +11 -0
  187. scadpy/d3/solid/exporters/map_solid_to_html.py +318 -0
  188. scadpy/d3/solid/exporters/map_solid_to_html_file.py +58 -0
  189. scadpy/d3/solid/exporters/map_solid_to_screen.py +51 -0
  190. scadpy/d3/solid/exporters/map_solid_to_stl_file.py +48 -0
  191. scadpy/d3/solid/features/__init__.py +11 -0
  192. scadpy/d3/solid/features/get_solid_bounds.py +37 -0
  193. scadpy/d3/solid/features/get_solid_part_bounds.py +37 -0
  194. scadpy/d3/solid/features/get_solid_part_colors.py +39 -0
  195. scadpy/d3/solid/features/is_solid_empty.py +36 -0
  196. scadpy/d3/solid/importers/__init__.py +11 -0
  197. scadpy/d3/solid/importers/map_geometries_to_solid.py +42 -0
  198. scadpy/d3/solid/importers/map_geometry_to_solid.py +42 -0
  199. scadpy/d3/solid/importers/map_parts_to_solid.py +66 -0
  200. scadpy/d3/solid/importers/map_stl_to_solid.py +37 -0
  201. scadpy/d3/solid/primitives/__init__.py +7 -0
  202. scadpy/d3/solid/primitives/cone.py +70 -0
  203. scadpy/d3/solid/primitives/cuboid.py +75 -0
  204. scadpy/d3/solid/primitives/cylinder.py +73 -0
  205. scadpy/d3/solid/primitives/polyhedron.py +60 -0
  206. scadpy/d3/solid/primitives/sphere.py +58 -0
  207. scadpy/d3/solid/topologies/__init__.py +8 -0
  208. scadpy/d3/solid/topologies/triangle/__init__.py +5 -0
  209. scadpy/d3/solid/topologies/triangle/get_solid_triangle_to_vertex.py +49 -0
  210. scadpy/d3/solid/topologies/vertex/__init__.py +7 -0
  211. scadpy/d3/solid/topologies/vertex/get_solid_vertex_coordinates.py +39 -0
  212. scadpy/d3/solid/topologies/vertex/get_solid_vertex_to_part.py +37 -0
  213. scadpy/d3/solid/transformations/__init__.py +23 -0
  214. scadpy/d3/solid/transformations/color_solid.py +46 -0
  215. scadpy/d3/solid/transformations/convexify_solid.py +64 -0
  216. scadpy/d3/solid/transformations/mirror_solid.py +53 -0
  217. scadpy/d3/solid/transformations/pull_solid.py +67 -0
  218. scadpy/d3/solid/transformations/push_solid.py +67 -0
  219. scadpy/d3/solid/transformations/recoordinate_solid.py +68 -0
  220. scadpy/d3/solid/transformations/resize_solid.py +92 -0
  221. scadpy/d3/solid/transformations/rotate_solid.py +93 -0
  222. scadpy/d3/solid/transformations/scale_solid.py +58 -0
  223. scadpy/d3/solid/transformations/translate_solid.py +54 -0
  224. scadpy/d3/solid/types/__init__.py +3 -0
  225. scadpy/d3/solid/types/solid.py +448 -0
  226. scadpy/d3/utils/__init__.py +3 -0
  227. scadpy/d3/utils/resolve_vector_3d.py +50 -0
  228. scadpy/utils/__init__.py +6 -0
  229. scadpy/utils/resolve_vector.py +64 -0
  230. scadpy/utils/x.py +38 -0
  231. scadpy/utils/y.py +38 -0
  232. scadpy/utils/z.py +38 -0
  233. scadpy-0.1.0.dist-info/METADATA +282 -0
  234. scadpy-0.1.0.dist-info/RECORD +236 -0
  235. scadpy-0.1.0.dist-info/WHEEL +4 -0
  236. scadpy-0.1.0.dist-info/licenses/LICENSE.md +43 -0
@@ -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.d2.shape import Shape
11
+
12
+
13
+ @typechecked
14
+ def get_shape_edge_normals(
15
+ shape: Shape,
16
+ ) -> NDArray[np.float64]:
17
+ """
18
+ For each edge in the shape, return its outward unit normal.
19
+
20
+ See :func:`get_assembly_edge_normals` for full documentation.
21
+
22
+ Examples
23
+ --------
24
+ >>> from scadpy import get_shape_edge_normals, square
25
+
26
+ >>> # square(2) centered at origin: 4 edges,
27
+ >>> # each normal points outward
28
+ >>> square_shape = square(2)
29
+ >>> get_shape_edge_normals(square_shape).round(4)
30
+ array([[ 0., -1.],
31
+ [ 1., -0.],
32
+ [ 0., 1.],
33
+ [-1., -0.]])
34
+ """
35
+ from scadpy.core.assembly import get_assembly_edge_normals
36
+
37
+ return get_assembly_edge_normals(
38
+ edge_to_vertex=shape.edge_to_vertex,
39
+ vertex_coordinates=shape.vertex_coordinates,
40
+ )
@@ -0,0 +1,71 @@
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.d2.shape import Shape
11
+
12
+
13
+ @typechecked
14
+ def get_shape_edge_to_vertex(
15
+ shape: Shape,
16
+ ) -> NDArray[np.int64]:
17
+ """
18
+ For each edge in the shape, return the indices of its start and end vertices.
19
+
20
+ An edge connects two consecutive vertices within a ring. Edges are directed
21
+ implicitly by the ring winding order (CCW for exterior rings, CW for interior
22
+ rings in Shapely convention).
23
+
24
+ Parameters
25
+ ----------
26
+ shape : Shape
27
+ The shape to extract edge-to-vertex indices from.
28
+
29
+ Returns
30
+ -------
31
+ NDArray[np.int64]
32
+ 2D array of shape ``(n_edges, 2)``. Each row is ``[start_vertex, end_vertex]``.
33
+ The number of edges equals the number of vertices (one edge per vertex,
34
+ since each ring is closed).
35
+
36
+ Examples
37
+ --------
38
+ >>> from scadpy import get_shape_edge_to_vertex, polygon, square
39
+
40
+ >>> # triangle: 3 vertices, 3 edges
41
+ >>> triangle = polygon([(0, 0), (1, 0), (0.5, 1)])
42
+ >>> get_shape_edge_to_vertex(triangle)
43
+ array([[0, 1],
44
+ [1, 2],
45
+ [2, 0]])
46
+
47
+ >>> # square: 4 vertices, 4 edges
48
+ >>> square_shape = square(1)
49
+ >>> get_shape_edge_to_vertex(square_shape).shape
50
+ (4, 2)
51
+ """
52
+ rings = [
53
+ ring
54
+ for g in map(lambda p: p.geometry, shape._parts) # pyright: ignore[reportPrivateUsage]
55
+ for ring in (g.exterior, *g.interiors)
56
+ ]
57
+ if not rings:
58
+ return np.empty((0, 2), dtype=np.int64)
59
+
60
+ # Build edge_to_vertex: for each ring, consecutive vertex pairs (wrapping around)
61
+ edge_rows: list[NDArray[np.int64]] = []
62
+ offset = 0
63
+ for ring in rings:
64
+ n = len(ring.coords) - 1 # exclude closing duplicate
65
+ local_indices = np.arange(n, dtype=np.int64)
66
+ starts = offset + local_indices
67
+ ends = offset + (local_indices + 1) % n
68
+ edge_rows.append(np.stack([starts, ends], axis=1))
69
+ offset += n
70
+
71
+ return np.concatenate(edge_rows, axis=0)
@@ -0,0 +1,7 @@
1
+ __all__ = [
2
+ "get_shape_ring_to_part",
3
+ "get_shape_ring_types",
4
+ ]
5
+
6
+ from .get_shape_ring_to_part import get_shape_ring_to_part
7
+ from .get_shape_ring_types import get_shape_ring_types
@@ -0,0 +1,46 @@
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.d2.shape import Shape
11
+
12
+
13
+ @typechecked
14
+ def get_shape_ring_to_part(
15
+ shape: Shape,
16
+ ) -> NDArray[np.int64]:
17
+ """
18
+ For each ring in the shape, return its part index
19
+
20
+ Parameters
21
+ ----------
22
+ shape : Shape
23
+ The shape to extract ring part indices from.
24
+
25
+ Returns
26
+ -------
27
+ NDArray[np.float64]
28
+ 1D array of shape (n_rings,), one element per ring.
29
+
30
+ Examples
31
+ --------
32
+ >>> from scadpy import get_shape_ring_to_part, square
33
+
34
+ >>> # square with a hole (2 rings in part 0)
35
+ >>> # unioned with a separate square (1 ring in part 1)
36
+ >>> shape = (square(2) - square(1)) | square(1).translate([5, 0])
37
+ >>> result = get_shape_ring_to_part(shape)
38
+ >>> result # doctest: +NORMALIZE_WHITESPACE
39
+ array([0, 0, 1])
40
+ """
41
+ part_indices = [
42
+ i
43
+ for i, p in enumerate(shape._parts) # pyright: ignore[reportPrivateUsage]
44
+ for _ in range(1 + len(p.geometry.interiors))
45
+ ]
46
+ return np.array(part_indices, dtype=np.int64)
@@ -0,0 +1,46 @@
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.d2.shape import Shape
11
+
12
+
13
+ @typechecked
14
+ def get_shape_ring_types(
15
+ shape: Shape,
16
+ ) -> NDArray[np.object_]:
17
+ """
18
+ For each ring in the shape, return its type ('exterior' or 'interior').
19
+
20
+ Parameters
21
+ ----------
22
+ shape : Shape
23
+ The shape to extract ring types from.
24
+
25
+ Returns
26
+ -------
27
+ NDArray[np.object_]
28
+ 1D array of shape (n_rings,), one element per ring.
29
+
30
+ Examples
31
+ --------
32
+ >>> from scadpy import get_shape_ring_types, square
33
+
34
+ >>> # square with a hole (exterior + interior)
35
+ >>> # unioned with a separate square (exterior only)
36
+ >>> shape = (square(2) - square(1)) | square(1).translate([5, 0])
37
+ >>> get_shape_ring_types(shape) # doctest: +NORMALIZE_WHITESPACE
38
+ array(['exterior', 'interior', 'exterior'], dtype=object)
39
+ """
40
+ # extract and flatmap polygon ring types
41
+ ring_types = [
42
+ ring_type
43
+ for g in [p.geometry for p in shape._parts] # pyright: ignore[reportPrivateUsage]
44
+ for ring_type in ["exterior"] + ["interior"] * len(g.interiors)
45
+ ]
46
+ return np.array(ring_types, dtype=np.object_)
@@ -0,0 +1,11 @@
1
+ __all__ = [
2
+ "get_shape_part_vertex_coordinates",
3
+ "get_shape_vertex_coordinates",
4
+ "get_shape_vertex_to_part",
5
+ "get_shape_vertex_to_ring",
6
+ ]
7
+
8
+ from .get_shape_part_vertex_coordinates import get_shape_part_vertex_coordinates
9
+ from .get_shape_vertex_coordinates import get_shape_vertex_coordinates
10
+ from .get_shape_vertex_to_part import get_shape_vertex_to_part
11
+ from .get_shape_vertex_to_ring import get_shape_vertex_to_ring
@@ -0,0 +1,62 @@
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.coords import CoordinateSequence
8
+ from shapely.geometry import Polygon
9
+ from typeguard import typechecked
10
+
11
+ if TYPE_CHECKING:
12
+ from scadpy.core.part import Part
13
+
14
+
15
+ @typechecked
16
+ def get_shape_part_vertex_coordinates(part: Part[Polygon]) -> NDArray[np.float64]:
17
+ """
18
+ For each vertex in the part, return its coordinates
19
+
20
+ Parameters
21
+ ----------
22
+ part : Part[Polygon]
23
+ The shape part to extract vertex coordinates from.
24
+
25
+ Returns
26
+ -------
27
+ NDArray[np.float64]
28
+ 2D array of shape (n_vertices, 2), one row per vertex.
29
+
30
+ Examples
31
+ --------
32
+ >>> from shapely.geometry import Polygon
33
+ >>> from scadpy import Part, get_shape_part_vertex_coordinates
34
+ ...
35
+ >>> polygon = Polygon(
36
+ ... shell=[(0, 0), (4, 0), (4, 4), (0, 4), (0, 0)],
37
+ ... holes=[[(1, 1), (3, 1), (3, 3), (1, 3), (1, 1)]]
38
+ ... )
39
+ >>> get_shape_part_vertex_coordinates(
40
+ ... Part.from_geometry(polygon)
41
+ ... ) # doctest: +NORMALIZE_WHITESPACE
42
+ array([[0., 0.],
43
+ [4., 0.],
44
+ [4., 4.],
45
+ ...
46
+ [3., 1.],
47
+ [3., 3.],
48
+ [1., 3.]])
49
+ """
50
+
51
+ def remove_closing_point(coordinates: CoordinateSequence) -> NDArray[np.float64]:
52
+ array = np.array(coordinates)
53
+ if len(array) > 1 and np.allclose(array[0], array[-1]): # pyright: ignore[reportAny]
54
+ return array[:-1]
55
+ return array
56
+
57
+ geometry = part.geometry
58
+ exterior = remove_closing_point(geometry.exterior.coords)
59
+ interiors = [remove_closing_point(interior.coords) for interior in geometry.interiors]
60
+ if not interiors:
61
+ return exterior
62
+ return np.vstack([exterior] + interiors)
@@ -0,0 +1,44 @@
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_vertex_coordinates(shape: Shape) -> NDArray[np.float64]:
15
+ """
16
+ For each vertex in the shape, return its coordinates.
17
+
18
+ Parameters
19
+ ----------
20
+ shape : Shape
21
+ The shape to extract vertex coordinates from.
22
+
23
+ Returns
24
+ -------
25
+ NDArray[np.float64]
26
+ 2D array of shape (n_vertices, 2), one row per vertex.
27
+
28
+ Examples
29
+ --------
30
+ >>> from shapely.geometry import Polygon
31
+ >>> from scadpy import Shape, get_shape_vertex_coordinates
32
+
33
+ >>> polygon = Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])
34
+ >>> get_shape_vertex_coordinates(
35
+ ... Shape.from_geometry(polygon)
36
+ ... ) # doctest: +NORMALIZE_WHITESPACE
37
+ array([[0., 0.],
38
+ [2., 0.],
39
+ [2., 2.],
40
+ [0., 2.]])
41
+ """
42
+ from scadpy import get_assembly_vertex_coordinates, get_shape_part_vertex_coordinates
43
+
44
+ return get_assembly_vertex_coordinates(shape._parts, get_shape_part_vertex_coordinates, 2)
@@ -0,0 +1,42 @@
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_vertex_to_part(shape: Shape) -> NDArray[np.int64]:
15
+ """
16
+ For each vertex in the shape, return its part index.
17
+
18
+ Parameters
19
+ ----------
20
+ shape : Shape
21
+ The shape to extract part indices from.
22
+
23
+ Returns
24
+ -------
25
+ NDArray[np.int64]
26
+ 1D array of shape (n_vertices,), one element per vertex.
27
+
28
+ Examples
29
+ --------
30
+ >>> from shapely.geometry import Polygon
31
+ >>> from scadpy import Shape, get_shape_vertex_to_part
32
+
33
+ >>> p1 = Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])
34
+ >>> p2 = Polygon([(10, 10), (12, 10), (12, 12), (10, 12)])
35
+ >>> get_shape_vertex_to_part(
36
+ ... Shape.from_geometries([p1, p2])
37
+ ... ) # doctest: +NORMALIZE_WHITESPACE
38
+ array([0, 0, 0, 0, 1, 1, 1, 1])
39
+ """
40
+ from scadpy import get_assembly_vertex_to_part, get_shape_part_vertex_coordinates
41
+
42
+ return get_assembly_vertex_to_part(shape._parts, get_shape_part_vertex_coordinates)
@@ -0,0 +1,63 @@
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.d2.shape import Shape
11
+
12
+
13
+ @typechecked
14
+ def get_shape_vertex_to_ring(
15
+ shape: Shape,
16
+ ) -> NDArray[np.int64]:
17
+ """
18
+ For each vertex in the shape, return the index of the ring (exterior or interior) it belongs to.
19
+
20
+ Parameters
21
+ ----------
22
+ shape : Shape
23
+ The shape to extract vertex ring indices from.
24
+
25
+ Returns
26
+ -------
27
+ NDArray[np.float64]
28
+ 1D array of shape (n_vertices,), one element per vertex.
29
+
30
+ Examples
31
+ --------
32
+ >>> from scadpy import get_shape_vertex_to_ring, polygon, square
33
+
34
+ >>> # two separate triangles: 3 vertices in ring 0, 3 in ring 1
35
+ >>> shape = (
36
+ ... polygon([(0, 0), (1, 0), (0.5, 1)])
37
+ ... | polygon([(5, 0), (6, 0), (5.5, 1)])
38
+ ... )
39
+ >>> result = get_shape_vertex_to_ring(shape)
40
+ >>> result # doctest: +NORMALIZE_WHITESPACE
41
+ array([0, 0, 0, 1, 1, 1])
42
+
43
+ >>> # square with a hole: 4 exterior vertices in ring 0,
44
+ >>> # 4 interior vertices in ring 1
45
+ >>> shape = square(4) - square(2)
46
+ >>> result = get_shape_vertex_to_ring(shape)
47
+ >>> result # doctest: +NORMALIZE_WHITESPACE
48
+ array([0, 0, 0, 0, 1, 1, 1, 1])
49
+ """
50
+ # extract and flatmap polygon rings
51
+ rings = [
52
+ ring
53
+ for g in map(lambda p: p.geometry, shape._parts) # pyright: ignore[reportPrivateUsage]
54
+ for ring in (g.exterior, *g.interiors)
55
+ ]
56
+ # no ring found
57
+ if not rings:
58
+ return np.array([], dtype=np.int64)
59
+
60
+ ring_indices = np.concatenate(
61
+ [np.full(len(ring.coords) - 1, i, dtype=np.int64) for i, ring in enumerate(rings)]
62
+ )
63
+ return np.array(ring_indices, dtype=np.int64)
@@ -0,0 +1,43 @@
1
+ __all__ = [
2
+ "chamfer_shape",
3
+ "color_shape",
4
+ "convexify_shape",
5
+ "fill_shape",
6
+ "fillet_shape",
7
+ "grow_shape",
8
+ "linear_cut_shape",
9
+ "linear_extrude_shape",
10
+ "linear_slice_shape",
11
+ "mirror_shape",
12
+ "pull_shape",
13
+ "push_shape",
14
+ "radial_extrude_shape",
15
+ "radial_slice_shape",
16
+ "recoordinate_shape",
17
+ "resize_shape",
18
+ "rotate_shape",
19
+ "scale_shape",
20
+ "shrink_shape",
21
+ "translate_shape",
22
+ ]
23
+
24
+ from .chamfer_shape import chamfer_shape
25
+ from .color_shape import color_shape
26
+ from .convexify_shape import convexify_shape
27
+ from .fill_shape import fill_shape
28
+ from .fillet_shape import fillet_shape
29
+ from .grow_shape import grow_shape
30
+ from .linear_cut_shape import linear_cut_shape
31
+ from .linear_extrude_shape import linear_extrude_shape
32
+ from .linear_slice_shape import linear_slice_shape
33
+ from .mirror_shape import mirror_shape
34
+ from .pull_shape import pull_shape
35
+ from .push_shape import push_shape
36
+ from .radial_extrude_shape import radial_extrude_shape
37
+ from .radial_slice_shape import radial_slice_shape
38
+ from .recoordinate_shape import recoordinate_shape
39
+ from .resize_shape import resize_shape
40
+ from .rotate_shape import rotate_shape
41
+ from .scale_shape import scale_shape
42
+ from .shrink_shape import shrink_shape
43
+ from .translate_shape import translate_shape