@thi.ng/geom 6.1.8 → 7.0.0

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 (83) hide show
  1. package/CHANGELOG.md +108 -1
  2. package/README.md +33 -28
  3. package/api/arc.js +1 -1
  4. package/api/complex-polygon.d.ts +14 -0
  5. package/api/complex-polygon.js +44 -0
  6. package/api/path.d.ts +11 -3
  7. package/api/path.js +45 -29
  8. package/apply-transforms.js +5 -10
  9. package/arc-length.d.ts +1 -0
  10. package/arc-length.js +12 -0
  11. package/area.d.ts +1 -0
  12. package/area.js +4 -1
  13. package/as-cubic.d.ts +2 -0
  14. package/as-cubic.js +10 -2
  15. package/as-path.d.ts +19 -3
  16. package/as-path.js +54 -1
  17. package/as-polygon.d.ts +7 -5
  18. package/as-polygon.js +14 -1
  19. package/as-polyline.d.ts +6 -4
  20. package/as-polyline.js +19 -5
  21. package/bounds.js +14 -7
  22. package/centroid.d.ts +3 -2
  23. package/centroid.js +10 -1
  24. package/classify-point.d.ts +5 -2
  25. package/clip-convex.d.ts +22 -3
  26. package/clip-convex.js +39 -12
  27. package/closest-point.d.ts +2 -0
  28. package/closest-point.js +34 -0
  29. package/complex-polygon-from-path.d.ts +14 -0
  30. package/complex-polygon-from-path.js +9 -0
  31. package/complex-polygon.d.ts +23 -0
  32. package/complex-polygon.js +6 -0
  33. package/convex-hull.d.ts +1 -0
  34. package/convex-hull.js +2 -0
  35. package/edges.d.ts +2 -0
  36. package/edges.js +7 -3
  37. package/fit-into-bounds.js +5 -10
  38. package/flip.d.ts +1 -0
  39. package/flip.js +5 -0
  40. package/index.d.ts +5 -0
  41. package/index.js +5 -0
  42. package/internal/bounds.js +3 -6
  43. package/internal/copy.d.ts +3 -1
  44. package/internal/copy.js +9 -3
  45. package/internal/transform.d.ts +20 -7
  46. package/internal/transform.js +10 -0
  47. package/intersects.js +3 -6
  48. package/package.json +48 -33
  49. package/path-builder.d.ts +21 -1
  50. package/path-builder.js +31 -14
  51. package/path-from-svg.d.ts +13 -1
  52. package/path-from-svg.js +10 -14
  53. package/path.d.ts +59 -2
  54. package/path.js +44 -19
  55. package/point-inside.d.ts +12 -9
  56. package/point-inside.js +3 -0
  57. package/proximity.d.ts +11 -0
  58. package/proximity.js +9 -0
  59. package/resample.d.ts +1 -0
  60. package/resample.js +7 -1
  61. package/rotate.d.ts +1 -0
  62. package/rotate.js +13 -10
  63. package/scale-with-center.d.ts +20 -0
  64. package/scale-with-center.js +7 -0
  65. package/scale.d.ts +1 -0
  66. package/scale.js +12 -9
  67. package/scatter.js +1 -2
  68. package/simplify.d.ts +4 -3
  69. package/simplify.js +39 -27
  70. package/split-arclength.d.ts +1 -1
  71. package/split-arclength.js +4 -6
  72. package/subdiv-curve.d.ts +5 -1
  73. package/subdiv-curve.js +10 -8
  74. package/transform-vertices.d.ts +1 -0
  75. package/transform-vertices.js +19 -19
  76. package/transform.d.ts +1 -0
  77. package/transform.js +17 -16
  78. package/translate.d.ts +1 -0
  79. package/translate.js +17 -12
  80. package/vertices.d.ts +18 -17
  81. package/vertices.js +22 -11
  82. package/with-attribs.d.ts +1 -1
  83. package/with-attribs.js +1 -1
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2024-04-23T07:02:18Z
3
+ - **Last updated**: 2024-05-08T18:24:31Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
@@ -9,6 +9,113 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
9
9
  **Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
10
10
  and/or version bumps of transitive dependencies.
11
11
 
