@immugio/three-math-extensions 0.2.29 → 0.2.31

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,19 @@ 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.29](https://github.com/Immugio/three-math-extensions/compare/0.2.28...0.2.29)
10
+ ## [0.2.31](https://github.com/Immugio/three-math-extensions/compare/0.2.30...0.2.31)
11
+
12
+ ### Commits
13
+
14
+ - Add Vec3.applyAxisAngleAroundCenter [`a45aaea`](https://github.com/Immugio/three-math-extensions/commit/a45aaea2b6579e8f94859d1ed29abf81479d3a76)
15
+
16
+ ## [0.2.30](https://github.com/Immugio/three-math-extensions/compare/0.2.29...0.2.30) - 2024-09-12
17
+
18
+ ### Commits
19
+
20
+ - Improve offset algorithm implementation [`79bac64`](https://github.com/Immugio/three-math-extensions/commit/79bac64c799de39d022fcf4496dab3fcef497b60)
21
+
22
+ ## [0.2.29](https://github.com/Immugio/three-math-extensions/compare/0.2.28...0.2.29) - 2024-09-12
11
23
 
12
24
  ### Commits
13
25
 
package/cjs/Line2D.js CHANGED
@@ -27,28 +27,18 @@ class Line2D {
27
27
  /**
28
28
  * Creates a polygon formed by an array of lines from points provided.
29
29
  * The polygon will only be closed if either
30
- * 1) the first and last points are the same or 2) `@forceClosedPolygon` is true.
31
- * Similar to Line2.fromVectors but creates new instances of Vec2.
30
+ * 1) the first and last points are the same or 2) `forceClosedPolygon` is true.
32
31
  */
33
32
  static fromPolygon(polygon, forceClosedPolygon = false) {
34
- return Line2D.fromVectors(polygon?.map(p => Vec2_1.Vec2.fromPoint(p)), forceClosedPolygon);
35
- }
36
- /**
37
- * Creates a polygon formed by an array of lines from points provided.
38
- * The polygon will only be closed if either
39
- * 1) the first and last points are the same or 2) `@forceClosedPolygon` is true.
40
- * Similar to Line2.fromPolygon but keeps the original instances of Vec2.
41
- */
42
- static fromVectors(polygon, forceClosedPolygon = false) {
43
33
  if (!polygon || polygon.length < 2) {
44
34
  return [];
45
35
  }
46
- if (forceClosedPolygon && !polygon[0].equals(polygon.at(-1))) {
36
+ if (forceClosedPolygon && (polygon[0].x !== polygon.at(-1).x || polygon[0].y !== polygon.at(-1).y)) {
47
37
  polygon = [...polygon, polygon[0]];
48
38
  }
49
39
  const lines = [];
50
40
  for (let i = 0; i < polygon.length - 1; i++) {
51
- lines.push(new Line2D(polygon[i], polygon[i + 1], i));
41
+ lines.push(Line2D.fromPoints(polygon[i], polygon[i + 1], i));
52
42
  }
53
43
  return lines;
54
44
  }
package/cjs/Polygon.js CHANGED
@@ -7,8 +7,6 @@ const BoundingBox_1 = require("./BoundingBox");
7
7
  const polygonPerimeter_1 = require("./polygonPerimeter");
8
8
  const isPointInPolygon_1 = require("./isPointInPolygon");
9
9
  const Line2D_1 = require("./Line2D");
10
- const offsetPolyline_1 = require("./offsetPolyline");
11
- const extendOrTrimPolylinesAtIntersections_1 = require("./extendOrTrimPolylinesAtIntersections");
12
10
  class Polygon {
13
11
  contour;
14
12
  holes;
@@ -124,13 +122,38 @@ class Polygon {
124
122
  return this;
125
123
  }
126
124
  offsetContour(offset) {
127
- (0, offsetPolyline_1.offsetPolyline)(Line2D_1.Line2D.fromVectors(this.contour), offset);
125
+ if (!this.contour[0].equals(this.contour.at(-1))) {
126
+ console.error("The contour should be closed");
127
+ return this;
128
+ }
129
+ for (let i = 0; i < this.contour.length - 1; i++) {
130
+ this.translateContourLine(i, offset);
131
+ }
128
132
  return this;
129
133
  }
130
134
  translateContourLine(index, offset) {
131
- const lines = Line2D_1.Line2D.fromVectors(this.contour);
132
- lines[index].translateLeft(offset);
133
- (0, extendOrTrimPolylinesAtIntersections_1.extendOrTrimPolylinesAtIntersections)(lines);
135
+ if (index < 0 || index > this.contour.length - 2) {
136
+ console.error(`Index out of bounds: ${index}`);
137
+ return this;
138
+ }
139
+ if (!this.contour[0].equals(this.contour.at(-1))) {
140
+ console.error("The contour should be closed");
141
+ return this;
142
+ }
143
+ const line = Line2D_1.Line2D.fromPoints(this.contour[index], this.contour[index + 1]);
144
+ const prev = Line2D_1.Line2D.fromPoints(this.contour[(index - 1 + this.contour.length) % this.contour.length], this.contour[index]);
145
+ const next = Line2D_1.Line2D.fromPoints(this.contour[index + 1], this.contour[(index + 2) % this.contour.length]);
146
+ line.translateLeft(offset);
147
+ line.extendToOrTrimAtIntersection(prev);
148
+ line.extendToOrTrimAtIntersection(next);
149
+ this.contour[index].copy(line.start);
150
+ this.contour[index + 1].copy(line.end);
151
+ if (index === 0) {
152
+ this.contour.at(-1).copy(line.start);
153
+ }
154
+ if (index === this.contour.length - 2) {
155
+ this.contour[0].copy(line.end);
156
+ }
134
157
  return this;
135
158
  }
136
159
  rotate(angle, center = this.center()) {
package/cjs/Vec3.js CHANGED
@@ -81,6 +81,15 @@ class Vec3 extends three_1.Vector3 {
81
81
  const closest = withDistances.reduce((a, b) => a.distance < b.distance ? a : b);
82
82
  return Vec3.fromPoint(closest.point);
83
83
  }
84
+ applyAxisAngleAroundCenter(axis, angle, center) {
85
+ // Translate the vector to the origin
86
+ this.sub(center);
87
+ // Apply the axis-angle rotation
88
+ this.applyAxisAngle(axis, angle);
89
+ // Translate the vector back to the original position
90
+ this.add(center);
91
+ return this;
92
+ }
84
93
  roundIfCloseToInteger(max = 0.000000000001) {
85
94
  if (Math.abs(this.x - Math.round(this.x)) < max) {
86
95
  this.x = Math.round(this.x);
@@ -1,10 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.offsetPolyline = void 0;
4
- const extendOrTrimPolylinesAtIntersections_1 = require("./extendOrTrimPolylinesAtIntersections");
5
4
  function offsetPolyline(lines, offset) {
6
- lines.forEach(line => line.translateLeft(offset));
7
- (0, extendOrTrimPolylinesAtIntersections_1.extendOrTrimPolylinesAtIntersections)(lines);
5
+ for (let i = 0; i < lines.length; i++) {
6
+ const line = lines[i];
7
+ line.translateLeft(offset);
8
+ const next = lines[(i + 1) % lines.length];
9
+ line.extendToOrTrimAtIntersection(next);
10
+ next.extendToOrTrimAtIntersection(line);
11
+ const previous = lines[(i + lines.length - 1) % lines.length];
12
+ line.extendToOrTrimAtIntersection(previous);
13
+ previous.extendToOrTrimAtIntersection(line);
14
+ }
8
15
  return lines;
9
16
  }
10
17
  exports.offsetPolyline = offsetPolyline;
package/esm/Line2D.js CHANGED
@@ -24,28 +24,18 @@ export class Line2D {
24
24
  /**
25
25
  * Creates a polygon formed by an array of lines from points provided.
26
26
  * The polygon will only be closed if either
27
- * 1) the first and last points are the same or 2) `@forceClosedPolygon` is true.
28
- * Similar to Line2.fromVectors but creates new instances of Vec2.
27
+ * 1) the first and last points are the same or 2) `forceClosedPolygon` is true.
29
28
  */
30
29
  static fromPolygon(polygon, forceClosedPolygon = false) {
31
- return Line2D.fromVectors(polygon?.map(p => Vec2.fromPoint(p)), forceClosedPolygon);
32
- }
33
- /**
34
- * Creates a polygon formed by an array of lines from points provided.
35
- * The polygon will only be closed if either
36
- * 1) the first and last points are the same or 2) `@forceClosedPolygon` is true.
37
- * Similar to Line2.fromPolygon but keeps the original instances of Vec2.
38
- */
39
- static fromVectors(polygon, forceClosedPolygon = false) {
40
30
  if (!polygon || polygon.length < 2) {
41
31
  return [];
42
32
  }
43
- if (forceClosedPolygon && !polygon[0].equals(polygon.at(-1))) {
33
+ if (forceClosedPolygon && (polygon[0].x !== polygon.at(-1).x || polygon[0].y !== polygon.at(-1).y)) {
44
34
  polygon = [...polygon, polygon[0]];
45
35
  }
46
36
  const lines = [];
47
37
  for (let i = 0; i < polygon.length - 1; i++) {
48
- lines.push(new Line2D(polygon[i], polygon[i + 1], i));
38
+ lines.push(Line2D.fromPoints(polygon[i], polygon[i + 1], i));
49
39
  }
50
40
  return lines;
51
41
  }
package/esm/Polygon.js CHANGED
@@ -4,8 +4,6 @@ import { BoundingBox } from "./BoundingBox";
4
4
  import { polygonPerimeter } from "./polygonPerimeter";
5
5
  import { isPointInPolygon } from "./isPointInPolygon";
6
6
  import { Line2D } from "./Line2D";
7
- import { offsetPolyline } from "./offsetPolyline";
8
- import { extendOrTrimPolylinesAtIntersections } from "./extendOrTrimPolylinesAtIntersections";
9
7
  export class Polygon {
10
8
  contour;
11
9
  holes;
@@ -121,13 +119,38 @@ export class Polygon {
121
119
  return this;
122
120
  }
123
121
  offsetContour(offset) {
124
- offsetPolyline(Line2D.fromVectors(this.contour), offset);
122
+ if (!this.contour[0].equals(this.contour.at(-1))) {
123
+ console.error("The contour should be closed");
124
+ return this;
125
+ }
126
+ for (let i = 0; i < this.contour.length - 1; i++) {
127
+ this.translateContourLine(i, offset);
128
+ }
125
129
  return this;
126
130
  }
127
131
  translateContourLine(index, offset) {
128
- const lines = Line2D.fromVectors(this.contour);
129
- lines[index].translateLeft(offset);
130
- extendOrTrimPolylinesAtIntersections(lines);
132
+ if (index < 0 || index > this.contour.length - 2) {
133
+ console.error(`Index out of bounds: ${index}`);
134
+ return this;
135
+ }
136
+ if (!this.contour[0].equals(this.contour.at(-1))) {
137
+ console.error("The contour should be closed");
138
+ return this;
139
+ }
140
+ const line = Line2D.fromPoints(this.contour[index], this.contour[index + 1]);
141
+ const prev = Line2D.fromPoints(this.contour[(index - 1 + this.contour.length) % this.contour.length], this.contour[index]);
142
+ const next = Line2D.fromPoints(this.contour[index + 1], this.contour[(index + 2) % this.contour.length]);
143
+ line.translateLeft(offset);
144
+ line.extendToOrTrimAtIntersection(prev);
145
+ line.extendToOrTrimAtIntersection(next);
146
+ this.contour[index].copy(line.start);
147
+ this.contour[index + 1].copy(line.end);
148
+ if (index === 0) {
149
+ this.contour.at(-1).copy(line.start);
150
+ }
151
+ if (index === this.contour.length - 2) {
152
+ this.contour[0].copy(line.end);
153
+ }
131
154
  return this;
132
155
  }
133
156
  rotate(angle, center = this.center()) {
package/esm/Vec3.js CHANGED
@@ -78,6 +78,15 @@ export class Vec3 extends Vector3 {
78
78
  const closest = withDistances.reduce((a, b) => a.distance < b.distance ? a : b);
79
79
  return Vec3.fromPoint(closest.point);
80
80
  }
81
+ applyAxisAngleAroundCenter(axis, angle, center) {
82
+ // Translate the vector to the origin
83
+ this.sub(center);
84
+ // Apply the axis-angle rotation
85
+ this.applyAxisAngle(axis, angle);
86
+ // Translate the vector back to the original position
87
+ this.add(center);
88
+ return this;
89
+ }
81
90
  roundIfCloseToInteger(max = 0.000000000001) {
82
91
  if (Math.abs(this.x - Math.round(this.x)) < max) {
83
92
  this.x = Math.round(this.x);
@@ -1,6 +1,13 @@
1
- import { extendOrTrimPolylinesAtIntersections } from "./extendOrTrimPolylinesAtIntersections";
2
1
  export function offsetPolyline(lines, offset) {
3
- lines.forEach(line => line.translateLeft(offset));
4
- extendOrTrimPolylinesAtIntersections(lines);
2
+ for (let i = 0; i < lines.length; i++) {
3
+ const line = lines[i];
4
+ line.translateLeft(offset);
5
+ const next = lines[(i + 1) % lines.length];
6
+ line.extendToOrTrimAtIntersection(next);
7
+ next.extendToOrTrimAtIntersection(line);
8
+ const previous = lines[(i + lines.length - 1) % lines.length];
9
+ line.extendToOrTrimAtIntersection(previous);
10
+ previous.extendToOrTrimAtIntersection(line);
11
+ }
5
12
  return lines;
6
13
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@immugio/three-math-extensions",
3
- "version": "0.2.29",
3
+ "version": "0.2.31",
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",
package/src/Line2D.ts CHANGED
@@ -26,31 +26,20 @@ export class Line2D {
26
26
  /**
27
27
  * Creates a polygon formed by an array of lines from points provided.
28
28
  * The polygon will only be closed if either
29
- * 1) the first and last points are the same or 2) `@forceClosedPolygon` is true.
30
- * Similar to Line2.fromVectors but creates new instances of Vec2.
29
+ * 1) the first and last points are the same or 2) `forceClosedPolygon` is true.
31
30
  */
32
31
  public static fromPolygon(polygon: Point2[], forceClosedPolygon: boolean = false): Line2D[] {
33
- return Line2D.fromVectors(polygon?.map(p => Vec2.fromPoint(p)), forceClosedPolygon);
34
- }
35
-
36
- /**
37
- * Creates a polygon formed by an array of lines from points provided.
38
- * The polygon will only be closed if either
39
- * 1) the first and last points are the same or 2) `@forceClosedPolygon` is true.
40
- * Similar to Line2.fromPolygon but keeps the original instances of Vec2.
41
- */
42
- public static fromVectors(polygon: Vec2[], forceClosedPolygon: boolean = false): Line2D[] {
43
32
  if (!polygon || polygon.length < 2) {
44
33
  return [];
45
34
  }
46
35
 
47
- if (forceClosedPolygon && !polygon[0].equals(polygon.at(-1))) {
36
+ if (forceClosedPolygon && (polygon[0].x !== polygon.at(-1).x || polygon[0].y !== polygon.at(-1).y)) {
48
37
  polygon = [...polygon, polygon[0]];
49
38
  }
50
39
 
51
40
  const lines: Line2D[] = [];
52
41
  for (let i = 0; i < polygon.length - 1; i++) {
53
- lines.push(new Line2D(polygon[i], polygon[i + 1], i));
42
+ lines.push(Line2D.fromPoints(polygon[i], polygon[i + 1], i));
54
43
  }
55
44
 
56
45
  return lines;
package/src/Polygon.ts CHANGED
@@ -5,8 +5,6 @@ import { BoundingBox } from "./BoundingBox";
5
5
  import { polygonPerimeter } from "./polygonPerimeter";
6
6
  import { isPointInPolygon } from "./isPointInPolygon";
7
7
  import { Line2D } from "./Line2D";
8
- import { offsetPolyline } from "./offsetPolyline";
9
- import { extendOrTrimPolylinesAtIntersections } from "./extendOrTrimPolylinesAtIntersections";
10
8
 
11
9
  export class Polygon {
12
10
 
@@ -144,14 +142,47 @@ export class Polygon {
144
142
  }
145
143
 
146
144
  public offsetContour(offset: number): this {
147
- offsetPolyline(Line2D.fromVectors(this.contour), offset);
145
+ if (!this.contour[0].equals(this.contour.at(-1))) {
146
+ console.error("The contour should be closed");
147
+ return this;
148
+ }
149
+
150
+ for (let i = 0; i < this.contour.length - 1; i++) {
151
+ this.translateContourLine(i, offset);
152
+ }
148
153
  return this;
149
154
  }
150
155
 
151
156
  public translateContourLine(index: number, offset: number): this {
152
- const lines = Line2D.fromVectors(this.contour);
153
- lines[index].translateLeft(offset);
154
- extendOrTrimPolylinesAtIntersections(lines);
157
+ if (index < 0 || index > this.contour.length - 2) {
158
+ console.error(`Index out of bounds: ${index}`);
159
+ return this;
160
+ }
161
+
162
+ if (!this.contour[0].equals(this.contour.at(-1))) {
163
+ console.error("The contour should be closed");
164
+ return this;
165
+ }
166
+
167
+ const line = Line2D.fromPoints(this.contour[index], this.contour[index + 1]);
168
+ const prev = Line2D.fromPoints(this.contour[(index - 1 + this.contour.length) % this.contour.length], this.contour[index]);
169
+ const next = Line2D.fromPoints(this.contour[index + 1], this.contour[(index + 2) % this.contour.length]);
170
+
171
+ line.translateLeft(offset);
172
+ line.extendToOrTrimAtIntersection(prev);
173
+ line.extendToOrTrimAtIntersection(next);
174
+
175
+ this.contour[index].copy(line.start);
176
+ this.contour[index + 1].copy(line.end);
177
+
178
+ if (index === 0) {
179
+ this.contour.at(-1).copy(line.start);
180
+ }
181
+
182
+ if (index === this.contour.length - 2) {
183
+ this.contour[0].copy(line.end);
184
+ }
185
+
155
186
  return this;
156
187
  }
157
188
 
package/src/Vec3.ts CHANGED
@@ -94,6 +94,19 @@ export class Vec3 extends Vector3 {
94
94
  return Vec3.fromPoint(closest.point);
95
95
  }
96
96
 
97
+ public applyAxisAngleAroundCenter(axis: Vector3, angle: number, center: Vector3): this {
98
+ // Translate the vector to the origin
99
+ this.sub(center);
100
+
101
+ // Apply the axis-angle rotation
102
+ this.applyAxisAngle(axis, angle);
103
+
104
+ // Translate the vector back to the original position
105
+ this.add(center);
106
+
107
+ return this;
108
+ }
109
+
97
110
  public roundIfCloseToInteger(max: number = 0.000000000001): this {
98
111
  if (Math.abs(this.x - Math.round(this.x)) < max) {
99
112
  this.x = Math.round(this.x);
@@ -1,8 +1,18 @@
1
1
  import { Line2D } from "./Line2D";
2
- import { extendOrTrimPolylinesAtIntersections } from "./extendOrTrimPolylinesAtIntersections";
3
2
 
4
3
  export function offsetPolyline(lines: Line2D[], offset: number): Line2D[] {
5
- lines.forEach(line => line.translateLeft(offset));
6
- extendOrTrimPolylinesAtIntersections(lines);
4
+ for (let i = 0; i < lines.length; i++){
5
+ const line = lines[i];
6
+ line.translateLeft(offset);
7
+
8
+ const next = lines[(i + 1) % lines.length];
9
+ line.extendToOrTrimAtIntersection(next);
10
+ next.extendToOrTrimAtIntersection(line);
11
+
12
+ const previous = lines[(i + lines.length - 1) % lines.length];
13
+ line.extendToOrTrimAtIntersection(previous);
14
+ previous.extendToOrTrimAtIntersection(line);
15
+ }
16
+
7
17
  return lines;
8
18
  }
package/types/Line2D.d.ts CHANGED
@@ -13,17 +13,9 @@ export declare class Line2D {
13
13
  /**
14
14
  * Creates a polygon formed by an array of lines from points provided.
15
15
  * The polygon will only be closed if either
16
- * 1) the first and last points are the same or 2) `@forceClosedPolygon` is true.
17
- * Similar to Line2.fromVectors but creates new instances of Vec2.
16
+ * 1) the first and last points are the same or 2) `forceClosedPolygon` is true.
18
17
  */
19
18
  static fromPolygon(polygon: Point2[], forceClosedPolygon?: boolean): Line2D[];
20
- /**
21
- * Creates a polygon formed by an array of lines from points provided.
22
- * The polygon will only be closed if either
23
- * 1) the first and last points are the same or 2) `@forceClosedPolygon` is true.
24
- * Similar to Line2.fromPolygon but keeps the original instances of Vec2.
25
- */
26
- static fromVectors(polygon: Vec2[], forceClosedPolygon?: boolean): Line2D[];
27
19
  static fromLength(length: number): Line2D;
28
20
  get center(): Vec2;
29
21
  /**
package/types/Vec3.d.ts CHANGED
@@ -50,6 +50,7 @@ export declare class Vec3 extends Vector3 {
50
50
  * @param points
51
51
  */
52
52
  closest(...points: Vector3[]): Vec3;
53
+ applyAxisAngleAroundCenter(axis: Vector3, angle: number, center: Vector3): this;
53
54
  roundIfCloseToInteger(max?: number): this;
54
55
  /**
55
56
  * Returns a clone of this Vec3 instance with y and z swapped.