@immugio/three-math-extensions 0.2.14 → 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.14](https://github.com/Immugio/three-math-extensions/compare/16.15.10...0.2.14)
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)
@@ -40,10 +42,17 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
40
42
  - Update release instructions [`5b41a2e`](https://github.com/Immugio/three-math-extensions/commit/5b41a2ed7e15450dbb6088a7f7ed0031a013badc)
41
43
  - Add Polygon to exports [`ed66775`](https://github.com/Immugio/three-math-extensions/commit/ed66775c33e961835b23843222b822cfd9c16b1d)
42
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)
43
46
  - Documentation update [`d5c7a07`](https://github.com/Immugio/three-math-extensions/commit/d5c7a0765f6097f5d3a3be01967d4059f19682fb)
44
47
  - Excluded files from build [`ec70614`](https://github.com/Immugio/three-math-extensions/commit/ec70614bc7df7a98f854c7a6693365118e04faf7)
45
48
 
46
- ## [16.15.10](https://github.com/Immugio/three-math-extensions/compare/0.2.13...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)
47
56
 
48
57
  ## [0.2.13](https://github.com/Immugio/three-math-extensions/compare/0.2.12...0.2.13) - 2023-08-31
49
58
 
@@ -221,15 +230,62 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
221
230
 
222
231
  ## [0.0.7](https://github.com/Immugio/three-math-extensions/compare/0.0.6...0.0.7) - 2022-11-21
223
232
 
224
- ## [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
225
236
 
226
237
  ### Commits
227
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)
228
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)
229
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)
230
284
  - Correct change log version [`c6244bf`](https://github.com/Immugio/three-math-extensions/commit/c6244bf1488ad21bcc5589d1dff62c41d8182d48)
231
285
  - Release 0.0.4 - tag pattern 6 [`c1c5454`](https://github.com/Immugio/three-math-extensions/commit/c1c54541ed400e1ad49bf42fe8926cd5293efefd)
232
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)
233
289
 
234
290
  ## 0.0.4 - 2022-11-21
235
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
@@ -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
@@ -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.14",
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
@@ -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
@@ -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;