12
+ # [7.0.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/geom@7.0.0) (2024-05-08)
13
+
14
+ #### 🛑 Breaking changes
15
+
16
+ - update Path to support sub-paths (holes), update impls ([#464](https://github.com/thi-ng/umbrella/issues/464)) ([9329d27](https://github.com/thi-ng/umbrella/commit/9329d27))
17
+ - BREAKING CHANGE: update path related ctors & functions
18
+ - add `subPaths` argument for Path ctor/factory fn
19
+ - rename `Path.add()` => `Path.addSegments()`
20
+ - add `Path.addSubPaths()`
21
+ - update `Path.toHiccup()` to include sub-paths
22
+ - update `pathFromSvg()` to always return a single path only
23
+ - sub-paths are included in main path now
24
+ - update impls for following ops to also process sub-paths:
25
+ - bounds()
26
+ - rotate()
27
+ - scale()
28
+ - simplify()
29
+ - translate()
30
+ - transform()
31
+ - transformVertices()
32
+ - update asPolyline(), add support for multiple boundaries ([#464](https://github.com/thi-ng/umbrella/issues/464)) ([0616b96](https://github.com/thi-ng/umbrella/commit/0616b96))
33
+ - BREAKING CHANGE: update asPolygon() to return array of polylines
34
+ - add/update impls for complexpoly & path to produce multiple results
35
+ - update other internal callsites
36
+ - update tests
37
+ - update `Path` closing logic ([ce3a922](https://github.com/thi-ng/umbrella/commit/ce3a922))
38
+ - BREAKING CHANGE: update `Path` closing logic, `Path.closed` now a readonly property
39
+ - add `Path.closed()` getter
40
+ - add `Path.close()` to add a `Z`-type segment, check if not closed already
41
+ - update `Path.addSegments()` to check each segment, throw error if path already closed
42
+ - refactor `PathBuilder.closePath()`
43
+ - add asPolygon() support for complexpoly & path ([e3c9f20](https://github.com/thi-ng/umbrella/commit/e3c9f20))
44
+ - BREAKING CHANGE: update asPolygon() to return array of polygons (rather than single only)
45
+ - add support for complexpoly & path (incl. sub-shapes, holes)
46
+ - refactor internal call sites
47
+ - update asPath(), add AsPathOpts ([ef0ebdf](https://github.com/thi-ng/umbrella/commit/ef0ebdf))
48
+ - BREAKING CHANGE: update asPath() args, add AsPathOpts as 2nd arg
49
+ - add option for using only linear path segments (no cubics)
50
+ - update impls for complexpoly & other polygon types
51
+ - update Path & PathBuilder.close() ([b2134c2](https://github.com/thi-ng/umbrella/commit/b2134c2))
52
+ - BREAKING CHANGE: rename `PathBuilder.closePath()` => `PathBuilder.close()`
53
+ - update `Path.close()` to return path itself
54
+ - rewrite roundedRect() to allow individual corner radii ([a4817aa](https://github.com/thi-ng/umbrella/commit/a4817aa))
55
+ - BREAKING CHANGE: update roundedRect() radius handling to allow individual corner radii
56
+ - update docs
57
+ - add tests
58
+
59
+ #### 🚀 Features
60
+
61
+ - initial import ComplexPolygon & impls ([#464](https://github.com/thi-ng/umbrella/issues/464)) ([ded007c](https://github.com/thi-ng/umbrella/commit/ded007c))
62
+ - add complexPolygon() factory fn
63
+ - add bounds() & centroid() impls
64
+ - add ops for complex polygons ([#464](https://github.com/thi-ng/umbrella/issues/464)) ([35ce854](https://github.com/thi-ng/umbrella/commit/35ce854))
65
+ - add implementations for:
66
+ - arcLength()
67
+ - area()
68
+ - asPath()
69
+ - closestPoint()
70
+ - convexHull()
71
+ - edges()
72
+ - flip()
73
+ - pointInside()
74
+ - resample()
75
+ - rotate()
76
+ - scale()
77
+ - simplify()
78
+ - subdivCurve()
79
+ - transform()
80
+ - transformVertices()
81
+ - translate()
82
+ - vertices()
83
+ - add tests
84
+ - add proximity() ([5d5951c](https://github.com/thi-ng/umbrella/commit/5d5951c))
85
+ - update `vertices()` impl for `Path`, incl. sub-path vertices ([824067f](https://github.com/thi-ng/umbrella/commit/824067f))
86
+ - update simplify() default threshold ([bdba298](https://github.com/thi-ng/umbrella/commit/bdba298))
87
+ - add arcLength() for Path, refactor complexpoly impl ([d133bbe](https://github.com/thi-ng/umbrella/commit/d133bbe))
88
+ - add/update asCubic() impls for complex poly & path ([7f9e927](https://github.com/thi-ng/umbrella/commit/7f9e927))
89
+ - update pathFromCubics() to auto-create sub-paths if needed ([1170e45](https://github.com/thi-ng/umbrella/commit/1170e45))
90
+ - add closestPoint() impl for Path ([f0cf2f1](https://github.com/thi-ng/umbrella/commit/f0cf2f1))
91
+ - add pointInside() impl for Polyline ([d10bf43](https://github.com/thi-ng/umbrella/commit/d10bf43))
92
+ - add centroid() & convexHull() impl for Path ([76aa229](https://github.com/thi-ng/umbrella/commit/76aa229))
93
+ - add complexPolygonFromPath() ([cd526f1](https://github.com/thi-ng/umbrella/commit/cd526f1))
94
+ - update PathBuilder.close(), fix attrib handling ([e68d0bc](https://github.com/thi-ng/umbrella/commit/e68d0bc))
95
+ - only insert closing line segment if needed
96
+ - copy attribs for each new path
97
+ - add docs
98
+ - add opt attribs for `pathFromSvg()` ([2da31f6](https://github.com/thi-ng/umbrella/commit/2da31f6))
99
+ - update docs
100
+ - add/update tests
101
+ - add scaleWithCenter() ([e328494](https://github.com/thi-ng/umbrella/commit/e328494))
102
+ - add complexpoly & path support for `clipConvex()` ([7665dc1](https://github.com/thi-ng/umbrella/commit/7665dc1))
103
+
104
+ #### 🩹 Bug fixes
105
+
106
+ - update vertices() ([2afc05e](https://github.com/thi-ng/umbrella/commit/2afc05e))
107
+ - update impl for points, poly, polyline to return shallow copy of point array if no opts given
108
+
109
+ #### ♻️ Refactoring
110
+
111
+ - update withAttribs(), make new attribs optional ([688e1bf](https://github.com/thi-ng/umbrella/commit/688e1bf))
112
+ - update geom examples (recent API changes) ([f0f5ea7](https://github.com/thi-ng/umbrella/commit/f0f5ea7))
113
+ - update area() impl for Path ([0960817](https://github.com/thi-ng/umbrella/commit/0960817))
114
+ - update/simplify asPath() impls ([cbc71bb](https://github.com/thi-ng/umbrella/commit/cbc71bb))
115
+ - update centroid() for complexpoly ([58ac296](https://github.com/thi-ng/umbrella/commit/58ac296))
116
+ - re-use migrated fn from [@thi.ng/geom-poly-utils](https://github.com/thi-ng/umbrella/tree/main/packages/geom-poly-utils)
117
+ - update path segment transformations ([88b2c40](https://github.com/thi-ng/umbrella/commit/88b2c40))
118
+
12
119
  ### [6.1.7](https://github.com/thi-ng/umbrella/tree/@thi.ng/geom@6.1.7) (2024-04-20)
13
120
 
14
121
  #### ♻️ Refactoring
package/README.md CHANGED
@@ -44,28 +44,29 @@ name](http://thi.ng/geom-clj). All polymorphic operations built on
44
44
  The following shape primitives are provided. For many there're multiple ways to
45
45
  create them, please check linked sources and/or docs.
46
46
 
47
- | Shape/Form | Description | Hiccup support |
48
- |-------------------------------------------------------------------------------------------------------|------------------------------|-----------------|
49
- | [AABB](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/aabb.ts) | 3D Axis-aligned bounding box | ✅<sup>(2)</sup> |
50
- | [Arc](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/arc.ts) | 2D elliptic arc | ✅ |
51
- | [Circle](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/circle.ts) | 2D circle | ✅ |
52
- | [Cubic](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/cubic.ts) | nD cubic bezier | ✅<sup>(1)</sup> |
53
- | [Ellipse](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/ellipse.ts) | 2D ellipse | |
54
- | [Group](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/group.ts) | group of 2D shapes | ✅ |
55
- | [Line](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/line.ts) | 2D line segment | ✅ |
56
- | [Path](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/path-builder.ts) | 2D path | ✅ |
57
- | [Path (from SVG)](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/path-from-svg.ts) | 2D path from SVG `<path>` | ✅ |
58
- | [Plane](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/plane.ts) | 3D plane | ✅<sup>(2)</sup> |
59
- | [Point cloud](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/points.ts) | nD point cloud | ✅<sup>(1)</sup> |
60
- | [Polygon](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/polygon.ts) | 2D simple polygon (no holes) | ✅ |
61
- | [Polyline](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/polyline.ts) | 2D polyline | ✅ |
62
- | [Quad](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/quad.ts) | 2D/3D quad (4-gon) | ✅<sup>(1)</sup> |
63
- | [Quadratic](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/quadratic.ts) | nD quadratic bezier | ✅<sup>(1)</sup> |
64
- | [Ray](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/ray.ts) | nD ray | ✅<sup>(1)</sup> |
65
- | [Rectangle](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/rect.ts) | 2D rectangle | |
66
- | [Sphere](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/sphere.ts) | 3D sphere | ✅<sup>(2)</sup> |
67
- | [Text](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/text.ts) | Basic stub for text labels | ✅<sup>(3)</sup> |
68
- | [Triangle](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/triangle.ts) | 2D triangle | |
47
+ | Shape/Form | Description | Hiccup support |
48
+ |--------------------------------------------------------------------------------------------------------|---------------------------------------|-----------------|
49
+ | [AABB](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/aabb.ts) | 3D Axis-aligned bounding box | ✅<sup>(2)</sup> |
50
+ | [Arc](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/arc.ts) | 2D elliptic arc | ✅ |
51
+ | [Circle](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/circle.ts) | 2D circle | ✅ |
52
+ | [ComplexPolygon](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/complex-polygon.ts) | 2D polygon w/ holes | |
53
+ | [Cubic](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/cubic.ts) | nD cubic bezier | ✅<sup>(1)</sup> |
54
+ | [Ellipse](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/ellipse.ts) | 2D ellipse | ✅ |
55
+ | [Group](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/group.ts) | group of 2D shapes | ✅ |
56
+ | [Line](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/line.ts) | 2D line segment | ✅ |
57
+ | [Path](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/path-builder.ts) | 2D path (w/ optional holes/sub-paths) | ✅ |
58
+ | [Path (from SVG)](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/path-from-svg.ts) | 2D path from SVG | ✅ |
59
+ | [Plane](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/plane.ts) | 3D plane | ✅<sup>(2)</sup> |
60
+ | [Point cloud](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/points.ts) | nD point cloud | ✅<sup>(1)</sup> |
61
+ | [Polygon](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/polygon.ts) | 2D simple polygon (no holes) | ✅ |
62
+ | [Polyline](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/polyline.ts) | 2D polyline | |
63
+ | [Quad](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/quad.ts) | 2D/3D quad (4-gon) | ✅<sup>(1)</sup> |
64
+ | [Quadratic](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/quadratic.ts) | nD quadratic bezier | ✅<sup>(1)</sup> |
65
+ | [Ray](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/ray.ts) | nD ray | ✅<sup>(1)</sup> |
66
+ | [Rectangle](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/rect.ts) | 2D rectangle | |
67
+ | [Sphere](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/sphere.ts) | 3D sphere | ✅<sup>(2)</sup> |
68
+ | [Text](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/text.ts) | Basic stub for text labels | ✅<sup>(3)</sup> |
69
+ | [Triangle](https://github.com/thi-ng/umbrella/blob/develop/packages/geom/src/triangle.ts) | 2D triangle | ✅ |
69
70
 
70
71
  - <sup>(1)</sup> valid hiccup format, currently only useable/supported if 2D geometry
71
72
  - <sup>(2)</sup> valid hiccup format, currently unused/unsupported elsewhere
@@ -77,9 +78,10 @@ With very few exceptions these all are implementing the [`IToHiccup`
77
78
  interface](https://docs.thi.ng/umbrella/api/interfaces/IToHiccup.html) and so
78
79
  can be easily converted (via
79
80
  [hiccup](https://github.com/thi-ng/umbrella/tree/develop/packages/hiccup)) to a
80
- variety of other formats. By design, for better flexibility and performance
81
- reasons, the hiccup flavor used by this package is **not** compatible with that
82
- used by
81
+ variety of other formats, incl. [conversion to SVG](#svg-support).
82
+
83
+ By design, for better flexibility and performance reasons, the hiccup flavor
84
+ used by this package is **not** compatible with that used by
83
85
  [thi.ng/hiccup-svg](https://github.com/thi-ng/umbrella/tree/develop/packages/hiccup-svg),
84
86
  though the latter provides a
85
87
  [`convertTree()`](https://docs.thi.ng/umbrella/hiccup-svg/functions/convertTree.html)
@@ -104,8 +106,8 @@ directly and/or perform automatic resampling/conversion if needed).
104
106
  | [`area()`](https://docs.thi.ng/umbrella/geom/functions/area.html) | signed/unsigned surface area |
105
107
  | [`asCubic()`](https://docs.thi.ng/umbrella/geom/functions/asCubic.html) | convert shape boundary to cubic bezier segments |
106
108
  | [`asPath()`](https://docs.thi.ng/umbrella/geom/functions/asPath.html) | convert shape to path |
107
- | [`asPolygon()`](https://docs.thi.ng/umbrella/geom/functions/asPolygon.html) | convert shape to polygon |
108
- | [`asPolyline()`](https://docs.thi.ng/umbrella/geom/functions/asPolyline.html) | convert shape to polyline |
109
+ | [`asPolygon()`](https://docs.thi.ng/umbrella/geom/functions/asPolygon.html) | convert shape to polygon(s) |
110
+ | [`asPolyline()`](https://docs.thi.ng/umbrella/geom/functions/asPolyline.html) | convert shape to polyline(s) |
109
111
  | [`asSvg()`](https://docs.thi.ng/umbrella/geom/functions/asSvg.html) | serialize shape/group/hierarchy to SVG |
110
112
  | [`bounds()`](https://docs.thi.ng/umbrella/geom/functions/bounds.html) | compute bounding box |
111
113
  | [`center()`](https://docs.thi.ng/umbrella/geom/functions/center.html) | center shape around origin or point |
@@ -122,6 +124,7 @@ directly and/or perform automatic resampling/conversion if needed).
122
124
  | [`offset()`](https://docs.thi.ng/umbrella/geom/functions/offset.html) | shape/path offsetting |
123
125
  | [`pointAt()`](https://docs.thi.ng/umbrella/geom/functions/pointAt.html) | compute point on shape boundary at parametric position |
124
126
  | [`pointInside()`](https://docs.thi.ng/umbrella/geom/functions/pointInside.html) | check if point is inside shape |
127
+ | [`proximity()`](https://docs.thi.ng/umbrella/geom/functions/proximity.html) | distance from point to shape boundary |
125
128
  | [`resample()`](https://docs.thi.ng/umbrella/geom/functions/resample.html) | resample/convert shape |
126
129
  | [`rotate()`](https://docs.thi.ng/umbrella/geom/functions/rotate.html) | rotate shape |
127
130
  | [`scale()`](https://docs.thi.ng/umbrella/geom/functions/scale.html) | scale shape (uniformly/non-uniformly) |
@@ -210,7 +213,7 @@ For Node.js REPL:
210
213
  const geom = await import("@thi.ng/geom");
211
214
  ```
212
215
 
213
- Package sizes (brotli'd, pre-treeshake): ESM: 13.25 KB
216
+ Package sizes (brotli'd, pre-treeshake): ESM: 14.59 KB
214
217
 
215
218
  ## Dependencies
216
219
 
@@ -253,9 +256,11 @@ directory are using this package:
253
256
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/boid-basics.png" width="240"/> | Basic 2D boid simulation and spatial indexing neighbor lookups | [Demo](https://demo.thi.ng/umbrella/boid-basics/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/boid-basics) |
254
257
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/canvas-recorder.png" width="240"/> | Self-modifying, animated typographic grid with emergent complex patterns | [Demo](https://demo.thi.ng/umbrella/canvas-recorder/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/canvas-recorder) |
255
258
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/fiber-basics.png" width="240"/> | Fiber-based cooperative multitasking basics | [Demo](https://demo.thi.ng/umbrella/fiber-basics/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/fiber-basics) |
259
+ | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/geom-complex-poly.png" width="240"/> | Shape conversions & operations using polygons with holes | [Demo](https://demo.thi.ng/umbrella/geom-complex-poly/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/geom-complex-poly) |
256
260
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/geom-convex-hull.png" width="240"/> | Convex hull & shape clipping of 2D polygons | [Demo](https://demo.thi.ng/umbrella/geom-convex-hull/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/geom-convex-hull) |
257
261
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/geom/geom-fuzz.png" width="240"/> | geom-fuzz basic shape & fill examples | [Demo](https://demo.thi.ng/umbrella/geom-fuzz-basics/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/geom-fuzz-basics) |
258
262
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/geom-sdf-logo.jpg" width="240"/> | (Re)Constructing the thi.ng logo using a 2D signed-distance field | [Demo](https://demo.thi.ng/umbrella/geom-sdf-logo/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/geom-sdf-logo) |
263
+ | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/geom-sdf-path.png" width="240"/> | SVG path to SDF, applying deformation and converting back to SVG | [Demo](https://demo.thi.ng/umbrella/geom-sdf-path/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/geom-sdf-path) |
259
264
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/geom-terrain-viz.jpg" width="240"/> | 2.5D hidden line visualization of digital elevation files (DEM) | [Demo](https://demo.thi.ng/umbrella/geom-terrain-viz/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/geom-terrain-viz) |
260
265
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/geom/tessel.png" width="240"/> | Animated, recursive polygon tessellations | [Demo](https://demo.thi.ng/umbrella/geom-tessel/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/geom-tessel) |
261
266
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/geom-voronoi-mst.jpg" width="240"/> | Poisson-disk shape-aware sampling, Voronoi & Minimum Spanning Tree visualization | [Demo](https://demo.thi.ng/umbrella/geom-voronoi-mst/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/geom-voronoi-mst) |
package/api/arc.js CHANGED
@@ -64,7 +64,7 @@ class Arc {
64
64
  return [
65
65
  "path",
66
66
  this.attribs,
67
- [["M", this.pointAt(0)], ...this.toHiccupPathSegments()]
67
+ [["M", this.pointAt(0)], this.toHiccupPathSegments()[0]]
68
68
  ];
69
69
  }
70
70
  toHiccupPathSegments() {
@@ -0,0 +1,14 @@
1
+ import type { Attribs, IHiccupShape } from "@thi.ng/geom-api";
2
+ import { Polygon } from "./polygon.js";
3
+ export declare class ComplexPolygon implements IHiccupShape {
4
+ boundary: Polygon;
5
+ attribs?: Attribs | undefined;
6
+ children: Polygon[];
7
+ constructor(boundary?: Polygon, children?: Iterable<Polygon>, attribs?: Attribs | undefined);
8
+ get type(): string;
9
+ addChild(poly: Polygon): void;
10
+ copy(): ComplexPolygon;
11
+ withAttribs(attribs: Attribs): ComplexPolygon;
12
+ toHiccup(): (string | any[] | Attribs | undefined)[];
13
+ }
14
+ //# sourceMappingURL=complex-polygon.d.ts.map
@@ -0,0 +1,44 @@
1
+ import { ensureArray } from "@thi.ng/arrays/ensure-array";
2
+ import { __copyAttribs } from "../internal/copy.js";
3
+ import { Polygon } from "./polygon.js";
4
+ class ComplexPolygon {
5
+ constructor(boundary = new Polygon(), children, attribs) {
6
+ this.boundary = boundary;
7
+ this.attribs = attribs;
8
+ this.children = children ? ensureArray(children) : [];
9
+ }
10
+ children;
11
+ get type() {
12
+ return "complexpoly";
13
+ }
14
+ addChild(poly) {
15
+ this.children.push(poly);
16
+ }
17
+ copy() {
18
+ return new ComplexPolygon(
19
+ this.boundary.copy(),
20
+ this.children.map((h) => h.copy()),
21
+ __copyAttribs(this)
22
+ );
23
+ }
24
+ withAttribs(attribs) {
25
+ return new ComplexPolygon(this.boundary, this.children, attribs);
26
+ }
27
+ toHiccup() {
28
+ const segments = [];
29
+ const $hiccupSegments = ({ points }) => {
30
+ if (!points.length) return;
31
+ segments.push(["M", points[0]]);
32
+ for (let i = 1, n = points.length; i < n; i++) {
33
+ segments.push(["L", points[i]]);
34
+ }
35
+ segments.push(["Z"]);
36
+ };
37
+ $hiccupSegments(this.boundary);
38
+ for (let c of this.children) $hiccupSegments(c);
39
+ return ["path", this.attribs, segments];
40
+ }
41
+ }
42
+ export {
43
+ ComplexPolygon
44
+ };
package/api/path.d.ts CHANGED
@@ -3,15 +3,23 @@ import type { Attribs, IHiccupShape, PathSegment } from "@thi.ng/geom-api";
3
3
  export declare class Path implements IClear, IHiccupShape {
4
4
  attribs?: Attribs | undefined;
5
5
  segments: PathSegment[];
6
- closed: boolean;
7
- constructor(segments?: Iterable<PathSegment>, attribs?: Attribs | undefined);
6
+ subPaths: PathSegment[][];
7
+ constructor(segments?: Iterable<PathSegment>, subPaths?: Iterable<PathSegment[]>, attribs?: Attribs | undefined);
8
8
  get type(): string;
9
+ /**
10
+ * Returns true, if the last main segment is a closing segment, e.g. if the
11
+ * path represents a closed shape.
12
+ */
13
+ get closed(): boolean;
9
14
  [Symbol.iterator](): Generator<PathSegment, void, undefined>;
10
15
  clear(): void;
16
+ close(): this;
11
17
  copy(): Path;
12
18
  withAttribs(attribs: Attribs): Path;
13
19
  equiv(o: any): boolean;
14
- add(...segments: PathSegment[]): void;
20
+ isComplex(): number;
21
+ addSegments(...segments: PathSegment[]): this;
22
+ addSubPaths(...paths: PathSegment[][]): this;
15
23
  toHiccup(): (string | any[] | Attribs)[];
16
24
  }
17
25
  //# sourceMappingURL=path.d.ts.map
package/api/path.js CHANGED
@@ -1,68 +1,84 @@
1
1
  import { ensureArray } from "@thi.ng/arrays/ensure-array";
2
+ import { peek } from "@thi.ng/arrays/peek";
2
3
  import { equiv } from "@thi.ng/equiv";
3
4
  import { illegalState } from "@thi.ng/errors/illegal-state";
4
- import { copy } from "@thi.ng/vectors/copy";
5
- import { __copyAttribs } from "../internal/copy.js";
5
+ import { __copyAttribs, __copySegment } from "../internal/copy.js";
6
+ const CLOSE = Object.freeze({ type: "z" });
6
7
  class Path {
7
- constructor(segments, attribs) {
8
+ constructor(segments, subPaths, attribs) {
8
9
  this.attribs = attribs;
9
10
  this.segments = segments ? ensureArray(segments) : [];
11
+ this.subPaths = subPaths ? ensureArray(subPaths) : [];
10
12
  }
11
13
  segments;
12
- closed = false;
14
+ subPaths;
13
15
  get type() {
14
16
  return "path";
15
17
  }
18
+ /**
19
+ * Returns true, if the last main segment is a closing segment, e.g. if the
20
+ * path represents a closed shape.
21
+ */
22
+ get closed() {
23
+ return peek(this.segments)?.type === "z";
24
+ }
16
25
  *[Symbol.iterator]() {
17
26
  yield* this.segments;
18
27
  }
19
28
  clear() {
20
29
  this.segments.length = 0;
21
30
  }
31
+ close() {
32
+ if (!this.closed) this.segments.push(CLOSE);
33
+ return this;
34
+ }
22
35
  copy() {
23
36
  const p = new Path(
24
- this.segments.map((s) => {
25
- const d = { type: s.type };
26
- s.point && (d.point = copy(s.point));
27
- s.geo && (d.geo = s.geo.copy());
28
- return d;
29
- }),
37
+ this.segments.map(__copySegment),
38
+ this.subPaths.map((sub) => sub.map(__copySegment)),
30
39
  __copyAttribs(this)
31
40
  );
32
- p.closed = this.closed;
33
41
  return p;
34
42
  }
35
43
  withAttribs(attribs) {
36
- const res = new Path(this.segments, attribs);
37
- res.closed = this.closed;
38
- return res;
44
+ return new Path(this.segments, this.subPaths, attribs);
39
45
  }
40
46
  equiv(o) {
41
47
  return o instanceof Path && equiv(this.segments, o.segments);
42
48
  }
43
- add(...segments) {
44
- if (this.closed)
45
- illegalState("path already closed");
46
- this.segments.push(...segments);
49
+ isComplex() {
50
+ return this.subPaths.length;
51
+ }
52
+ addSegments(...segments) {
53
+ for (let s of segments) {
54
+ this.closed && illegalState("path already closed");
55
+ this.segments.push(s);
56
+ }
57
+ return this;
58
+ }
59
+ addSubPaths(...paths) {
60
+ this.subPaths.push(...paths);
61
+ return this;
47
62
  }
48
63
  toHiccup() {
49
- let dest = [];
50
- const segments = this.segments;
51
- const n = segments.length;
52
- if (n > 1) {
53
- for (let i = 0; i < n; i++) {
64
+ const acc = [];
65
+ const $hiccupSegments = (segments) => {
66
+ for (let i = 0, n = segments.length; i < n; i++) {
54
67
  const s = segments[i];
55
68
  if (s.geo) {
56
- dest = dest.concat(s.geo.toHiccupPathSegments());
69
+ acc.push(...s.geo.toHiccupPathSegments());
57
70
  } else if (s.point) {
58
- dest.push(["M", s.point]);
71
+ acc.push(["M", s.point]);
72
+ } else {
73
+ acc.push([s.type]);
59
74
  }
60
75
  }
61
- if (this.closed) {
62
- dest.push(["Z"]);
63
- }
76
+ };
77
+ if (this.segments.length > 1) {
78
+ $hiccupSegments(this.segments);
64
79
  }
65
- return ["path", this.attribs || {}, dest];
80
+ for (let p of this.subPaths) $hiccupSegments(p);
81
+ return ["path", this.attribs || {}, acc];
66
82
  }
67
83
  }
68
84
  export {
@@ -8,23 +8,18 @@ import { translate } from "./translate.js";
8
8
  const TX_ATTRIBS = ["transform", "translate", "rotate", "scale"];
9
9
  const __apply = ($) => {
10
10
  let attribs = $.attribs;
11
- if (!attribs)
12
- return $;
11
+ if (!attribs) return $;
13
12
  const { transform: tx, translate: t, rotate: r, scale: s } = attribs;
14
13
  if (tx)
15
14
  return transform(
16
15
  $.withAttribs(withoutKeysObj(attribs, TX_ATTRIBS)),
17
16
  tx
18
17
  );
19
- if (!(t || r || s))
20
- return $;
18
+ if (!(t || r || s)) return $;
21
19
  $ = $.withAttribs(withoutKeysObj(attribs, TX_ATTRIBS));
22
- if (r)
23
- $ = rotate($, r);
24
- if (s)
25
- $ = scale($, s);
26
- if (t)
27
- $ = translate($, t);
20
+ if (r) $ = rotate($, r);
21
+ if (s) $ = scale($, s);
22
+ if (t) $ = translate($, t);
28
23
  return $;
29
24
  };
30
25
  const applyTransforms = defmulti(
package/arc-length.d.ts CHANGED
@@ -8,6 +8,7 @@ import type { IShape } from "@thi.ng/geom-api";
8
8
  * Implemented for:
9
9
  *
10
10
  * - {@link Circle}
11
+ * - {@link ComplexPolygon}
11
12
  * - {@link Ellipse}
12
13
  * - {@link Group} (total sum of child circumferences)
13
14
  * - {@link Line}
package/arc-length.js CHANGED
@@ -2,6 +2,8 @@ import { defmulti } from "@thi.ng/defmulti/defmulti";
2
2
  import { perimeter } from "@thi.ng/geom-poly-utils/perimeter";
3
3
  import { PI, TAU } from "@thi.ng/math/api";
4
4
  import { dist } from "@thi.ng/vectors/dist";
5
+ import { asPolygon } from "./as-polygon.js";
6
+ import { asPolyline } from "./as-polyline.js";
5
7
  import { __dispatch } from "./internal/dispatch.js";
6
8
  const arcLength = defmulti(
7
9
  __dispatch,
@@ -11,6 +13,10 @@ const arcLength = defmulti(
11
13
  },
12
14
  {
13
15
  circle: ($) => TAU * $.r,
16
+ complexpoly: ($) => [$.boundary, ...$.children].reduce(
17
+ (acc, c) => acc + arcLength(c),
18
+ 0
19
+ ),
14
20
  ellipse: ({ r: [a, b] }) => (
15
21
  // Ramanujan approximation
16
22
  // https://www.mathsisfun.com/geometry/ellipse-perimeter.html
@@ -18,6 +24,12 @@ const arcLength = defmulti(
18
24
  ),
19
25
  group: ({ children }) => children.reduce((sum, $) => sum + arcLength($), 0),
20
26
  line: ({ points }) => dist(points[0], points[1]),
27
+ path: ($) => {
28
+ return ($.closed ? asPolygon($) : asPolyline($)).reduce(
29
+ (acc, p) => acc + arcLength(p),
30
+ 0
31
+ );
32
+ },
21
33
  poly: ({ points }) => perimeter(points, points.length, true),
22
34
  polyline: ({ points }) => perimeter(points, points.length),
23
35
  rect: ({ size: [w, h] }) => 2 * (w + h),
package/area.d.ts CHANGED
@@ -15,6 +15,7 @@ import type { IShape } from "@thi.ng/geom-api";
15
15
  *
16
16
  * - {@link AABB}
17
17
  * - {@link Circle}
18
+ * - {@link ComplexPolygon}
18
19
  * - {@link Cubic}
19
20
  * - {@link Ellipse}
20
21
  * - {@link Group}
package/area.js CHANGED
@@ -14,9 +14,12 @@ const area = defmulti(
14
14
  ($) => 0.5 * Math.abs($.start - $.end) * $.r[0] * $.r[1]
15
15
  ),
16
16
  circle: ($) => PI * $.r ** 2,
17
+ complexpoly: ($, signed) => area($.boundary, signed) - $.children.reduce((acc, c) => acc + area(c, signed), 0),
17
18
  ellipse: ($) => PI * $.r[0] * $.r[1],
18
19
  group: ({ children }) => children.reduce((sum, $) => sum + area($, false), 0),
19
- path: ($) => $.closed ? area(asPolygon($)) : 0,
20
+ path: ($, signed) => {
21
+ return $.closed ? asPolygon($).reduce((acc, p) => acc + area(p, signed), 0) : 0;
22
+ },
20
23
  plane: () => Infinity,
21
24
  poly: ($, signed) => {
22
25
  const area2 = polyArea2($.points);
package/as-cubic.d.ts CHANGED
@@ -10,6 +10,7 @@ import { Cubic } from "./api/cubic.js";
10
10
  *
11
11
  * - {@link Arc}
12
12
  * - {@link Circle}
13
+ * - {@link ComplexPolygon}
13
14
  * - {@link Cubic}
14
15
  * - {@link Ellipse}
15
16
  * - {@link Group}
@@ -27,6 +28,7 @@ import { Cubic } from "./api/cubic.js";
27
28
  * for more details):
28
29
  *
29
30
  * - {@link Group} (only used for eligible children)
31
+ * - {@link ComplexPolygon}
30
32
  * - {@link Polygon}
31
33
  * - {@link Polyline}
32
34
  * - {@link Quad}
package/as-cubic.js CHANGED
@@ -8,6 +8,8 @@ import {
8
8
  openCubicFromControlPoints
9
9
  } from "@thi.ng/geom-splines/cubic-from-controlpoints";
10
10
  import { TAU } from "@thi.ng/math/api";
11
+ import { concat } from "@thi.ng/transducers/concat";
12
+ import { flatten1 } from "@thi.ng/transducers/flatten1";
11
13
  import { mapcat } from "@thi.ng/transducers/mapcat";
12
14
  import { Cubic } from "./api/cubic.js";
13
15
  import { arc } from "./arc.js";
@@ -25,6 +27,9 @@ const asCubic = defmulti(
25
27
  {
26
28
  arc: cubicFromArc,
27
29
  circle: ($) => asCubic(arc($.pos, $.r, 0, 0, TAU, true, true)),
30
+ complexpoly: ($, opts = {}) => [
31
+ ...mapcat((x) => asCubic(x, opts), [$.boundary, ...$.children])
32
+ ],
28
33
  cubic: ($) => [$],
29
34
  group: ($, opts) => [
30
35
  ...mapcat((x) => asCubic(x, opts), $.children)
@@ -33,7 +38,10 @@ const asCubic = defmulti(
33
38
  cubicFromLine(points[0], points[1], { ...attribs })
34
39
  ],
35
40
  path: ($) => [
36
- ...mapcat((s) => s.geo ? asCubic(s.geo) : null, $.segments)
41
+ ...mapcat(
42
+ (segment) => segment.geo ? asCubic(segment.geo) : null,
43
+ concat($.segments, flatten1($.subPaths))
44
+ )
37
45
  ],
38
46
  poly: ($, opts = {}) => __polyCubic(
39
47
  $,
@@ -50,7 +58,7 @@ const asCubic = defmulti(
50
58
  quadratic: ({ attribs, points }) => [
51
59
  cubicFromQuadratic(points[0], points[1], points[2], { ...attribs })
52
60
  ],
53
- rect: ($, opts) => asCubic(asPolygon($), opts)
61
+ rect: ($, opts) => asCubic(asPolygon($)[0], opts)
54
62
  }
55
63
  );
56
64
  const __polyCubic = ($, opts, breakPoints, controlPoints) => {
package/as-path.d.ts CHANGED
@@ -1,10 +1,26 @@
1
- import type { Attribs, IShape } from "@thi.ng/geom-api";
1
+ import type { Maybe } from "@thi.ng/api";
2
+ import type { MultiFn2O } from "@thi.ng/defmulti";
3
+ import type { Attribs, CubicOpts, IShape } from "@thi.ng/geom-api";
4
+ import { Path } from "./api/path.js";
5
+ export interface AsPathOpts extends CubicOpts {
6
+ /**
7
+ * If true (default: false), creates path consisting of linear segments
8
+ * only.
9
+ */
10
+ linear: boolean;
11
+ }
2
12
  /**
3
- * Converts given shape into a {@link Path} (via {@link asCubic} and
13
+ * Converts given shape into a {@link Path} (by default via {@link asCubic} and
4
14
  * {@link pathFromCubics}).
5
15
  *
16
+ * @remarks
17
+ * If {@link AsPathOpts.linear} is enabled the shape will be converted into a
18
+ * path consisting only of linear segments (NOT cubic beziers). As an interim
19
+ * step this will involve a conversion via {@link asPolygon} or
20
+ * {@link asPolyline} with default opts.
21
+ *
6
22
  * @param src
7
23
  * @param attribs
8
24
  */
9
- export declare const asPath: (src: IShape, attribs?: Attribs) => import("./index.js").Path;
25
+ export declare const asPath: ((shape: IShape, opts?: Partial<AsPathOpts>, attribs?: Attribs) => Path) & MultiFn2O<IShape, Maybe<Partial<AsPathOpts>>, Attribs, Path>;
10
26
  //# sourceMappingURL=as-path.d.ts.map