@immugio/three-math-extensions 0.2.13 → 0.2.15

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.
package/CHANGELOG.md CHANGED
@@ -7,16 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
9
9
 
10
- ## [0.2.13](https://github.com/Immugio/three-math-extensions/compare/16.15.10...0.2.13)
10
+ ## [0.2.15](https://github.com/Immugio/three-math-extensions/compare/16.15.10...0.2.15)
11
11
 
12
12
  ### Commits
13
13
 
14
+ - Packages update [`0d85b39`](https://github.com/Immugio/three-math-extensions/commit/0d85b392029f7bbaa5063cd0494e34f593d62ea5)
14
15
  - Add eslint [`98e4912`](https://github.com/Immugio/three-math-extensions/commit/98e4912d637b42ba80e2f3267638b43296113019)
15
16
  - Update jest packages [`af23b4f`](https://github.com/Immugio/three-math-extensions/commit/af23b4f08154bba3407f05b773865215e7e1cba8)
16
17
  - Add Rectangle, update Polygon [`58ee875`](https://github.com/Immugio/three-math-extensions/commit/58ee87539af8f9ade186e5250cba9e01926da514)
17
18
  - Add isPointInPolygon [`a59eb4b`](https://github.com/Immugio/three-math-extensions/commit/a59eb4be026f17a3106070ae626a0588cd4f4411)
18
19
  - Improve Line2D.closestPointToPoint, add Vec2.signedAngle [`151f214`](https://github.com/Immugio/three-math-extensions/commit/151f21462e0358057ad8e9d75d5782563a1061f6)
19
20
  - Improve documentation [`d0fcb51`](https://github.com/Immugio/three-math-extensions/commit/d0fcb5132f127b4382ac5f7291575a061b8ec121)
21
+ - Add isContinuousClosedShape, add Line2D.groupConnectedLines [`4ef8c2f`](https://github.com/Immugio/three-math-extensions/commit/4ef8c2fe83fdc71dd87fee4cbc478ddf0a086442)
20
22
  - Vec3, Line3D - update documentation [`67d9c32`](https://github.com/Immugio/three-math-extensions/commit/67d9c328e08cc0a5599932d2f0529e97f31c9213)
21
23
  - Add Polygon [`629cff8`](https://github.com/Immugio/three-math-extensions/commit/629cff8ecbb963477e8ea76d7f8b16d95435cbad)
22
24
  - Line3D.groupConnectedLines added [`29f372b`](https://github.com/Immugio/three-math-extensions/commit/29f372bc984c06b00c50fcd9428ce9a7b9cab799)
@@ -27,6 +29,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
27
29
  - Add Vec2.fromPoints to accept multiple points [`a261402`](https://github.com/Immugio/three-math-extensions/commit/a2614027cf5fb8263189b48f7e0bb9a23a552c15)
28
30
  - Add Vec2.parallelTo [`989874d`](https://github.com/Immugio/three-math-extensions/commit/989874dcfe122d3ee84d8d56d79cb88e4e441736)
29
31
  - Line2D.intersect - enable line segments intersection only [`1f1470e`](https://github.com/Immugio/three-math-extensions/commit/1f1470e1cf00118e643f5c44a135e0baf6b76d41)
32
+ - Line3D.groupConnectedLines now supports line breaks [`417a9ea`](https://github.com/Immugio/three-math-extensions/commit/417a9ea471bf4c539f73f5fb170c962a78ee4ab4)
30
33
  - Add Line2D.projectOn [`4c52c5c`](https://github.com/Immugio/three-math-extensions/commit/4c52c5c2e649fbddb72ce3fca60cfd3f1319f72f)
31
34
  - Add Line3D.index [`7ed13d2`](https://github.com/Immugio/three-math-extensions/commit/7ed13d213748056c9dafd86288c3bcec9a28d1ba)
32
35
  - Polygon from bounding size [`eae6701`](https://github.com/Immugio/three-math-extensions/commit/eae67012f57f426f8b5259b765000447ce06d608)
@@ -39,10 +42,23 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
39
42
  - Update release instructions [`5b41a2e`](https://github.com/Immugio/three-math-extensions/commit/5b41a2ed7e15450dbb6088a7f7ed0031a013badc)
40
43
  - Add Polygon to exports [`ed66775`](https://github.com/Immugio/three-math-extensions/commit/ed66775c33e961835b23843222b822cfd9c16b1d)
41
44
  - Vec2.fromPoint and Vec3.fromPoint should accept null [`4b871af`](https://github.com/Immugio/three-math-extensions/commit/4b871af297bdcbe8584f1e2b99d602247b77687c)
45
+ - Add HalfPI [`7a6614c`](https://github.com/Immugio/three-math-extensions/commit/7a6614c3d6f59ac216e58986927112f94207a755)
42
46
  - Documentation update [`d5c7a07`](https://github.com/Immugio/three-math-extensions/commit/d5c7a0765f6097f5d3a3be01967d4059f19682fb)
43
47
  - Excluded files from build [`ec70614`](https://github.com/Immugio/three-math-extensions/commit/ec70614bc7df7a98f854c7a6693365118e04faf7)
44
48
 
45
- ## [16.15.10](https://github.com/Immugio/three-math-extensions/compare/0.2.12...16.15.10) - 2023-01-02
49
+ ## [16.15.10](https://github.com/Immugio/three-math-extensions/compare/0.2.14...16.15.10) - 2023-01-02
50
+
51
+ ## [0.2.14](https://github.com/Immugio/three-math-extensions/compare/0.2.13...0.2.14) - 2023-08-31
52
+
53
+ ### Commits
54
+
55
+ - Line3D.groupConnectedLines now supports line breaks [`417a9ea`](https://github.com/Immugio/three-math-extensions/commit/417a9ea471bf4c539f73f5fb170c962a78ee4ab4)
56
+
57
+ ## [0.2.13](https://github.com/Immugio/three-math-extensions/compare/0.2.12...0.2.13) - 2023-08-31
58
+
59
+ ### Commits
60
+
61
+ - Line3D.connectsTo added [`6d2cfa0`](https://github.com/Immugio/three-math-extensions/commit/6d2cfa0f5335c665f325a694a32c57b574ec326d)
46
62
 
47
63
  ## [0.2.12](https://github.com/Immugio/three-math-extensions/compare/0.2.11...0.2.12) - 2023-08-30
48
64
 
@@ -214,15 +230,62 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
214
230
 
215
231
  ## [0.0.7](https://github.com/Immugio/three-math-extensions/compare/0.0.6...0.0.7) - 2022-11-21
216
232
 
217
- ## [0.0.6](https://github.com/Immugio/three-math-extensions/compare/0.0.4...0.0.6) - 2022-11-24
233
+ ## [0.0.6](https://github.com/Immugio/three-math-extensions/compare/0.0.5...0.0.6) - 2022-11-24
234
+
235
+ ## [0.0.5](https://github.com/Immugio/three-math-extensions/compare/0.0.4...0.0.5) - 2023-09-01
218
236
 
219
237
  ### Commits
220
238
 
239
+ - Generate documentation using TSDoc [`304c3a8`](https://github.com/Immugio/three-math-extensions/commit/304c3a84b5dcc49183db57083f550d134ae641b2)
240
+ - Add eslint [`98e4912`](https://github.com/Immugio/three-math-extensions/commit/98e4912d637b42ba80e2f3267638b43296113019)
241
+ - Update jest packages [`af23b4f`](https://github.com/Immugio/three-math-extensions/commit/af23b4f08154bba3407f05b773865215e7e1cba8)
242
+ - Add Rectangle, update Polygon [`58ee875`](https://github.com/Immugio/three-math-extensions/commit/58ee87539af8f9ade186e5250cba9e01926da514)
243
+ - Add isPointInPolygon [`a59eb4b`](https://github.com/Immugio/three-math-extensions/commit/a59eb4be026f17a3106070ae626a0588cd4f4411)
244
+ - Improve Line2D.closestPointToPoint, add Vec2.signedAngle [`151f214`](https://github.com/Immugio/three-math-extensions/commit/151f21462e0358057ad8e9d75d5782563a1061f6)
245
+ - Improve documentation [`d0fcb51`](https://github.com/Immugio/three-math-extensions/commit/d0fcb5132f127b4382ac5f7291575a061b8ec121)
246
+ - Vec3, Line3D - update documentation [`67d9c32`](https://github.com/Immugio/three-math-extensions/commit/67d9c328e08cc0a5599932d2f0529e97f31c9213)
247
+ - Add Polygon [`629cff8`](https://github.com/Immugio/three-math-extensions/commit/629cff8ecbb963477e8ea76d7f8b16d95435cbad)
221
248
  - Improve API, minor bug fix, improve test coverage [`881a5f0`](https://github.com/Immugio/three-math-extensions/commit/881a5f096823f0d5fd90faa76cd602f076291bc5)
249
+ - Line3D.groupConnectedLines added [`29f372b`](https://github.com/Immugio/three-math-extensions/commit/29f372bc984c06b00c50fcd9428ce9a7b9cab799)
250
+ - Dependencies update and remove now duplicate Vec2.angleTo implementation [`4774abb`](https://github.com/Immugio/three-math-extensions/commit/4774abb81d882082df0da606c79a3c7bd3aecc57)
251
+ - Line2D.isCloserToHorizontal [`b6f1429`](https://github.com/Immugio/three-math-extensions/commit/b6f14292d1d2765f7314c45e4c74be91280ac764)
252
+ - Add Vec2.angleTo and tests [`dcf1e53`](https://github.com/Immugio/three-math-extensions/commit/dcf1e531aecf8c115f323e14e5e44059e5c5d15c)
253
+ - Add Vec2.signedAngle [`863c8f2`](https://github.com/Immugio/three-math-extensions/commit/863c8f27f11288cbda535e21bb688206259269ed)
254
+ - Add intersect method to Line3D [`6fe47de`](https://github.com/Immugio/three-math-extensions/commit/6fe47de7caaa1807b47a4363e551510c463757d7)
255
+ - Add Line2D.extendToOrTrimAtIntersection [`ab82a36`](https://github.com/Immugio/three-math-extensions/commit/ab82a36db52b9ae83cf8bfb848362d295140d073)
256
+ - Add Vec2.fromPoints to accept multiple points [`a261402`](https://github.com/Immugio/three-math-extensions/commit/a2614027cf5fb8263189b48f7e0bb9a23a552c15)
257
+ - Improve documentation for Vec2 and Vec3 [`6a2373d`](https://github.com/Immugio/three-math-extensions/commit/6a2373d8b6754a87720dcaea5d98336bfa7bc5b5)
258
+ - Add Vec2.parallelTo [`989874d`](https://github.com/Immugio/three-math-extensions/commit/989874dcfe122d3ee84d8d56d79cb88e4e441736)
259
+ - Line2D.intersect - enable line segments intersection only [`1f1470e`](https://github.com/Immugio/three-math-extensions/commit/1f1470e1cf00118e643f5c44a135e0baf6b76d41)
260
+ - Line3D.groupConnectedLines now supports line breaks [`417a9ea`](https://github.com/Immugio/three-math-extensions/commit/417a9ea471bf4c539f73f5fb170c962a78ee4ab4)
261
+ - Add Line2D.projectOn [`4c52c5c`](https://github.com/Immugio/three-math-extensions/commit/4c52c5c2e649fbddb72ce3fca60cfd3f1319f72f)
262
+ - Added "isNear" to Vec2 & Vec3 as a shorthand for distanceTo <= maxDistance [`a27cff8`](https://github.com/Immugio/three-math-extensions/commit/a27cff8421472f625ed240439b9e6a7d2c430db8)
263
+ - Add Line3D.index [`7ed13d2`](https://github.com/Immugio/three-math-extensions/commit/7ed13d213748056c9dafd86288c3bcec9a28d1ba)
222
264
  - Add .npmignore [`f58329a`](https://github.com/Immugio/three-math-extensions/commit/f58329a86b96589bb574d6ebed37d4cc4474663a)
265
+ - Polygon from bounding size [`eae6701`](https://github.com/Immugio/three-math-extensions/commit/eae67012f57f426f8b5259b765000447ce06d608)
266
+ - Add Vec2 documentation [`f625e66`](https://github.com/Immugio/three-math-extensions/commit/f625e66b60ee0d90c5c788a80989f64013d60265)
267
+ - Clean up documentation [`70c8d5e`](https://github.com/Immugio/three-math-extensions/commit/70c8d5efe8b7095d7a03af637df3af5d46615293)
268
+ - Line2D and Line3D to return this instead of specific type [`761ef6a`](https://github.com/Immugio/three-math-extensions/commit/761ef6a9d8cc4e35120b666576794e521aa3b991)
269
+ - Line2D.in3DSpace added [`a6ce0ec`](https://github.com/Immugio/three-math-extensions/commit/a6ce0ecb67f5c7b2a75fcc283c28af626153a4af)
270
+ - Line3D.connectsTo added [`6d2cfa0`](https://github.com/Immugio/three-math-extensions/commit/6d2cfa0f5335c665f325a694a32c57b574ec326d)
271
+ - Line2D.hasIntersectionWithAngle to support optional tolerance [`b313bbe`](https://github.com/Immugio/three-math-extensions/commit/b313bbe118d435d53750deefd9a9e29ba6ec5c71)
272
+ - Add Vec2.moveTowards [`b46ba12`](https://github.com/Immugio/three-math-extensions/commit/b46ba1286f9924cd9bfecfb37200664202e964ba)
273
+ - Line2D.hasIntersectionWithAngle - modulo all angles [`5409aa0`](https://github.com/Immugio/three-math-extensions/commit/5409aa0bc41510efa86d548e91837e44e5b6c343)
274
+ - Use Vec2 instead of Vector2 [`7e6a6ea`](https://github.com/Immugio/three-math-extensions/commit/7e6a6ea272f4441ef4bc78b3fdec23fc783fa1db)
275
+ - Add release instructions into README.md [`03653b1`](https://github.com/Immugio/three-math-extensions/commit/03653b1ffa55be606d3f9cd588e28a6084462c2e)
276
+ - Documentation improvements [`160db8b`](https://github.com/Immugio/three-math-extensions/commit/160db8ba6d6e5eb63a4e91ed9c40efd6fa70181a)
277
+ - Update release instructions [`5b41a2e`](https://github.com/Immugio/three-math-extensions/commit/5b41a2ed7e15450dbb6088a7f7ed0031a013badc)
278
+ - Add Polygon to exports [`ed66775`](https://github.com/Immugio/three-math-extensions/commit/ed66775c33e961835b23843222b822cfd9c16b1d)
279
+ - Vec2.fromPoint and Vec3.fromPoint should accept null [`4b871af`](https://github.com/Immugio/three-math-extensions/commit/4b871af297bdcbe8584f1e2b99d602247b77687c)
280
+ - Documentation improvements [`2f3e676`](https://github.com/Immugio/three-math-extensions/commit/2f3e6768b3b0139b60688fc151a4084f15566f8d)
281
+ - Documentation update [`d5c7a07`](https://github.com/Immugio/three-math-extensions/commit/d5c7a0765f6097f5d3a3be01967d4059f19682fb)
282
+ - Fix peer dependency version [`00dd116`](https://github.com/Immugio/three-math-extensions/commit/00dd1169f578d5769207031fa625f29c96a38c31)
283
+ - Add Line2D.extendToOrTrimAtIntersection [`b22aa12`](https://github.com/Immugio/three-math-extensions/commit/b22aa120b5eb02562cebc4573374ebb61e2dba14)
223
284
  - Correct change log version [`c6244bf`](https://github.com/Immugio/three-math-extensions/commit/c6244bf1488ad21bcc5589d1dff62c41d8182d48)
224
285
  - Release 0.0.4 - tag pattern 6 [`c1c5454`](https://github.com/Immugio/three-math-extensions/commit/c1c54541ed400e1ad49bf42fe8926cd5293efefd)
225
286
  - Release 0.0.4 - tag pattern 5 [`5245eed`](https://github.com/Immugio/three-math-extensions/commit/5245eed60195103e989c0fadf9bd642f39ef4589)
287
+ - Excluded files from build [`ec70614`](https://github.com/Immugio/three-math-extensions/commit/ec70614bc7df7a98f854c7a6693365118e04faf7)
288
+ - Revert npm ignore [`590b26a`](https://github.com/Immugio/three-math-extensions/commit/590b26a9e57fc41466b51e711f3f5c648e2d56ed)
226
289
 
227
290
  ## 0.0.4 - 2022-11-21
228
291
 
package/cjs/Line2D.js CHANGED
@@ -580,6 +580,51 @@ class Line2D {
580
580
  get isCloserToVertical() {
581
581
  return !this.isCloserToHorizontal;
582
582
  }
583
+ /**
584
+ * Accepts an array of Line2D and groups them into arrays of connected lines
585
+ * @param lines Lines to be grouped
586
+ * @param tolerance Tolerance for considering lines as connected
587
+ * @param breakpoints
588
+ */
589
+ static groupConnectedLines(lines, tolerance = 0, breakpoints = []) {
590
+ const visited = new Set();
591
+ // Use graph-based approach. Each line can be considered as an edge in the graph, and the endpoints of the lines can be considered as vertices.
592
+ // Then use Depth-First Search (DFS) to find connected components in the graph.
593
+ const dfs = (line, group) => {
594
+ if (visited.has(line))
595
+ return;
596
+ visited.add(line);
597
+ group.push(line);
598
+ lines.forEach((neighbor) => {
599
+ if (!visited.has(neighbor)) {
600
+ if (line.connectsTo(neighbor, tolerance, breakpoints)) {
601
+ dfs(neighbor, group);
602
+ }
603
+ }
604
+ });
605
+ };
606
+ const connectedLines = [];
607
+ lines.forEach((line) => {
608
+ if (!visited.has(line)) {
609
+ const group = [];
610
+ dfs(line, group);
611
+ connectedLines.push(group);
612
+ }
613
+ });
614
+ return connectedLines;
615
+ }
616
+ /**
617
+ * Returns true if any endpoint of this line is within the tolerance of any @other line's endpoints.
618
+ * @param other
619
+ * @param tolerance
620
+ * @param breakpoints
621
+ */
622
+ connectsTo(other, tolerance = 0, breakpoints = []) {
623
+ return ((this.start.isNear(other.start, tolerance) && breakpoints.every(b => !b.isNear(this.start, tolerance))) ||
624
+ (this.start.isNear(other.end, tolerance) && breakpoints.every(b => !b.isNear(this.start, tolerance))) ||
625
+ (this.end.isNear(other.start, tolerance) && breakpoints.every(b => !b.isNear(this.end, tolerance))) ||
626
+ (this.end.isNear(other.end, tolerance) && breakpoints.every(b => !b.isNear(this.end, tolerance))));
627
+ }
583
628
  /**
584
629
  * Project the line to 2D space. For start and end points Vec2.y becomes Vec3.z. and Vec3.y is provided as an argument.
585
630
  * @param y - The y value of the new Vec3 instance.
package/cjs/Line3D.js CHANGED
@@ -371,8 +371,8 @@ class Line3D extends three_1.Line3 {
371
371
  }
372
372
  /**
373
373
  * Calculates the intersection between this and `other` line. The lines are assumed to be infinite.
374
- * In a lot of cases an actual intersection cannot be calculated due to rounding errors.
375
- * Therefore, the intersection calculated by this method comes in a form of the shorted possible line segment connecting the two lines.
374
+ * In a lot of cases, an actual intersection cannot be calculated due to rounding errors.
375
+ * Therefore, the intersection calculated by this method comes in the form of the shorted possible line segment connecting the two lines.
376
376
  * Sources:
377
377
  * http://paulbourke.net/geometry/pointlineplane/
378
378
  * https://stackoverflow.com/questions/2316490/the-algorithm-to-find-the-point-of-intersection-of-two-3d-line-segment/2316934#2316934
@@ -412,8 +412,9 @@ class Line3D extends three_1.Line3 {
412
412
  * Accepts an array of Line3D and groups them into arrays of connected lines
413
413
  * @param lines Lines to be grouped
414
414
  * @param tolerance Tolerance for considering lines as connected
415
+ * @param breakpoints
415
416
  */
416
- static groupConnectedLines(lines, tolerance = 0) {
417
+ static groupConnectedLines(lines, tolerance = 0, breakpoints = []) {
417
418
  const visited = new Set();
418
419
  // Use graph-based approach. Each line can be considered as an edge in the graph, and the endpoints of the lines can be considered as vertices.
419
420
  // Then use Depth-First Search (DFS) to find connected components in the graph.
@@ -424,7 +425,7 @@ class Line3D extends three_1.Line3 {
424
425
  group.push(line);
425
426
  lines.forEach((neighbor) => {
426
427
  if (!visited.has(neighbor)) {
427
- if (line.connectsTo(neighbor, tolerance)) {
428
+ if (line.connectsTo(neighbor, tolerance, breakpoints)) {
428
429
  dfs(neighbor, group);
429
430
  }
430
431
  }
@@ -441,15 +442,16 @@ class Line3D extends three_1.Line3 {
441
442
  return connectedLines;
442
443
  }
443
444
  /**
444
- * Returns true if any endpoint of this line if within the tolerance distance of any endpoint of the @other line.
445
+ * Returns true if any endpoint of this line is within the tolerance of any @other line's endpoints.
445
446
  * @param other
446
447
  * @param tolerance
448
+ * @param breakpoints
447
449
  */
448
- connectsTo(other, tolerance = 0) {
449
- return this.start.isNear(other.start, tolerance) ||
450
- this.start.isNear(other.end, tolerance) ||
451
- this.end.isNear(other.start, tolerance) ||
452
- this.end.isNear(other.end, tolerance);
450
+ connectsTo(other, tolerance = 0, breakpoints = []) {
451
+ return ((this.start.isNear(other.start, tolerance) && breakpoints.every(b => !b.isNear(this.start, tolerance))) ||
452
+ (this.start.isNear(other.end, tolerance) && breakpoints.every(b => !b.isNear(this.start, tolerance))) ||
453
+ (this.end.isNear(other.start, tolerance) && breakpoints.every(b => !b.isNear(this.end, tolerance))) ||
454
+ (this.end.isNear(other.end, tolerance) && breakpoints.every(b => !b.isNear(this.end, tolerance))));
453
455
  }
454
456
  /**
455
457
  * Project the line to 2D space, Y value is dropped
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TwoPI = void 0;
3
+ exports.HalfPI = exports.TwoPI = void 0;
4
4
  exports.TwoPI = 2 * Math.PI;
5
+ exports.HalfPI = Math.PI / 2;
package/cjs/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.directions2d = exports.directions = exports.isPointInPolygon = exports.TwoPI = exports.normalizeAngleRadians = exports.normalizeAngleDegrees = exports.Rectangle = exports.BoundingBox = exports.Polygon = exports.Size2 = exports.Line3D = exports.Line2D = exports.Vec3 = exports.Vec2 = void 0;
3
+ exports.isContinuousClosedShape = exports.directions2d = exports.directions = exports.isPointInPolygon = exports.HalfPI = exports.TwoPI = exports.normalizeAngleRadians = exports.normalizeAngleDegrees = exports.Rectangle = exports.BoundingBox = exports.Polygon = exports.Size2 = exports.Line3D = exports.Line2D = exports.Vec3 = exports.Vec2 = void 0;
4
4
  var Vec2_1 = require("./Vec2");
5
5
  Object.defineProperty(exports, "Vec2", { enumerable: true, get: function () { return Vec2_1.Vec2; } });
6
6
  var Vec3_1 = require("./Vec3");
@@ -23,9 +23,12 @@ var normalizeAngleRadians_1 = require("./normalizeAngleRadians");
23
23
  Object.defineProperty(exports, "normalizeAngleRadians", { enumerable: true, get: function () { return normalizeAngleRadians_1.normalizeAngleRadians; } });
24
24
  var MathConstants_1 = require("./MathConstants");
25
25
  Object.defineProperty(exports, "TwoPI", { enumerable: true, get: function () { return MathConstants_1.TwoPI; } });
26
+ Object.defineProperty(exports, "HalfPI", { enumerable: true, get: function () { return MathConstants_1.HalfPI; } });
26
27
  var isPointInPolygon_1 = require("./isPointInPolygon");
27
28
  Object.defineProperty(exports, "isPointInPolygon", { enumerable: true, get: function () { return isPointInPolygon_1.isPointInPolygon; } });
28
29
  var directions_1 = require("./directions");
29
30
  Object.defineProperty(exports, "directions", { enumerable: true, get: function () { return directions_1.directions; } });
30
31
  var directions2d_1 = require("./directions2d");
31
32
  Object.defineProperty(exports, "directions2d", { enumerable: true, get: function () { return directions2d_1.directions2d; } });
33
+ var isContinuousClosedShape_1 = require("./isContinuousClosedShape");
34
+ Object.defineProperty(exports, "isContinuousClosedShape", { enumerable: true, get: function () { return isContinuousClosedShape_1.isContinuousClosedShape; } });
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isContinuousClosedShape = void 0;
4
+ function isContinuousClosedShape(lines, tolerance = 0) {
5
+ if (lines.length < 3) {
6
+ return false; // A shape needs at least 3 lines to be closed
7
+ }
8
+ // Starting from the first line, check if the end of the current line is the start of the next line
9
+ for (let i = 0; i < lines.length - 1; i++) {
10
+ const endCurrent = lines[i].end;
11
+ const startNext = lines[i + 1].start;
12
+ if (!endCurrent.isNear(startNext, tolerance)) {
13
+ return false; // If the end of the current line and start of the next line are not close, return false
14
+ }
15
+ }
16
+ // Lastly, we should check the end of the last line with the start of the first line
17
+ const endLast = lines[lines.length - 1].end;
18
+ const startFirst = lines[0].start;
19
+ return endLast.isNear(startFirst, tolerance);
20
+ }
21
+ exports.isContinuousClosedShape = isContinuousClosedShape;
package/esm/Line2D.js CHANGED
@@ -577,6 +577,51 @@ export class Line2D {
577
577
  get isCloserToVertical() {
578
578
  return !this.isCloserToHorizontal;
579
579
  }
580
+ /**
581
+ * Accepts an array of Line2D and groups them into arrays of connected lines
582
+ * @param lines Lines to be grouped
583
+ * @param tolerance Tolerance for considering lines as connected
584
+ * @param breakpoints
585
+ */
586
+ static groupConnectedLines(lines, tolerance = 0, breakpoints = []) {
587
+ const visited = new Set();
588
+ // Use graph-based approach. Each line can be considered as an edge in the graph, and the endpoints of the lines can be considered as vertices.
589
+ // Then use Depth-First Search (DFS) to find connected components in the graph.
590
+ const dfs = (line, group) => {
591
+ if (visited.has(line))
592
+ return;
593
+ visited.add(line);
594
+ group.push(line);
595
+ lines.forEach((neighbor) => {
596
+ if (!visited.has(neighbor)) {
597
+ if (line.connectsTo(neighbor, tolerance, breakpoints)) {
598
+ dfs(neighbor, group);
599
+ }
600
+ }
601
+ });
602
+ };
603
+ const connectedLines = [];
604
+ lines.forEach((line) => {
605
+ if (!visited.has(line)) {
606
+ const group = [];
607
+ dfs(line, group);
608
+ connectedLines.push(group);
609
+ }
610
+ });
611
+ return connectedLines;
612
+ }
613
+ /**
614
+ * Returns true if any endpoint of this line is within the tolerance of any @other line's endpoints.
615
+ * @param other
616
+ * @param tolerance
617
+ * @param breakpoints
618
+ */
619
+ connectsTo(other, tolerance = 0, breakpoints = []) {
620
+ return ((this.start.isNear(other.start, tolerance) && breakpoints.every(b => !b.isNear(this.start, tolerance))) ||
621
+ (this.start.isNear(other.end, tolerance) && breakpoints.every(b => !b.isNear(this.start, tolerance))) ||
622
+ (this.end.isNear(other.start, tolerance) && breakpoints.every(b => !b.isNear(this.end, tolerance))) ||
623
+ (this.end.isNear(other.end, tolerance) && breakpoints.every(b => !b.isNear(this.end, tolerance))));
624
+ }
580
625
  /**
581
626
  * Project the line to 2D space. For start and end points Vec2.y becomes Vec3.z. and Vec3.y is provided as an argument.
582
627
  * @param y - The y value of the new Vec3 instance.
package/esm/Line3D.js CHANGED
@@ -368,8 +368,8 @@ export class Line3D extends Line3 {
368
368
  }
369
369
  /**
370
370
  * Calculates the intersection between this and `other` line. The lines are assumed to be infinite.
371
- * In a lot of cases an actual intersection cannot be calculated due to rounding errors.
372
- * Therefore, the intersection calculated by this method comes in a form of the shorted possible line segment connecting the two lines.
371
+ * In a lot of cases, an actual intersection cannot be calculated due to rounding errors.
372
+ * Therefore, the intersection calculated by this method comes in the form of the shorted possible line segment connecting the two lines.
373
373
  * Sources:
374
374
  * http://paulbourke.net/geometry/pointlineplane/
375
375
  * https://stackoverflow.com/questions/2316490/the-algorithm-to-find-the-point-of-intersection-of-two-3d-line-segment/2316934#2316934
@@ -409,8 +409,9 @@ export class Line3D extends Line3 {
409
409
  * Accepts an array of Line3D and groups them into arrays of connected lines
410
410
  * @param lines Lines to be grouped
411
411
  * @param tolerance Tolerance for considering lines as connected
412
+ * @param breakpoints
412
413
  */
413
- static groupConnectedLines(lines, tolerance = 0) {
414
+ static groupConnectedLines(lines, tolerance = 0, breakpoints = []) {
414
415
  const visited = new Set();
415
416
  // Use graph-based approach. Each line can be considered as an edge in the graph, and the endpoints of the lines can be considered as vertices.
416
417
  // Then use Depth-First Search (DFS) to find connected components in the graph.
@@ -421,7 +422,7 @@ export class Line3D extends Line3 {
421
422
  group.push(line);
422
423
  lines.forEach((neighbor) => {
423
424
  if (!visited.has(neighbor)) {
424
- if (line.connectsTo(neighbor, tolerance)) {
425
+ if (line.connectsTo(neighbor, tolerance, breakpoints)) {
425
426
  dfs(neighbor, group);
426
427
  }
427
428
  }
@@ -438,15 +439,16 @@ export class Line3D extends Line3 {
438
439
  return connectedLines;
439
440
  }
440
441
  /**
441
- * Returns true if any endpoint of this line if within the tolerance distance of any endpoint of the @other line.
442
+ * Returns true if any endpoint of this line is within the tolerance of any @other line's endpoints.
442
443
  * @param other
443
444
  * @param tolerance
445
+ * @param breakpoints
444
446
  */
445
- connectsTo(other, tolerance = 0) {
446
- return this.start.isNear(other.start, tolerance) ||
447
- this.start.isNear(other.end, tolerance) ||
448
- this.end.isNear(other.start, tolerance) ||
449
- this.end.isNear(other.end, tolerance);
447
+ connectsTo(other, tolerance = 0, breakpoints = []) {
448
+ return ((this.start.isNear(other.start, tolerance) && breakpoints.every(b => !b.isNear(this.start, tolerance))) ||
449
+ (this.start.isNear(other.end, tolerance) && breakpoints.every(b => !b.isNear(this.start, tolerance))) ||
450
+ (this.end.isNear(other.start, tolerance) && breakpoints.every(b => !b.isNear(this.end, tolerance))) ||
451
+ (this.end.isNear(other.end, tolerance) && breakpoints.every(b => !b.isNear(this.end, tolerance))));
450
452
  }
451
453
  /**
452
454
  * Project the line to 2D space, Y value is dropped
@@ -1 +1,2 @@
1
1
  export const TwoPI = 2 * Math.PI;
2
+ export const HalfPI = Math.PI / 2;
package/esm/index.js CHANGED
@@ -8,7 +8,8 @@ export { BoundingBox } from "./BoundingBox";
8
8
  export { Rectangle } from "./Rectangle";
9
9
  export { normalizeAngleDegrees } from "./normalizeAngleDegrees";
10
10
  export { normalizeAngleRadians } from "./normalizeAngleRadians";
11
- export { TwoPI } from "./MathConstants";
11
+ export { TwoPI, HalfPI } from "./MathConstants";
12
12
  export { isPointInPolygon } from "./isPointInPolygon";
13
13
  export { directions } from "./directions";
14
14
  export { directions2d } from "./directions2d";
15
+ export { isContinuousClosedShape } from "./isContinuousClosedShape";
@@ -0,0 +1,17 @@
1
+ export function isContinuousClosedShape(lines, tolerance = 0) {
2
+ if (lines.length < 3) {
3
+ return false; // A shape needs at least 3 lines to be closed
4
+ }
5
+ // Starting from the first line, check if the end of the current line is the start of the next line
6
+ for (let i = 0; i < lines.length - 1; i++) {
7
+ const endCurrent = lines[i].end;
8
+ const startNext = lines[i + 1].start;
9
+ if (!endCurrent.isNear(startNext, tolerance)) {
10
+ return false; // If the end of the current line and start of the next line are not close, return false
11
+ }
12
+ }
13
+ // Lastly, we should check the end of the last line with the start of the first line
14
+ const endLast = lines[lines.length - 1].end;
15
+ const startFirst = lines[0].start;
16
+ return endLast.isNear(startFirst, tolerance);
17
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@immugio/three-math-extensions",
3
- "version": "0.2.13",
3
+ "version": "0.2.15",
4
4
  "description": "Set of utilities for 2d and 3d line math built on top of three.js",
5
5
  "author": "Jan Mikeska <janmikeska@gmail.com>",
6
6
  "license": "ISC",
@@ -33,18 +33,18 @@
33
33
  "postversion": "git push && git push --tags"
34
34
  },
35
35
  "devDependencies": {
36
- "@types/jest": "^29.5.4",
37
- "@types/offscreencanvas": "2019.7.0",
36
+ "@types/jest": "^29.5.5",
37
+ "@types/offscreencanvas": "2019.7.1",
38
38
  "@types/three": "0.152.0",
39
- "@typescript-eslint/eslint-plugin": "^6.5.0",
39
+ "@typescript-eslint/eslint-plugin": "^6.7.5",
40
40
  "auto-changelog": "^2.4.0",
41
- "jest": "^29.6.4",
42
- "rimraf": "^3.0.2",
43
- "ts-jest": "^29.0.0",
44
- "typedoc": "^0.23.23",
45
- "typedoc-plugin-markdown": "^3.14.0",
46
- "typescript": "4.9.5",
47
- "eslint": "^8.48.0"
41
+ "jest": "^29.7.0",
42
+ "rimraf": "^5.0.5",
43
+ "ts-jest": "^29.1.1",
44
+ "typedoc": "^0.25.2",
45
+ "typedoc-plugin-markdown": "^3.16.0",
46
+ "typescript": "5.2.2",
47
+ "eslint": "^8.51.0"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "three": "0.152.2"
package/src/Line2D.ts CHANGED
@@ -682,6 +682,61 @@ export class Line2D {
682
682
  return !this.isCloserToHorizontal;
683
683
  }
684
684
 
685
+ /**
686
+ * Accepts an array of Line2D and groups them into arrays of connected lines
687
+ * @param lines Lines to be grouped
688
+ * @param tolerance Tolerance for considering lines as connected
689
+ * @param breakpoints
690
+ */
691
+ public static groupConnectedLines(lines: Line2D[], tolerance: number = 0, breakpoints: Vec2[] = []): Line2D[][] {
692
+ const visited: Set<Line2D> = new Set();
693
+
694
+ // Use graph-based approach. Each line can be considered as an edge in the graph, and the endpoints of the lines can be considered as vertices.
695
+ // Then use Depth-First Search (DFS) to find connected components in the graph.
696
+ const dfs = (line: Line2D, group: Line2D[]) => {
697
+ if (visited.has(line)) return;
698
+ visited.add(line);
699
+ group.push(line);
700
+
701
+ lines.forEach((neighbor) => {
702
+ if (!visited.has(neighbor)) {
703
+ if (
704
+ line.connectsTo(neighbor, tolerance, breakpoints)
705
+ ) {
706
+ dfs(neighbor, group);
707
+ }
708
+ }
709
+ });
710
+ };
711
+
712
+ const connectedLines: Line2D[][] = [];
713
+
714
+ lines.forEach((line) => {
715
+ if (!visited.has(line)) {
716
+ const group: Line2D[] = [];
717
+ dfs(line, group);
718
+ connectedLines.push(group);
719
+ }
720
+ });
721
+
722
+ return connectedLines;
723
+ }
724
+
725
+ /**
726
+ * Returns true if any endpoint of this line is within the tolerance of any @other line's endpoints.
727
+ * @param other
728
+ * @param tolerance
729
+ * @param breakpoints
730
+ */
731
+ public connectsTo(other: Line2D, tolerance: number = 0, breakpoints: typeof other.start[] = []): boolean {
732
+ return (
733
+ (this.start.isNear(other.start, tolerance) && breakpoints.every(b => !b.isNear(this.start, tolerance))) ||
734
+ (this.start.isNear(other.end, tolerance) && breakpoints.every(b => !b.isNear(this.start, tolerance))) ||
735
+ (this.end.isNear(other.start, tolerance) && breakpoints.every(b => !b.isNear(this.end, tolerance))) ||
736
+ (this.end.isNear(other.end, tolerance) && breakpoints.every(b => !b.isNear(this.end, tolerance)))
737
+ );
738
+ }
739
+
685
740
  /**
686
741
  * Project the line to 2D space. For start and end points Vec2.y becomes Vec3.z. and Vec3.y is provided as an argument.
687
742
  * @param y - The y value of the new Vec3 instance.
package/src/Line3D.ts CHANGED
@@ -446,8 +446,8 @@ export class Line3D extends Line3 {
446
446
 
447
447
  /**
448
448
  * Calculates the intersection between this and `other` line. The lines are assumed to be infinite.
449
- * In a lot of cases an actual intersection cannot be calculated due to rounding errors.
450
- * Therefore, the intersection calculated by this method comes in a form of the shorted possible line segment connecting the two lines.
449
+ * In a lot of cases, an actual intersection cannot be calculated due to rounding errors.
450
+ * Therefore, the intersection calculated by this method comes in the form of the shorted possible line segment connecting the two lines.
451
451
  * Sources:
452
452
  * http://paulbourke.net/geometry/pointlineplane/
453
453
  * https://stackoverflow.com/questions/2316490/the-algorithm-to-find-the-point-of-intersection-of-two-3d-line-segment/2316934#2316934
@@ -506,8 +506,9 @@ export class Line3D extends Line3 {
506
506
  * Accepts an array of Line3D and groups them into arrays of connected lines
507
507
  * @param lines Lines to be grouped
508
508
  * @param tolerance Tolerance for considering lines as connected
509
+ * @param breakpoints
509
510
  */
510
- public static groupConnectedLines(lines: Line3D[], tolerance: number = 0): Line3D[][] {
511
+ public static groupConnectedLines(lines: Line3D[], tolerance: number = 0, breakpoints: Vec3[] = []): Line3D[][] {
511
512
  const visited: Set<Line3D> = new Set();
512
513
 
513
514
  // Use graph-based approach. Each line can be considered as an edge in the graph, and the endpoints of the lines can be considered as vertices.
@@ -520,7 +521,7 @@ export class Line3D extends Line3 {
520
521
  lines.forEach((neighbor) => {
521
522
  if (!visited.has(neighbor)) {
522
523
  if (
523
- line.connectsTo(neighbor, tolerance)
524
+ line.connectsTo(neighbor, tolerance, breakpoints)
524
525
  ) {
525
526
  dfs(neighbor, group);
526
527
  }
@@ -542,15 +543,18 @@ export class Line3D extends Line3 {
542
543
  }
543
544
 
544
545
  /**
545
- * Returns true if any endpoint of this line if within the tolerance distance of any endpoint of the @other line.
546
+ * Returns true if any endpoint of this line is within the tolerance of any @other line's endpoints.
546
547
  * @param other
547
548
  * @param tolerance
549
+ * @param breakpoints
548
550
  */
549
- public connectsTo(other: Line3D, tolerance: number = 0): boolean {
550
- return this.start.isNear(other.start, tolerance) ||
551
- this.start.isNear(other.end, tolerance) ||
552
- this.end.isNear(other.start, tolerance) ||
553
- this.end.isNear(other.end, tolerance);
551
+ public connectsTo(other: Line3D, tolerance: number = 0, breakpoints: Vec3[] = []): boolean {
552
+ return (
553
+ (this.start.isNear(other.start, tolerance) && breakpoints.every(b => !b.isNear(this.start, tolerance))) ||
554
+ (this.start.isNear(other.end, tolerance) && breakpoints.every(b => !b.isNear(this.start, tolerance))) ||
555
+ (this.end.isNear(other.start, tolerance) && breakpoints.every(b => !b.isNear(this.end, tolerance))) ||
556
+ (this.end.isNear(other.end, tolerance) && breakpoints.every(b => !b.isNear(this.end, tolerance)))
557
+ );
554
558
  }
555
559
 
556
560
  /**
@@ -1 +1,2 @@
1
- export const TwoPI = 2 * Math.PI;
1
+ export const TwoPI = 2 * Math.PI;
2
+ export const HalfPI = Math.PI / 2;
package/src/index.ts CHANGED
@@ -8,9 +8,10 @@ export { BoundingBox } from "./BoundingBox";
8
8
  export { Rectangle } from "./Rectangle";
9
9
  export { normalizeAngleDegrees } from "./normalizeAngleDegrees";
10
10
  export { normalizeAngleRadians } from "./normalizeAngleRadians";
11
- export { TwoPI } from "./MathConstants";
11
+ export { TwoPI, HalfPI } from "./MathConstants";
12
12
  export { Point2 } from "./Point2";
13
13
  export { Point3 } from "./Point3";
14
14
  export { isPointInPolygon } from "./isPointInPolygon";
15
15
  export { directions } from "./directions";
16
- export { directions2d } from "./directions2d";
16
+ export { directions2d } from "./directions2d";
17
+ export { isContinuousClosedShape } from "./isContinuousClosedShape";
@@ -0,0 +1,24 @@
1
+ import { Line3D } from "./Line3D";
2
+ import { Line2D } from "./Line2D";
3
+
4
+ export function isContinuousClosedShape<T extends Line2D | Line3D>(lines: T[], tolerance: number = 0): boolean {
5
+ if (lines.length < 3) {
6
+ return false; // A shape needs at least 3 lines to be closed
7
+ }
8
+
9
+ // Starting from the first line, check if the end of the current line is the start of the next line
10
+ for (let i = 0; i < lines.length - 1; i++) {
11
+ const endCurrent = lines[i].end;
12
+ const startNext = lines[i + 1].start;
13
+
14
+ if (!endCurrent.isNear(startNext as any, tolerance)) {
15
+ return false; // If the end of the current line and start of the next line are not close, return false
16
+ }
17
+ }
18
+
19
+ // Lastly, we should check the end of the last line with the start of the first line
20
+ const endLast = lines[lines.length - 1].end;
21
+ const startFirst = lines[0].start;
22
+
23
+ return endLast.isNear(startFirst as any, tolerance);
24
+ }
package/types/Line2D.d.ts CHANGED
@@ -220,6 +220,20 @@ export declare class Line2D {
220
220
  hasIntersectionWithAngle(other: Line2D, expectedAngleInRads: number, angleTolerance?: number, distanceTolerance?: number): Vec2;
221
221
  get isCloserToHorizontal(): boolean;
222
222
  get isCloserToVertical(): boolean;
223
+ /**
224
+ * Accepts an array of Line2D and groups them into arrays of connected lines
225
+ * @param lines Lines to be grouped
226
+ * @param tolerance Tolerance for considering lines as connected
227
+ * @param breakpoints
228
+ */
229
+ static groupConnectedLines(lines: Line2D[], tolerance?: number, breakpoints?: Vec2[]): Line2D[][];
230
+ /**
231
+ * Returns true if any endpoint of this line is within the tolerance of any @other line's endpoints.
232
+ * @param other
233
+ * @param tolerance
234
+ * @param breakpoints
235
+ */
236
+ connectsTo(other: Line2D, tolerance?: number, breakpoints?: typeof other.start[]): boolean;
223
237
  /**
224
238
  * Project the line to 2D space. For start and end points Vec2.y becomes Vec3.z. and Vec3.y is provided as an argument.
225
239
  * @param y - The y value of the new Vec3 instance.
package/types/Line3D.d.ts CHANGED
@@ -138,8 +138,8 @@ export declare class Line3D extends Line3 {
138
138
  translate(p: Vector3): this;
139
139
  /**
140
140
  * Calculates the intersection between this and `other` line. The lines are assumed to be infinite.
141
- * In a lot of cases an actual intersection cannot be calculated due to rounding errors.
142
- * Therefore, the intersection calculated by this method comes in a form of the shorted possible line segment connecting the two lines.
141
+ * In a lot of cases, an actual intersection cannot be calculated due to rounding errors.
142
+ * Therefore, the intersection calculated by this method comes in the form of the shorted possible line segment connecting the two lines.
143
143
  * Sources:
144
144
  * http://paulbourke.net/geometry/pointlineplane/
145
145
  * https://stackoverflow.com/questions/2316490/the-algorithm-to-find-the-point-of-intersection-of-two-3d-line-segment/2316934#2316934
@@ -150,14 +150,16 @@ export declare class Line3D extends Line3 {
150
150
  * Accepts an array of Line3D and groups them into arrays of connected lines
151
151
  * @param lines Lines to be grouped
152
152
  * @param tolerance Tolerance for considering lines as connected
153
+ * @param breakpoints
153
154
  */
154
- static groupConnectedLines(lines: Line3D[], tolerance?: number): Line3D[][];
155
+ static groupConnectedLines(lines: Line3D[], tolerance?: number, breakpoints?: Vec3[]): Line3D[][];
155
156
  /**
156
- * Returns true if any endpoint of this line if within the tolerance distance of any endpoint of the @other line.
157
+ * Returns true if any endpoint of this line is within the tolerance of any @other line's endpoints.
157
158
  * @param other
158
159
  * @param tolerance
160
+ * @param breakpoints
159
161
  */
160
- connectsTo(other: Line3D, tolerance?: number): boolean;
162
+ connectsTo(other: Line3D, tolerance?: number, breakpoints?: Vec3[]): boolean;
161
163
  /**
162
164
  * Project the line to 2D space, Y value is dropped
163
165
  */
@@ -1 +1,2 @@
1
1
  export declare const TwoPI: number;
2
+ export declare const HalfPI: number;
package/types/index.d.ts CHANGED
@@ -8,9 +8,10 @@ export { BoundingBox } from "./BoundingBox";
8
8
  export { Rectangle } from "./Rectangle";
9
9
  export { normalizeAngleDegrees } from "./normalizeAngleDegrees";
10
10
  export { normalizeAngleRadians } from "./normalizeAngleRadians";
11
- export { TwoPI } from "./MathConstants";
11
+ export { TwoPI, HalfPI } from "./MathConstants";
12
12
  export { Point2 } from "./Point2";
13
13
  export { Point3 } from "./Point3";
14
14
  export { isPointInPolygon } from "./isPointInPolygon";
15
15
  export { directions } from "./directions";
16
16
  export { directions2d } from "./directions2d";
17
+ export { isContinuousClosedShape } from "./isContinuousClosedShape";
@@ -0,0 +1,3 @@
1
+ import { Line3D } from "./Line3D";
2
+ import { Line2D } from "./Line2D";
3
+ export declare function isContinuousClosedShape<T extends Line2D | Line3D>(lines: T[], tolerance?: number): boolean;