@immugio/three-math-extensions 0.3.0 → 0.3.2

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,7 +7,27 @@ 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.3.0](https://github.com/Immugio/three-math-extensions/compare/0.2.38...0.3.0)
10
+ ## [0.3.2](https://github.com/Immugio/three-math-extensions/compare/0.3.1...0.3.2)
11
+
12
+ ### Merged
13
+
14
+ - Update GitHub Actions to latest versions [`#5`](https://github.com/Immugio/three-math-extensions/pull/5)
15
+
16
+ ## [0.3.1](https://github.com/Immugio/three-math-extensions/compare/0.3.0...0.3.1) - 2025-11-20
17
+
18
+ ### Merged
19
+
20
+ - GitHub Actions - Update workflow to Node 20.x [`#4`](https://github.com/Immugio/three-math-extensions/pull/4)
21
+ - Line2D.spec.ts - Split tests into individual test files per method being tested [`#3`](https://github.com/Immugio/three-math-extensions/pull/3)
22
+
23
+ ### Commits
24
+
25
+ - Update eslint and fix linting errors [`718ec97`](https://github.com/Immugio/three-math-extensions/commit/718ec978cf0d79cba66f87ac2978007860edfb34)
26
+ - Improve Line2D.joinLines robustness [`a17fd31`](https://github.com/Immugio/three-math-extensions/commit/a17fd3107768e99deb561131581822079bdab2b1)
27
+ - Update isContinuousClosedShape types to avoid using any [`25028b7`](https://github.com/Immugio/three-math-extensions/commit/25028b7ee7b389edaae2c04493e775fd685e4a22)
28
+ - Fix isContinuousClosedShape signature for compatibility with Line2D and Line3D [`1d569e7`](https://github.com/Immugio/three-math-extensions/commit/1d569e7b0a7ba5f92eef1ce2493589fe2a080847)
29
+
30
+ ## [0.3.0](https://github.com/Immugio/three-math-extensions/compare/0.2.38...0.3.0) - 2024-12-11
11
31
 
12
32
  ### Commits
13
33
 
package/cjs/Line2D.js CHANGED
@@ -250,7 +250,7 @@ class Line2D {
250
250
  */
251
251
  isPointBesideLineSection(point) {
252
252
  const l2 = (((this.end.x - this.start.x) * (this.end.x - this.start.x)) + ((this.end.y - this.start.y) * (this.end.y - this.start.y)));
253
- if (l2 == 0)
253
+ if (l2 === 0)
254
254
  return false;
255
255
  const r = (((point.x - this.start.x) * (this.end.x - this.start.x)) + ((point.y - this.start.y) * (this.end.y - this.start.y))) / l2;
256
256
  return (0 <= r) && (r <= 1);
@@ -353,23 +353,27 @@ class Line2D {
353
353
  if (lines.length < 2) {
354
354
  return lines.map(x => x.clone());
355
355
  }
356
- const toProcess = lines.slice();
357
- const result = [];
358
- while (toProcess.length > 0) {
359
- const current = toProcess.pop();
360
- let joined = false;
356
+ // Start with cloned lines as initial result
357
+ const result = lines.map(x => x.clone());
358
+ // Keep trying to join lines until no more joins are possible
359
+ let joinedInLastPass = true;
360
+ while (joinedInLastPass) {
361
+ joinedInLastPass = false;
362
+ // Try to join each pair of lines
361
363
  for (let i = 0; i < result.length; i++) {
362
- const other = result[i];
363
- const joinedLine = Line2D.joinLine(current, other);
364
- if (joinedLine) {
365
- result[i] = joinedLine;
366
- joined = true;
367
- break;
364
+ for (let j = i + 1; j < result.length; j++) {
365
+ const joinedLine = Line2D.joinLine(result[i], result[j]);
366
+ if (joinedLine) {
367
+ // Replace the first line with the joined line and remove the second
368
+ result[i] = joinedLine;
369
+ result.splice(j, 1);
370
+ joinedInLastPass = true;
371
+ // Start over from the beginning since we modified the array
372
+ i = -1;
373
+ break;
374
+ }
368
375
  }
369
376
  }
370
- if (!joined) {
371
- result.push(current.clone());
372
- }
373
377
  }
374
378
  return result;
375
379
  }
@@ -452,7 +456,7 @@ class Line2D {
452
456
  */
453
457
  distanceToPointOnInfiniteLine(point) {
454
458
  const l2 = (((this.end.x - this.start.x) * (this.end.x - this.start.x)) + ((this.end.y - this.start.y) * (this.end.y - this.start.y)));
455
- if (l2 == 0)
459
+ if (l2 === 0)
456
460
  return Infinity;
457
461
  const s = (((this.start.y - point.y) * (this.end.x - this.start.x)) - ((this.start.x - point.x) * (this.end.y - this.start.y))) / l2;
458
462
  return Math.abs(s) * Math.sqrt(l2);
@@ -673,7 +677,7 @@ class Line2D {
673
677
  return;
674
678
  visited.add(line);
675
679
  group.push(line);
676
- lines.forEach((neighbor) => {
680
+ lines.forEach(neighbor => {
677
681
  if (!visited.has(neighbor)) {
678
682
  if (line.connectsTo(neighbor, tolerance, breakpoints)) {
679
683
  dfs(neighbor, group);
@@ -682,7 +686,7 @@ class Line2D {
682
686
  });
683
687
  };
684
688
  const connectedLines = [];
685
- lines.forEach((line) => {
689
+ lines.forEach(line => {
686
690
  if (!visited.has(line)) {
687
691
  const group = [];
688
692
  dfs(line, group);
package/cjs/Line3D.js CHANGED
@@ -425,7 +425,7 @@ class Line3D extends three_1.Line3 {
425
425
  return;
426
426
  visited.add(line);
427
427
  group.push(line);
428
- lines.forEach((neighbor) => {
428
+ lines.forEach(neighbor => {
429
429
  if (!visited.has(neighbor)) {
430
430
  if (line.connectsTo(neighbor, tolerance, breakpoints)) {
431
431
  dfs(neighbor, group);
@@ -434,7 +434,7 @@ class Line3D extends three_1.Line3 {
434
434
  });
435
435
  };
436
436
  const connectedLines = [];
437
- lines.forEach((line) => {
437
+ lines.forEach(line => {
438
438
  if (!visited.has(line)) {
439
439
  const group = [];
440
440
  dfs(line, group);
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isContinuousClosedShape = void 0;
4
+ // This matches the signatures on Vec2 and Vec3 (for example, isNear(v: Vector2, maxDistance?: number)).
4
5
  function isContinuousClosedShape(lines, tolerance = 0) {
5
6
  if (lines.length < 3) {
6
7
  return false; // A shape needs at least 3 lines to be closed
@@ -0,0 +1,112 @@
1
+ import react from "eslint-plugin-react";
2
+ import typescriptEslint from "@typescript-eslint/eslint-plugin";
3
+ import globals from "globals";
4
+ import tsParser from "@typescript-eslint/parser";
5
+ import path from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ import js from "@eslint/js";
8
+ import { FlatCompat } from "@eslint/eslintrc";
9
+ import stylistic from "@stylistic/eslint-plugin";
10
+
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = path.dirname(__filename);
13
+ const compat = new FlatCompat({
14
+ baseDirectory: __dirname,
15
+ recommendedConfig: js.configs.recommended,
16
+ allConfig: js.configs.all
17
+ });
18
+
19
+ export default [
20
+ {
21
+ ignores: ["cjs/", "esm/", "types/"],
22
+ },
23
+ ...compat.extends("eslint:recommended",
24
+ "plugin:react/recommended",
25
+ "plugin:@typescript-eslint/recommended"),
26
+ {
27
+ plugins: {
28
+ react,
29
+ "@typescript-eslint": typescriptEslint,
30
+ "@stylistic": stylistic
31
+ },
32
+
33
+ languageOptions: {
34
+ globals: {
35
+ ...globals.browser,
36
+ ...globals.jest,
37
+ },
38
+
39
+ parser: tsParser,
40
+ ecmaVersion: 11,
41
+ sourceType: "module",
42
+
43
+ parserOptions: {
44
+ ecmaFeatures: {
45
+ jsx: true,
46
+ },
47
+ lib: ["esnext", "dom"]
48
+ },
49
+ },
50
+
51
+ settings: {
52
+ react: {
53
+ pragma: "dom",
54
+ version: "17.0"
55
+ },
56
+ },
57
+
58
+ rules: {
59
+ "@stylistic/indent": ["warn", 4, { "SwitchCase": 1 }],
60
+ "@stylistic/linebreak-style": ["error", "windows"],
61
+ "@stylistic/quotes": ["error", "double"],
62
+ "@stylistic/semi": ["error", "always"],
63
+ "@stylistic/no-extra-semi": ["error"],
64
+ "@stylistic/no-trailing-spaces": ["error"],
65
+ "@stylistic/no-multiple-empty-lines": ["error", { max: 1 }],
66
+ "@stylistic/space-in-parens": ["error", "never"],
67
+ "@stylistic/space-infix-ops": ["error", { int32Hint: false }],
68
+ "@stylistic/no-mixed-spaces-and-tabs": ["error"],
69
+ "@stylistic/space-before-blocks": ["error", "always"],
70
+ "@stylistic/function-call-spacing": ["error", "never"],
71
+ "@stylistic/key-spacing": ["error", { "beforeColon": false, "afterColon": true }],
72
+ "@stylistic/array-bracket-spacing": ["error", "never"],
73
+ "@stylistic/arrow-spacing": ["error", { "before": true, "after": true }],
74
+ "@stylistic/block-spacing": ["error", "always"],
75
+ "@stylistic/brace-style": ["error", "1tbs", { "allowSingleLine": true }],
76
+ "@stylistic/semi-spacing": ["error", { "before": false, "after": true }],
77
+ "@stylistic/space-before-function-paren": ["error", "never"],
78
+ "@stylistic/switch-colon-spacing": ["error", { "after": true, "before": false }],
79
+ "@stylistic/template-curly-spacing": ["error", "never"],
80
+ "@stylistic/type-annotation-spacing": ["error", { "after": true }],
81
+ "@stylistic/object-curly-spacing": ["error", "always"],
82
+ "@stylistic/keyword-spacing": ["error", { "before": true, "after": true }],
83
+ "no-undef": "error",
84
+ "consistent-return": "error",
85
+ "no-invalid-this": "error",
86
+ "arrow-parens": ["error", "as-needed"],
87
+ "eol-last": ["error", "never"],
88
+ "@typescript-eslint/no-inferrable-types": "off",
89
+ "@typescript-eslint/no-empty-interface": "off",
90
+ "@typescript-eslint/no-this-alias": "off",
91
+ "no-inv": "off",
92
+ "no-prototype-builtins": "off",
93
+ "react/react-in-jsx-scope": "off",
94
+ "react/no-unknown-property": "off",
95
+ "react/no-unescaped-entities": "off",
96
+ "react/jsx-key": "off",
97
+ "react/prop-types": "off",
98
+ "react/no-is-mounted": "off",
99
+ "@typescript-eslint/explicit-member-accessibility": ["error", {
100
+ "accessibility": "explicit",
101
+ "overrides": {
102
+ "constructors": "no-public"
103
+ }
104
+ }],
105
+ "react/self-closing-comp": ["warn", {
106
+ "component": true,
107
+ "html": true
108
+ }],
109
+ "@typescript-eslint/explicit-module-boundary-types": "error",
110
+ "eqeqeq": ["error", "always"]
111
+ },
112
+ }];
package/esm/Line2D.js CHANGED
@@ -247,7 +247,7 @@ export class Line2D {
247
247
  */
248
248
  isPointBesideLineSection(point) {
249
249
  const l2 = (((this.end.x - this.start.x) * (this.end.x - this.start.x)) + ((this.end.y - this.start.y) * (this.end.y - this.start.y)));
250
- if (l2 == 0)
250
+ if (l2 === 0)
251
251
  return false;
252
252
  const r = (((point.x - this.start.x) * (this.end.x - this.start.x)) + ((point.y - this.start.y) * (this.end.y - this.start.y))) / l2;
253
253
  return (0 <= r) && (r <= 1);
@@ -350,23 +350,27 @@ export class Line2D {
350
350
  if (lines.length < 2) {
351
351
  return lines.map(x => x.clone());
352
352
  }
353
- const toProcess = lines.slice();
354
- const result = [];
355
- while (toProcess.length > 0) {
356
- const current = toProcess.pop();
357
- let joined = false;
353
+ // Start with cloned lines as initial result
354
+ const result = lines.map(x => x.clone());
355
+ // Keep trying to join lines until no more joins are possible
356
+ let joinedInLastPass = true;
357
+ while (joinedInLastPass) {
358
+ joinedInLastPass = false;
359
+ // Try to join each pair of lines
358
360
  for (let i = 0; i < result.length; i++) {
359
- const other = result[i];
360
- const joinedLine = Line2D.joinLine(current, other);
361
- if (joinedLine) {
362
- result[i] = joinedLine;
363
- joined = true;
364
- break;
361
+ for (let j = i + 1; j < result.length; j++) {
362
+ const joinedLine = Line2D.joinLine(result[i], result[j]);
363
+ if (joinedLine) {
364
+ // Replace the first line with the joined line and remove the second
365
+ result[i] = joinedLine;
366
+ result.splice(j, 1);
367
+ joinedInLastPass = true;
368
+ // Start over from the beginning since we modified the array
369
+ i = -1;
370
+ break;
371
+ }
365
372
  }
366
373
  }
367
- if (!joined) {
368
- result.push(current.clone());
369
- }
370
374
  }
371
375
  return result;
372
376
  }
@@ -449,7 +453,7 @@ export class Line2D {
449
453
  */
450
454
  distanceToPointOnInfiniteLine(point) {
451
455
  const l2 = (((this.end.x - this.start.x) * (this.end.x - this.start.x)) + ((this.end.y - this.start.y) * (this.end.y - this.start.y)));
452
- if (l2 == 0)
456
+ if (l2 === 0)
453
457
  return Infinity;
454
458
  const s = (((this.start.y - point.y) * (this.end.x - this.start.x)) - ((this.start.x - point.x) * (this.end.y - this.start.y))) / l2;
455
459
  return Math.abs(s) * Math.sqrt(l2);
@@ -670,7 +674,7 @@ export class Line2D {
670
674
  return;
671
675
  visited.add(line);
672
676
  group.push(line);
673
- lines.forEach((neighbor) => {
677
+ lines.forEach(neighbor => {
674
678
  if (!visited.has(neighbor)) {
675
679
  if (line.connectsTo(neighbor, tolerance, breakpoints)) {
676
680
  dfs(neighbor, group);
@@ -679,7 +683,7 @@ export class Line2D {
679
683
  });
680
684
  };
681
685
  const connectedLines = [];
682
- lines.forEach((line) => {
686
+ lines.forEach(line => {
683
687
  if (!visited.has(line)) {
684
688
  const group = [];
685
689
  dfs(line, group);
package/esm/Line3D.js CHANGED
@@ -422,7 +422,7 @@ export class Line3D extends Line3 {
422
422
  return;
423
423
  visited.add(line);
424
424
  group.push(line);
425
- lines.forEach((neighbor) => {
425
+ lines.forEach(neighbor => {
426
426
  if (!visited.has(neighbor)) {
427
427
  if (line.connectsTo(neighbor, tolerance, breakpoints)) {
428
428
  dfs(neighbor, group);
@@ -431,7 +431,7 @@ export class Line3D extends Line3 {
431
431
  });
432
432
  };
433
433
  const connectedLines = [];
434
- lines.forEach((line) => {
434
+ lines.forEach(line => {
435
435
  if (!visited.has(line)) {
436
436
  const group = [];
437
437
  dfs(line, group);
@@ -1,3 +1,4 @@
1
+ // This matches the signatures on Vec2 and Vec3 (for example, isNear(v: Vector2, maxDistance?: number)).
1
2
  export function isContinuousClosedShape(lines, tolerance = 0) {
2
3
  if (lines.length < 3) {
3
4
  return false; // A shape needs at least 3 lines to be closed
package/package.json CHANGED
@@ -1,56 +1,62 @@
1
1
  {
2
- "name": "@immugio/three-math-extensions",
3
- "version": "0.3.0",
4
- "description": "Set of utilities for 2d and 3d line math built on top of three.js",
5
- "author": "Jan Mikeska <janmikeska@gmail.com>",
6
- "license": "ISC",
7
- "keywords": [
8
- "threejs",
9
- "three",
10
- "math"
11
- ],
12
- "bugs": {
13
- "url": "https://github.com/Immugio/three-math-extensions/issues"
14
- },
15
- "homepage": "https://github.com/Immugio/three-math-extensions#readme",
16
- "sideEffects": false,
17
- "source": "src/index.ts",
18
- "main": "cjs/index.js",
19
- "module": "esm/index.js",
20
- "types": "types/index.d.ts",
21
- "auto-changelog": {
22
- "commitLimit": false,
23
- "template": "keepachangelog"
24
- },
25
- "scripts": {
26
- "test": "npx jest",
27
- "build:esm": "tsc",
28
- "build:cjs": "tsc -p tsconfig-cjs.json",
29
- "clean": "rimraf types cjs esm",
30
- "build": "npm run clean && npm run build:esm && npm run build:cjs",
31
- "preversion": "npm run clean && npm run build && npm run test",
32
- "version": "auto-changelog -p && git add CHANGELOG.md",
33
- "postversion": "git push && git push --tags"
34
- },
35
- "devDependencies": {
36
- "@types/jest": "^29.5.11",
37
- "@types/offscreencanvas": "2019.7.3",
38
- "@types/three": "0.152.0",
39
- "@typescript-eslint/eslint-plugin": "^6.16.0",
40
- "auto-changelog": "^2.4.0",
41
- "jest": "^29.7.0",
42
- "rimraf": "^5.0.5",
43
- "ts-jest": "^29.1.1",
44
- "typedoc": "^0.25.4",
45
- "typedoc-plugin-markdown": "^3.17.1",
46
- "typescript": "5.3.3",
47
- "eslint": "^8.56.0"
48
- },
49
- "peerDependencies": {
50
- "three": ">=0.152.0"
51
- },
52
- "repository": {
53
- "type": "git",
54
- "url": "git+https://github.com/Immugio/three-math-extensions.git"
55
- }
2
+ "name": "@immugio/three-math-extensions",
3
+ "version": "0.3.2",
4
+ "description": "Set of utilities for 2d and 3d line math built on top of three.js",
5
+ "author": "Jan Mikeska <janmikeska@gmail.com>",
6
+ "license": "ISC",
7
+ "keywords": [
8
+ "threejs",
9
+ "three",
10
+ "math"
11
+ ],
12
+ "bugs": {
13
+ "url": "https://github.com/Immugio/three-math-extensions/issues"
14
+ },
15
+ "homepage": "https://github.com/Immugio/three-math-extensions#readme",
16
+ "sideEffects": false,
17
+ "source": "src/index.ts",
18
+ "main": "cjs/index.js",
19
+ "module": "esm/index.js",
20
+ "types": "types/index.d.ts",
21
+ "auto-changelog": {
22
+ "commitLimit": false,
23
+ "template": "keepachangelog"
24
+ },
25
+ "scripts": {
26
+ "test": "npx jest",
27
+ "build:esm": "tsc",
28
+ "build:cjs": "tsc -p tsconfig-cjs.json",
29
+ "clean": "rimraf types cjs esm",
30
+ "build": "npm run clean && npm run build:esm && npm run build:cjs",
31
+ "preversion": "npm run clean && npm run build && npm run test",
32
+ "version": "auto-changelog -p && git add CHANGELOG.md",
33
+ "postversion": "git push && git push --tags"
34
+ },
35
+ "devDependencies": {
36
+ "@eslint/eslintrc": "^3.3.1",
37
+ "@eslint/js": "^9.39.1",
38
+ "@stylistic/eslint-plugin": "^5.6.1",
39
+ "@types/jest": "^29.5.11",
40
+ "@types/offscreencanvas": "2019.7.3",
41
+ "@types/three": "0.152.0",
42
+ "@typescript-eslint/eslint-plugin": "^8.47.0",
43
+ "@typescript-eslint/parser": "^8.47.0",
44
+ "auto-changelog": "^2.5.0",
45
+ "eslint": "^9.39.1",
46
+ "eslint-plugin-react": "^7.37.5",
47
+ "globals": "^16.5.0",
48
+ "jest": "^30.2.0",
49
+ "rimraf": "^6.1.2",
50
+ "ts-jest": "^29.4.5",
51
+ "typedoc": "^0.28.14",
52
+ "typedoc-plugin-markdown": "^4.9.0",
53
+ "typescript": "5.3.3"
54
+ },
55
+ "peerDependencies": {
56
+ "three": ">=0.152.0"
57
+ },
58
+ "repository": {
59
+ "type": "git",
60
+ "url": "git+https://github.com/Immugio/three-math-extensions.git"
61
+ }
56
62
  }
@@ -1,14 +1,14 @@
1
1
  import { Vec2 } from "./Vec2";
2
2
 
3
3
  export class BoundingBox {
4
- constructor(public minX: number, public maxX: number, public minY: number, public maxY: number) {
5
- }
4
+ constructor(public minX: number, public maxX: number, public minY: number, public maxY: number) {
5
+ }
6
6
 
7
- public equals(other: BoundingBox): boolean {
8
- return this.minX === other.minX && this.maxX === other.maxX && this.minY === other.minY && this.maxY === other.maxY;
9
- }
7
+ public equals(other: BoundingBox): boolean {
8
+ return this.minX === other.minX && this.maxX === other.maxX && this.minY === other.minY && this.maxY === other.maxY;
9
+ }
10
10
 
11
- public get size(): Vec2 {
12
- return new Vec2(this.maxX - this.minX, this.maxY - this.minY);
13
- }
11
+ public get size(): Vec2 {
12
+ return new Vec2(this.maxX - this.minX, this.maxY - this.minY);
13
+ }
14
14
  }
package/src/Line2D.ts CHANGED
@@ -285,7 +285,7 @@ export class Line2D {
285
285
  */
286
286
  public isPointBesideLineSection(point: Point2): boolean {
287
287
  const l2 = (((this.end.x - this.start.x) * (this.end.x - this.start.x)) + ((this.end.y - this.start.y) * (this.end.y - this.start.y)));
288
- if (l2 == 0) return false;
288
+ if (l2 === 0) return false;
289
289
  const r = (((point.x - this.start.x) * (this.end.x - this.start.x)) + ((point.y - this.start.y) * (this.end.y - this.start.y))) / l2;
290
290
 
291
291
  return (0 <= r) && (r <= 1);
@@ -409,27 +409,29 @@ export class Line2D {
409
409
  return lines.map(x => x.clone());
410
410
  }
411
411
 
412
- const toProcess = lines.slice();
413
- const result: Line2D[] = [];
414
-
415
- while (toProcess.length > 0) {
412
+ // Start with cloned lines as initial result
413
+ const result: Line2D[] = lines.map(x => x.clone());
416
414
 
417
- const current = toProcess.pop();
418
- let joined = false;
415
+ // Keep trying to join lines until no more joins are possible
416
+ let joinedInLastPass = true;
417
+ while (joinedInLastPass) {
418
+ joinedInLastPass = false;
419
419
 
420
+ // Try to join each pair of lines
420
421
  for (let i = 0; i < result.length; i++) {
421
- const other = result[i];
422
- const joinedLine = Line2D.joinLine(current, other);
423
- if (joinedLine) {
424
- result[i] = joinedLine;
425
- joined = true;
426
- break;
422
+ for (let j = i + 1; j < result.length; j++) {
423
+ const joinedLine = Line2D.joinLine(result[i], result[j]);
424
+ if (joinedLine) {
425
+ // Replace the first line with the joined line and remove the second
426
+ result[i] = joinedLine;
427
+ result.splice(j, 1);
428
+ joinedInLastPass = true;
429
+ // Start over from the beginning since we modified the array
430
+ i = -1;
431
+ break;
432
+ }
427
433
  }
428
434
  }
429
-
430
- if (!joined) {
431
- result.push(current.clone());
432
- }
433
435
  }
434
436
 
435
437
  return result;
@@ -527,7 +529,7 @@ export class Line2D {
527
529
  */
528
530
  public distanceToPointOnInfiniteLine(point: Point2): number {
529
531
  const l2 = (((this.end.x - this.start.x) * (this.end.x - this.start.x)) + ((this.end.y - this.start.y) * (this.end.y - this.start.y)));
530
- if (l2 == 0) return Infinity;
532
+ if (l2 === 0) return Infinity;
531
533
  const s = (((this.start.y - point.y) * (this.end.x - this.start.x)) - ((this.start.x - point.x) * (this.end.y - this.start.y))) / l2;
532
534
  return Math.abs(s) * Math.sqrt(l2);
533
535
  }
@@ -789,7 +791,7 @@ export class Line2D {
789
791
  visited.add(line);
790
792
  group.push(line);
791
793
 
792
- lines.forEach((neighbor) => {
794
+ lines.forEach(neighbor => {
793
795
  if (!visited.has(neighbor)) {
794
796
  if (line.connectsTo(neighbor, tolerance, breakpoints)) {
795
797
  dfs(neighbor, group);
@@ -800,7 +802,7 @@ export class Line2D {
800
802
 
801
803
  const connectedLines: Line2D[][] = [];
802
804
 
803
- lines.forEach((line) => {
805
+ lines.forEach(line => {
804
806
  if (!visited.has(line)) {
805
807
  const group: Line2D[] = [];
806
808
  dfs(line, group);
package/src/Line3D.ts CHANGED
@@ -521,7 +521,7 @@ export class Line3D extends Line3 {
521
521
  visited.add(line);
522
522
  group.push(line);
523
523
 
524
- lines.forEach((neighbor) => {
524
+ lines.forEach(neighbor => {
525
525
  if (!visited.has(neighbor)) {
526
526
  if (
527
527
  line.connectsTo(neighbor, tolerance, breakpoints)
@@ -534,7 +534,7 @@ export class Line3D extends Line3 {
534
534
 
535
535
  const connectedLines: Line3D[][] = [];
536
536
 
537
- lines.forEach((line) => {
537
+ lines.forEach(line => {
538
538
  if (!visited.has(line)) {
539
539
  const group: Line3D[] = [];
540
540
  dfs(line, group);
package/src/Point3.ts CHANGED
@@ -2,5 +2,4 @@ export interface Point3 {
2
2
  x: number,
3
3
  y: number,
4
4
  z: number
5
- }
6
-
5
+ }
package/src/Polygon.ts CHANGED
@@ -15,7 +15,7 @@ export class Polygon {
15
15
  }
16
16
 
17
17
  public static fromPoints(contour: Point2[], holes?: Point2[][]): Polygon {
18
- return new Polygon(contour.map(p => Vec2.fromPoint(p)), holes?.map(h => h.map(p => Vec2.fromPoint(p))) );
18
+ return new Polygon(contour.map(p => Vec2.fromPoint(p)), holes?.map(h => h.map(p => Vec2.fromPoint(p))));
19
19
  }
20
20
 
21
21
  public static fromSize(width: number, height: number): Polygon {
@@ -284,5 +284,4 @@ export class Polygon {
284
284
 
285
285
  return true;
286
286
  }
287
- }
288
-
287
+ }
package/src/Vec2.ts CHANGED
@@ -1,7 +1,7 @@
1
- import {Vector2} from "three";
2
- import {Vec3} from "./Vec3";
3
- import {Point2} from "./Point2";
4
- import {normalizeAngleRadians} from "./normalizeAngleRadians";
1
+ import { Vector2 } from "three";
2
+ import { Vec3 } from "./Vec3";
3
+ import { Point2 } from "./Point2";
4
+ import { normalizeAngleRadians } from "./normalizeAngleRadians";
5
5
 
6
6
  /**
7
7
  * Vec2 represents a 2D vector. It extends `Vector2` from the `threejs` library.
package/src/Vec3.ts CHANGED
@@ -56,7 +56,6 @@ export class Vec3 extends Vector3 {
56
56
  return this.moveTowards(target, this.distanceTo(target) / 2);
57
57
  }
58
58
 
59
-
60
59
  /**
61
60
  * Adds y amount to this Vec3 instance and return this
62
61
  * @param y
@@ -1,7 +1,8 @@
1
- import { Line3D } from "./Line3D";
2
- import { Line2D } from "./Line2D";
1
+ // The point type P must implement an isNear method that accepts the same point type and an optional tolerance.
2
+ type Point<P extends { isNear(other: P, tolerance?: number): boolean }> = { isNear(other: P, tolerance?: number): boolean };
3
3
 
4
- export function isContinuousClosedShape<T extends Line2D | Line3D>(lines: T[], tolerance: number = 0): boolean {
4
+ // This matches the signatures on Vec2 and Vec3 (for example, isNear(v: Vector2, maxDistance?: number)).
5
+ export function isContinuousClosedShape<P extends Point<P>>(lines: { start: P; end: P }[], tolerance: number = 0): boolean {
5
6
  if (lines.length < 3) {
6
7
  return false; // A shape needs at least 3 lines to be closed
7
8
  }
@@ -11,7 +12,7 @@ export function isContinuousClosedShape<T extends Line2D | Line3D>(lines: T[], t
11
12
  const endCurrent = lines[i].end;
12
13
  const startNext = lines[i + 1].start;
13
14
 
14
- if (!endCurrent.isNear(startNext as any, tolerance)) {
15
+ if (!endCurrent.isNear(startNext, tolerance)) {
15
16
  return false; // If the end of the current line and start of the next line are not close, return false
16
17
  }
17
18
  }
@@ -20,5 +21,5 @@ export function isContinuousClosedShape<T extends Line2D | Line3D>(lines: T[], t
20
21
  const endLast = lines[lines.length - 1].end;
21
22
  const startFirst = lines[0].start;
22
23
 
23
- return endLast.isNear(startFirst as any, tolerance);
24
+ return endLast.isNear(startFirst, tolerance);
24
25
  }
@@ -1,3 +1,10 @@
1
- import { Line3D } from "./Line3D";
2
- import { Line2D } from "./Line2D";
3
- export declare function isContinuousClosedShape<T extends Line2D | Line3D>(lines: T[], tolerance?: number): boolean;
1
+ type Point<P extends {
2
+ isNear(other: P, tolerance?: number): boolean;
3
+ }> = {
4
+ isNear(other: P, tolerance?: number): boolean;
5
+ };
6
+ export declare function isContinuousClosedShape<P extends Point<P>>(lines: {
7
+ start: P;
8
+ end: P;
9
+ }[], tolerance?: number): boolean;
10
+ export {};