@thi.ng/geom 6.1.9 → 7.0.1

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 (85) hide show
  1. package/CHANGELOG.md +114 -1
  2. package/README.md +34 -29
  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/arc.d.ts +51 -1
  12. package/arc.js +12 -1
  13. package/area.d.ts +1 -0
  14. package/area.js +4 -1
  15. package/as-cubic.d.ts +2 -0
  16. package/as-cubic.js +10 -2
  17. package/as-path.d.ts +19 -3
  18. package/as-path.js +54 -1
  19. package/as-polygon.d.ts +7 -5
  20. package/as-polygon.js +14 -1
  21. package/as-polyline.d.ts +6 -4
  22. package/as-polyline.js +19 -5
  23. package/bounds.js +14 -7
  24. package/centroid.d.ts +3 -2
  25. package/centroid.js +10 -1
  26. package/classify-point.d.ts +5 -2
  27. package/clip-convex.d.ts +22 -3
  28. package/clip-convex.js +39 -12
  29. package/closest-point.d.ts +2 -0
  30. package/closest-point.js +34 -0
  31. package/complex-polygon-from-path.d.ts +14 -0
  32. package/complex-polygon-from-path.js +9 -0
  33. package/complex-polygon.d.ts +23 -0
  34. package/complex-polygon.js +6 -0
  35. package/convex-hull.d.ts +1 -0
  36. package/convex-hull.js +2 -0
  37. package/edges.d.ts +2 -0
  38. package/edges.js +7 -3
  39. package/fit-into-bounds.js +5 -10
  40. package/flip.d.ts +1 -0
  41. package/flip.js +5 -0
  42. package/index.d.ts +5 -0
  43. package/index.js +5 -0
  44. package/internal/bounds.js +3 -6
  45. package/internal/copy.d.ts +3 -1
  46. package/internal/copy.js +9 -3
  47. package/internal/transform.d.ts +20 -7
  48. package/internal/transform.js +10 -0
  49. package/intersects.js +3 -6
  50. package/package.json +48 -33
  51. package/path-builder.d.ts +21 -1
  52. package/path-builder.js +31 -14
  53. package/path-from-svg.d.ts +13 -1
  54. package/path-from-svg.js +10 -14
  55. package/path.d.ts +59 -2
  56. package/path.js +44 -19
  57. package/point-inside.d.ts +12 -9
  58. package/point-inside.js +3 -0
  59. package/proximity.d.ts +11 -0
  60. package/proximity.js +9 -0
  61. package/resample.d.ts +1 -0
  62. package/resample.js +7 -1
  63. package/rotate.d.ts +1 -0
  64. package/rotate.js +13 -10
  65. package/scale-with-center.d.ts +20 -0
  66. package/scale-with-center.js +7 -0
  67. package/scale.d.ts +1 -0
  68. package/scale.js +12 -9
  69. package/scatter.js +1 -2
  70. package/simplify.d.ts +4 -3
  71. package/simplify.js +39 -27
  72. package/split-arclength.d.ts +1 -1
  73. package/split-arclength.js +4 -6
  74. package/subdiv-curve.d.ts +5 -1
  75. package/subdiv-curve.js +10 -8
  76. package/transform-vertices.d.ts +1 -0
  77. package/transform-vertices.js +19 -19
  78. package/transform.d.ts +1 -0
  79. package/transform.js +17 -16
  80. package/translate.d.ts +1 -0
  81. package/translate.js +17 -12
  82. package/vertices.d.ts +18 -17
  83. package/vertices.js +22 -11
  84. package/with-attribs.d.ts +1 -1
  85. 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-09T14:25:15Z
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,119 @@ 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.1](https://github.com/thi-ng/umbrella/tree/@thi.ng/geom@7.0.1) (2024-05-09)
13
+
14
+ #### 🩹 Bug fixes
15
+
16
+ - update arc() arg defaults, add docs ([cc57a57](https://github.com/thi-ng/umbrella/commit/cc57a57))
17
+
18
+ # [7.0.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/geom@7.0.0) (2024-05-08)
19
+
20
+ #### 🛑 Breaking changes
21
+
22
+ - 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))
23
+ - BREAKING CHANGE: update path related ctors & functions
24
+ - add `subPaths` argument for Path ctor/factory fn
25
+ - rename `Path.add()` => `Path.addSegments()`
26
+ - add `Path.addSubPaths()`
27
+ - update `Path.toHiccup()` to include sub-paths
28
+ - update `pathFromSvg()` to always return a single path only
29
+ - sub-paths are included in main path now
30
+ - update impls for following ops to also process sub-paths:
31
+ - bounds()
32
+ - rotate()
33
+ - scale()
34
+ - simplify()
35
+ - translate()
36
+ - transform()
37
+ - transformVertices()
38
+ - 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))
39
+ - BREAKING CHANGE: update asPolygon() to return array of polylines
40
+ - add/update impls for complexpoly & path to produce multiple results
41
+ - update other internal callsites
42
+ - update tests
43
+ - update `Path` closing logic ([ce3a922](https://github.com/thi-ng/umbrella/commit/ce3a922))
44
+ - BREAKING CHANGE: update `Path` closing logic, `Path.closed` now a readonly property
45
+ - add `Path.closed()` getter
46
+ - add `Path.close()` to add a `Z`-type segment, check if not closed already
47
+ - update `Path.addSegments()` to check each segment, throw error if path already closed
48
+ - refactor `PathBuilder.closePath()`
49
+ - add asPolygon() support for complexpoly & path ([e3c9f20](https://github.com/thi-ng/umbrella/commit/e3c9f20))
50
+ - BREAKING CHANGE: update asPolygon() to return array of polygons (rather than single only)
51
+ - add support for complexpoly & path (incl. sub-shapes, holes)
52
+ - refactor internal call sites
53
+ - update asPath(), add AsPathOpts ([ef0ebdf](https://github.com/thi-ng/umbrella/commit/ef0ebdf))
54
+ - BREAKING CHANGE: update asPath() args, add AsPathOpts as 2nd arg
55
+ - add option for using only linear path segments (no cubics)
56
+ - update impls for complexpoly & other polygon types
57
+ - update Path & PathBuilder.close() ([b2134c2](https://github.com/thi-ng/umbrella/commit/b2134c2))
58
+ - BREAKING CHANGE: rename `PathBuilder.closePath()` => `PathBuilder.close()`
59
+ - update `Path.close()` to return path itself
60
+ - rewrite roundedRect() to allow individual corner radii ([a4817aa](https://github.com/thi-ng/umbrella/commit/a4817aa))
61
+ - BREAKING CHANGE: update roundedRect() radius handling to allow individual corner radii
62
+ - update docs
63
+ - add tests
64
+
65
+ #### 🚀 Features
66
+
67
+ - initial import ComplexPolygon & impls ([#464](https://github.com/thi-ng/umbrella/issues/464)) ([ded007c](https://github.com/thi-ng/umbrella/commit/ded007c))
68
+ - add complexPolygon() factory fn
69
+ - add bounds() & centroid() impls
70
+ - add ops for complex polygons ([#464](https://github.com/thi-ng/umbrella/issues/464)) ([35ce854](https://github.com/thi-ng/umbrella/commit/35ce854))
71
+ - add implementations for:
72
+ - arcLength()
73
+ - area()
74
+ - asPath()
75
+ - closestPoint()
76
+ - convexHull()
77
+ - edges()
78
+ - flip()
79
+ - pointInside()
80
+ - resample()
81
+ - rotate()
82
+ - scale()
83
+ - simplify()
84
+ - subdivCurve()
85
+ - transform()
86
+ - transformVertices()
87
+ - translate()
88
+ - vertices()
89
+ - add tests
90
+ - add proximity() ([5d5951c](https://github.com/thi-ng/umbrella/commit/5d5951c))
91
+ - update `vertices()` impl for `Path`, incl. sub-path vertices ([824067f](https://github.com/thi-ng/umbrella/commit/824067f))
92
+ - update simplify() default threshold ([bdba298](https://github.com/thi-ng/umbrella/commit/bdba298))
93
+ - add arcLength() for Path, refactor complexpoly impl ([d133bbe](https://github.com/thi-ng/umbrella/commit/d133bbe))
94
+ - add/update asCubic() impls for complex poly & path ([7f9e927](https://github.com/thi-ng/umbrella/commit/7f9e927))
95
+ - update pathFromCubics() to auto-create sub-paths if needed ([1170e45](https://github.com/thi-ng/umbrella/commit/1170e45))
96
+ - add closestPoint() impl for Path ([f0cf2f1](https://github.com/thi-ng/umbrella/commit/f0cf2f1))
97
+ - add pointInside() impl for Polyline ([d10bf43](https://github.com/thi-ng/umbrella/commit/d10bf43))
98
+ - add centroid() & convexHull() impl for Path ([76aa229](https://github.com/thi-ng/umbrella/commit/76aa229))
99
+ - add complexPolygonFromPath() ([cd526f1](https://github.com/thi-ng/umbrella/commit/cd526f1))
100
+ - update PathBuilder.close(), fix attrib handling ([e68d0bc](https://github.com/thi-ng/umbrella/commit/e68d0bc))
101
+ - only insert closing line segment if needed
102
+ - copy attribs for each new path
103
+ - add docs
104
+ - add opt attribs for `pathFromSvg()` ([2da31f6](https://github.com/thi-ng/umbrella/commit/2da31f6))
105
+ - update docs
106
+ - add/update tests
107
+ - add scaleWithCenter() ([e328494](https://github.com/thi-ng/umbrella/commit/e328494))
108
+ - add complexpoly & path support for `clipConvex()` ([7665dc1](https://github.com/thi-ng/umbrella/commit/7665dc1))
109
+
110
+ #### 🩹 Bug fixes
111
+
112
+ - update vertices() ([2afc05e](https://github.com/thi-ng/umbrella/commit/2afc05e))
113
+ - update impl for points, poly, polyline to return shallow copy of point array if no opts given
114
+
115
+ #### ♻️ Refactoring
116
+
117
+ - update withAttribs(), make new attribs optional ([688e1bf](https://github.com/thi-ng/umbrella/commit/688e1bf))
118
+ - update geom examples (recent API changes) ([f0f5ea7](https://github.com/thi-ng/umbrella/commit/f0f5ea7))
119
+ - update area() impl for Path ([0960817](https://github.com/thi-ng/umbrella/commit/0960817))
120
+ - update/simplify asPath() impls ([cbc71bb](https://github.com/thi-ng/umbrella/commit/cbc71bb))
121
+ - update centroid() for complexpoly ([58ac296](https://github.com/thi-ng/umbrella/commit/58ac296))
122
+ - re-use migrated fn from [@thi.ng/geom-poly-utils](https://github.com/thi-ng/umbrella/tree/main/packages/geom-poly-utils)
123
+ - update path segment transformations ([88b2c40](https://github.com/thi-ng/umbrella/commit/88b2c40))
124
+
12
125
  ### [6.1.7](https://github.com/thi-ng/umbrella/tree/@thi.ng/geom@6.1.7) (2024-04-20)
13
126
 
14
127
  #### ♻️ 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.61 KB
214
217
 
215
218
  ## Dependencies
216
219
 
@@ -253,15 +256,17 @@ 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) |
262
267
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/gesture-analysis.png" width="240"/> | Mouse gesture / stroke analysis, simplification, corner detection | [Demo](https://demo.thi.ng/umbrella/gesture-analysis/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/gesture-analysis) |
263
268
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/hdom-canvas-particles.jpg" width="240"/> | 2D Bezier curve-guided particle system | [Demo](https://demo.thi.ng/umbrella/hdom-canvas-particles/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/hdom-canvas-particles) |
264
- | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/hiccup-canvas-arcs.png" width="240"/> | Animated arcs & drawing using hiccup-canvas | [Demo](https://demo.thi.ng/umbrella/hiccup-canvas-arcs/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/hiccup-canvas-arcs) |
269
+ | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/hiccup-canvas-arcs.jpg" width="240"/> | Animated arcs & drawing using hiccup-canvas | [Demo](https://demo.thi.ng/umbrella/hiccup-canvas-arcs/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/hiccup-canvas-arcs) |
265
270
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/imgui/imgui-all.png" width="240"/> | Canvas based Immediate Mode GUI components | [Demo](https://demo.thi.ng/umbrella/imgui/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/imgui) |
266
271
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/geom/geom-isoline.png" width="240"/> | Animated sine plasma effect visualized using contour lines | [Demo](https://demo.thi.ng/umbrella/iso-plasma/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/iso-plasma) |
267
272
  | <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/kmeans-viz.jpg" width="240"/> | k-means clustering visualization | [Demo](https://demo.thi.ng/umbrella/kmeans-viz/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/kmeans-viz) |
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/arc.d.ts CHANGED
@@ -1,6 +1,56 @@
1
1
  import type { Attribs } from "@thi.ng/geom-api";
2
2
  import type { ReadonlyVec, Vec } from "@thi.ng/vectors";
3
3
  import { Arc } from "./api/arc.js";
4
- export declare const arc: (pos: Vec, r: number | Vec, axis: number, start: number, end: number, xl?: boolean, clockwise?: boolean) => Arc;
4
+ /**
5
+ * Creates a new elliptic {@link Arc} from given `center`, `radii`, `axis`
6
+ * rotation, `start` and `end` angles (in radians).
7
+ *
8
+ * @remarks
9
+ * The `xl` (large arc) and `clockwise` params are defaulting to:
10
+ *
11
+ * - xl = true if |start-end| > PI
12
+ * - clockwise = true if end > start
13
+ *
14
+ * Reference:
15
+ * - https://svgwg.org/svg2-draft/paths.html#PathDataEllipticalArcCommands
16
+ * - https://svgwg.org/svg2-draft/images/paths/arcs02.svg
17
+ *
18
+ * Also see {@link arcFrom2Points}, {@link pathFromSvg} for an alternative construction.
19
+ *
20
+ * @param center
21
+ * @param radii
22
+ * @param axis
23
+ * @param start
24
+ * @param end
25
+ * @param xl
26
+ * @param clockwise
27
+ * @param attribs
28
+ */
29
+ export declare const arc: (center: Vec, radii: number | Vec, axis: number, start: number, end: number, xl?: boolean, clockwise?: boolean, attribs?: Attribs) => Arc;
30
+ /**
31
+ * Constructs a new {@link Arc} between the two given points `a` and `b` using
32
+ * `radii`, `axis` rotation (in radians) and `xl`, `clockwise` params to
33
+ * configure which of 4 possible arcs will be chosen.
34
+ *
35
+ * @remarks
36
+ * This function returns `undefined` if it's mathematically impossible to create
37
+ * an arc with the given parameters.
38
+ *
39
+ * Reference:
40
+ * - https://svgwg.org/svg2-draft/paths.html#PathDataEllipticalArcCommands
41
+ * - https://svgwg.org/svg2-draft/images/paths/arcs02.svg
42
+ * - https://svgwg.org/svg2-draft/implnote.html#ArcConversionEndpointToCenter
43
+ * - https://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
44
+ *
45
+ * Also see {@link arc}, {@link pathFromSvg} for an alternative construction.
46
+ *
47
+ * @param a
48
+ * @param b
49
+ * @param radii
50
+ * @param axis
51
+ * @param xl
52
+ * @param cw
53
+ * @param attribs
54
+ */
5
55
  export declare const arcFrom2Points: (a: ReadonlyVec, b: ReadonlyVec, radii: ReadonlyVec, axis?: number, xl?: boolean, cw?: boolean, attribs?: Attribs) => Arc | undefined;
6
56
  //# sourceMappingURL=arc.d.ts.map
package/arc.js CHANGED
@@ -1,7 +1,18 @@
1
1
  import { isNumber } from "@thi.ng/checks/is-number";
2
2
  import { fromEndPoints } from "@thi.ng/geom-arc/from-endpoints";
3
3
  import { Arc } from "./api/arc.js";
4
- const arc = (pos, r, axis, start, end, xl = false, clockwise = false) => new Arc(pos, isNumber(r) ? [r, r] : r, axis, start, end, xl, clockwise);
4
+ import { absDiff } from "@thi.ng/math/abs";
5
+ import { PI } from "@thi.ng/math/api";
6
+ const arc = (center, radii, axis, start, end, xl = absDiff(start, end) > PI, clockwise = end > start, attribs) => new Arc(
7
+ center,
8
+ isNumber(radii) ? [radii, radii] : radii,
9
+ axis,
10
+ start,
11
+ end,
12
+ xl,
13
+ clockwise,
14
+ attribs
15
+ );
5
16
  const arcFrom2Points = (a, b, radii, axis = 0, xl = false, cw = false, attribs) => {
6
17
  const res = fromEndPoints(a, b, radii, axis, xl, cw);
7
18
  return res ? new Arc(
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}