@immugio/three-math-extensions 0.0.4 → 0.0.5

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/esm/Line3D.js ADDED
@@ -0,0 +1,388 @@
1
+ import { Line3 } from "three";
2
+ import { Vec3 } from "./Vec3";
3
+ import { Line2D } from "./Line2D";
4
+ export class Line3D extends Line3 {
5
+ #target;
6
+ constructor(start, end) {
7
+ super(start, end);
8
+ this.#target = new Vec3();
9
+ }
10
+ static fromPoints(start, end) {
11
+ return new Line3D(new Vec3(start.x, start.y, start.z), new Vec3(end.x, end.y, end.z));
12
+ }
13
+ /**
14
+ * Creates a polygon formed by an array of lines from points provided.
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
+ */
18
+ static fromPolygon(polygon, forceClosedPolygon = false) {
19
+ if (!polygon || polygon.length < 2) {
20
+ return [];
21
+ }
22
+ if (forceClosedPolygon && (polygon[0].x !== polygon.at(-1).x || polygon[0].y !== polygon.at(-1).y || polygon[0].z !== polygon.at(-1).z)) {
23
+ polygon = [...polygon, polygon[0]];
24
+ }
25
+ const lines = [];
26
+ for (let i = 0; i < polygon.length - 1; i++) {
27
+ lines.push(Line3D.fromPoints(polygon[i], polygon[i + 1]));
28
+ }
29
+ return lines;
30
+ }
31
+ /**
32
+ * Returns lines that are the result of clipping this line by the @other line.
33
+ * Clips must be parallel to this line.
34
+ * Clones the line, does not modify this.
35
+ * @param other
36
+ * @param parallelTolerance
37
+ */
38
+ clipLine(other, parallelTolerance = Number.EPSILON) {
39
+ other = this.getParallelLineInTheSameDirection(other, parallelTolerance);
40
+ // 1) Lines aren't parallel
41
+ if (!other) {
42
+ return [this.clone()];
43
+ }
44
+ const left = this.clone();
45
+ left.end.copy(other.start);
46
+ const right = this.clone();
47
+ right.start.copy(other.end);
48
+ return [left, right].filter(x => x.direction.manhattanDistanceTo(this.direction) <= parallelTolerance);
49
+ }
50
+ /**
51
+ * Returns lines that are the result of clipping this line by the @clips.
52
+ * Clips must be parallel to this line.
53
+ * Clones the line, does not modify this.
54
+ * @param clips
55
+ * @param distanceTolerance
56
+ * @param parallelTolerance
57
+ */
58
+ clipLines(clips, distanceTolerance = 0, parallelTolerance = Number.EPSILON) {
59
+ const free = [];
60
+ const sources = [this.clone()];
61
+ while (sources.length > 0) {
62
+ let isFree = true;
63
+ const tested = sources.pop();
64
+ for (const clip of clips) {
65
+ if (tested.overlaps(clip, distanceTolerance, parallelTolerance)) {
66
+ isFree = false;
67
+ const subtracted = tested.clipLine(clip, parallelTolerance);
68
+ sources.push(...subtracted);
69
+ break;
70
+ }
71
+ }
72
+ if (isFree)
73
+ free.push(tested);
74
+ }
75
+ return free;
76
+ }
77
+ /**
78
+ * Joins a copy of this line with the @other line.
79
+ * Other must be parallel to this line.
80
+ * Returns null if there is no overlap
81
+ * Clones the line, does not modify this.
82
+ * @param other
83
+ * @param distanceTolerance
84
+ * @param parallelTolerance
85
+ */
86
+ joinLine(other, distanceTolerance = 0, parallelTolerance = Number.EPSILON) {
87
+ // 6 possible cases:
88
+ const otherParallel = this.getParallelLineInTheSameDirection(other, parallelTolerance);
89
+ // 1) Lines aren't parallel
90
+ if (!otherParallel) {
91
+ return null;
92
+ }
93
+ const thisContainsOtherStartPoint = this.containsPoint(otherParallel.start, distanceTolerance);
94
+ const thisContainsOtherEndPoint = this.containsPoint(otherParallel.end, distanceTolerance);
95
+ const otherContainsThisStartPoint = otherParallel.containsPoint(this.start, distanceTolerance);
96
+ const otherContainsThisEndPoint = otherParallel.containsPoint(this.end, distanceTolerance);
97
+ // 2) Lines don't overlap at all
98
+ if (!thisContainsOtherStartPoint &&
99
+ !thisContainsOtherEndPoint &&
100
+ !otherContainsThisStartPoint &&
101
+ !otherContainsThisEndPoint) {
102
+ return null;
103
+ }
104
+ // 3) This line entirely covers the other line
105
+ if (thisContainsOtherStartPoint && thisContainsOtherEndPoint) {
106
+ return this.clone();
107
+ }
108
+ // 4) The other line entirely covers this line
109
+ if (otherContainsThisStartPoint && otherContainsThisEndPoint) {
110
+ return otherParallel.clone();
111
+ }
112
+ // 5) This line is overlapped by the start of the other line
113
+ if (thisContainsOtherStartPoint && !thisContainsOtherEndPoint) {
114
+ return new Line3D(this.start, otherParallel.end);
115
+ }
116
+ // 6) This line is overlapped by the end of the other line
117
+ if (thisContainsOtherEndPoint && !thisContainsOtherStartPoint) {
118
+ return new Line3D(otherParallel.start, this.end);
119
+ }
120
+ return null;
121
+ }
122
+ /**
123
+ * Joins provided lines into several joined lines.
124
+ * Lines must be parallel for joining.
125
+ * @param lines
126
+ * @param distanceTolerance
127
+ * @param parallelTolerance
128
+ */
129
+ static joinLines(lines, distanceTolerance = 0, parallelTolerance = Number.EPSILON) {
130
+ if (lines.length < 2) {
131
+ return lines.map(x => x.clone());
132
+ }
133
+ const toProcess = lines.slice();
134
+ const result = [];
135
+ while (toProcess.length > 0) {
136
+ const current = toProcess.pop();
137
+ let joinedLine;
138
+ for (let i = 0; i < result.length; i++) {
139
+ const other = result[i];
140
+ joinedLine = current.joinLine(other, distanceTolerance, parallelTolerance);
141
+ if (joinedLine) {
142
+ result.splice(i, 1);
143
+ toProcess.push(joinedLine);
144
+ break;
145
+ }
146
+ }
147
+ if (!joinedLine) {
148
+ result.push(current.clone());
149
+ }
150
+ }
151
+ return result;
152
+ }
153
+ /**
154
+ * Returns true if this line section completely overlaps the @other line section.
155
+ * @param other
156
+ * @param tolerance
157
+ */
158
+ covers(other, tolerance = 0) {
159
+ return this.containsPoint(other.start, tolerance) && this.containsPoint(other.end, tolerance);
160
+ }
161
+ /**
162
+ * Returns true if there is any overlap between this line and the @other line section.
163
+ * @param other
164
+ * @param distanceTolerance
165
+ * @param parallelTolerance
166
+ */
167
+ overlaps(other, distanceTolerance = 0, parallelTolerance = Number.EPSILON) {
168
+ // Special case
169
+ if (this.equals(other, distanceTolerance)) {
170
+ return true;
171
+ }
172
+ // Always have to be parallel
173
+ if (this.isParallelTo(other, parallelTolerance)) {
174
+ // To pass as overlapping, at least one point has to be within the other line, but they mush not be equal - "touching" is not considered overlapping
175
+ const otherStartEqualsToAnyOfThisPoint = other.start.distanceTo(this.start) <= distanceTolerance || other.start.distanceTo(this.end) <= distanceTolerance;
176
+ if (this.containsPoint(other.start, distanceTolerance) && !otherStartEqualsToAnyOfThisPoint) {
177
+ return true;
178
+ }
179
+ const otherEndEqualsToAnyOfThisPoint = other.end.distanceTo(this.start) <= distanceTolerance || other.end.distanceTo(this.end) <= distanceTolerance;
180
+ if (this.containsPoint(other.end, distanceTolerance) && !otherEndEqualsToAnyOfThisPoint) {
181
+ return true;
182
+ }
183
+ const thisStartEqualsToAnyOfOtherPoint = this.start.distanceTo(other.start) <= distanceTolerance || this.start.distanceTo(other.end) <= distanceTolerance;
184
+ if (other.containsPoint(this.start, distanceTolerance) && !thisStartEqualsToAnyOfOtherPoint) {
185
+ return true;
186
+ }
187
+ const thisEndEqualsToAnyOfOtherPoint = this.end.distanceTo(other.start) <= distanceTolerance || this.end.distanceTo(other.end) <= distanceTolerance;
188
+ if (other.containsPoint(this.end, distanceTolerance) && !thisEndEqualsToAnyOfOtherPoint) {
189
+ return true;
190
+ }
191
+ }
192
+ return false;
193
+ }
194
+ /**
195
+ * Returns this line's length.
196
+ */
197
+ get length() {
198
+ return this.start.distanceTo(this.end);
199
+ }
200
+ /**
201
+ * Set the length of this line. Center and direction remain unchanged.
202
+ * @param length
203
+ */
204
+ setLength(length) {
205
+ const diff = length - this.length;
206
+ return this.resize(diff);
207
+ }
208
+ /**
209
+ * Returns the direction of this line.
210
+ */
211
+ get direction() {
212
+ return this.end.clone().sub(this.start).normalize();
213
+ }
214
+ /**
215
+ * Returns the center of this line
216
+ */
217
+ get center() {
218
+ return this.getCenter(new Vec3());
219
+ }
220
+ /**
221
+ * Set the center of the line to the provided point. Length and direction remain unchanged.
222
+ * @param value
223
+ */
224
+ setCenter(value) {
225
+ const current = this.center;
226
+ const diffX = current.x - value.x;
227
+ const diffY = current.y - value.y;
228
+ const diffZ = current.z - value.z;
229
+ this.start.x -= diffX;
230
+ this.start.y -= diffY;
231
+ this.start.z -= diffZ;
232
+ this.end.x -= diffX;
233
+ this.end.y -= diffY;
234
+ this.end.z -= diffZ;
235
+ return this;
236
+ }
237
+ /** Returns the start and end points of the line as an array. */
238
+ get endpoints() {
239
+ return [this.start, this.end];
240
+ }
241
+ /**
242
+ * Check that this line section contains provided point.
243
+ * @param p
244
+ * @param tolerance
245
+ */
246
+ containsPoint(p, tolerance = 0) {
247
+ const closestPointToPoint = this.closestPointToPoint(p, true, this.#target);
248
+ return closestPointToPoint.distanceTo(p) <= tolerance;
249
+ }
250
+ /**
251
+ * Distance from this line to provided point.
252
+ * @param p
253
+ * @param clampToLine
254
+ */
255
+ distanceToPoint(p, clampToLine = true) {
256
+ const closestPointToPoint = this.closestPointToPoint(p, clampToLine, this.#target);
257
+ return closestPointToPoint.distanceTo(p);
258
+ }
259
+ /**
260
+ * Returns a copy of @other line, the direction of @other is reversed if needed.
261
+ * Returns null if lines are not parallel.
262
+ * @param other
263
+ * @param tolerance
264
+ */
265
+ getParallelLineInTheSameDirection(other, tolerance = Number.EPSILON) {
266
+ const direction = this.direction;
267
+ const areTheSameDirection = direction.manhattanDistanceTo(other.direction) < tolerance;
268
+ if (areTheSameDirection) {
269
+ return other.clone();
270
+ }
271
+ const otherLineOppositeDirection = new Line3D(other.end, other.start);
272
+ if (otherLineOppositeDirection.direction.manhattanDistanceTo(direction) < tolerance) {
273
+ return otherLineOppositeDirection;
274
+ }
275
+ return null;
276
+ }
277
+ /**
278
+ * Check if @other is parallel to this line.
279
+ * @param other
280
+ * @param tolerance
281
+ */
282
+ isParallelTo(other, tolerance = Number.EPSILON) {
283
+ const direction = this.direction;
284
+ const otherDirection = other.direction;
285
+ const areTheSameDirection = direction.manhattanDistanceTo(otherDirection) <= tolerance;
286
+ if (areTheSameDirection) {
287
+ return true;
288
+ }
289
+ return direction.negate().manhattanDistanceTo(otherDirection) < tolerance;
290
+ }
291
+ /*
292
+ * Extends or reduces the line to the given length while keeping the center of the line constant.
293
+ */
294
+ resize(amount) {
295
+ this.moveStartPoint(amount / 2);
296
+ this.moveEndPoint(amount / 2);
297
+ return this;
298
+ }
299
+ /*
300
+ * Moves start on the line by the given amount. Plus values move the point further away from the center.
301
+ */
302
+ moveStartPoint(amount) {
303
+ const start = this.movePointOnThisLine(this.start, amount);
304
+ this.start.x = start.x;
305
+ this.start.y = start.y;
306
+ this.start.z = start.z;
307
+ return this;
308
+ }
309
+ /*
310
+ * Moves end on the line by the given amount in the current direction. Plus values move the point further away from the center.
311
+ */
312
+ moveEndPoint(amount) {
313
+ const end = this.movePointOnThisLine(this.end, amount);
314
+ this.end.x = end.x;
315
+ this.end.y = end.y;
316
+ this.end.z = end.z;
317
+ return this;
318
+ }
319
+ /**
320
+ * Returns a new line that is the projection of this line onto @other. Uses `closestPointToPoint` to find the projection.
321
+ * @param other
322
+ * @param clampToLine
323
+ */
324
+ projectOn(other, clampToLine) {
325
+ const p1 = other.closestPointToPoint(this.start, clampToLine, new Vec3());
326
+ const p2 = other.closestPointToPoint(this.end, clampToLine, new Vec3());
327
+ return p1.distanceTo(this.start) < p2.distanceTo(this.start) ? new Line3D(p1, p2) : new Line3D(p2, p1);
328
+ }
329
+ /**
330
+ * Divides the Line3D into a number of segments of the given length.
331
+ * @param maxSegmentLength number
332
+ */
333
+ chunk(maxSegmentLength) {
334
+ const source = this.clone();
335
+ const result = [];
336
+ while (source.length > maxSegmentLength) {
337
+ const chunk = source.clone();
338
+ chunk.moveEndPoint(-(chunk.length - maxSegmentLength));
339
+ result.push(chunk);
340
+ source.start.copy(chunk.end);
341
+ }
342
+ if (source.length > 0) {
343
+ result.push(source);
344
+ }
345
+ return result;
346
+ }
347
+ /**
348
+ * Note that this works well for moving the endpoints as it's currently used
349
+ * If it were to be made public, it would need to handle the situation where the point to move is in the center of the line which would require a different approach
350
+ */
351
+ movePointOnThisLine(point, amount) {
352
+ const center = this.getCenter(this.#target);
353
+ const vec = new Vec3(center.x - point.x, center.y - point.y, center.z - point.z);
354
+ const length = vec.length();
355
+ vec.normalize().multiplyScalar(length + amount);
356
+ return new Vec3(center.x - vec.x, center.y - vec.y, center.z - vec.z);
357
+ }
358
+ /**
359
+ * Move this line by the given vector.
360
+ * @param p
361
+ */
362
+ translate(p) {
363
+ this.start.add(p);
364
+ this.end.add(p);
365
+ return this;
366
+ }
367
+ /**
368
+ * Project the line to 2D space, Y value is dropped
369
+ */
370
+ onPlan() {
371
+ return new Line2D(this.start.onPlan(), this.end.onPlan());
372
+ }
373
+ /**
374
+ * Equals with tolerance
375
+ */
376
+ equals(other, tolerance = 0) {
377
+ return !!other && this.start.distanceTo(other.start) <= tolerance && this.end.distanceTo(other.end) <= tolerance;
378
+ }
379
+ /**
380
+ * Deep clone of this line
381
+ */
382
+ clone() {
383
+ return new Line3D(this.start.clone(), this.end.clone());
384
+ }
385
+ toString() {
386
+ return `Line3D { start: ${this.start.x}, ${this.start.y}, ${this.start.z}, end: ${this.end.x}, ${this.end.y}, ${this.end.z}}`;
387
+ }
388
+ }
package/esm/Point2.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/esm/Point3.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/esm/Vec2.js ADDED
@@ -0,0 +1,19 @@
1
+ import { Vector2 } from "three";
2
+ import { Vec3 } from "./Vec3";
3
+ export class Vec2 extends Vector2 {
4
+ static fromPoint(point) {
5
+ return new Vec2(point.x, point.y);
6
+ }
7
+ roundIfCloseToInteger(max = 0.000000000001) {
8
+ if (Math.abs(this.x - Math.round(this.x)) < max) {
9
+ this.x = Math.round(this.x);
10
+ }
11
+ if (Math.abs(this.y - Math.round(this.y)) < max) {
12
+ this.y = Math.round(this.y);
13
+ }
14
+ return this;
15
+ }
16
+ in3DSpace(z = 0) {
17
+ return new Vec3(this.x, z, this.y);
18
+ }
19
+ }
package/esm/Vec3.js ADDED
@@ -0,0 +1,53 @@
1
+ import { Vector3 } from "three";
2
+ import { Vec2 } from "./Vec2";
3
+ export class Vec3 extends Vector3 {
4
+ #target;
5
+ static fromPoint(point) {
6
+ return new Vec3(point.x, point.y, point.z);
7
+ }
8
+ moveTowards(target, amount) {
9
+ if (this.#target === undefined) {
10
+ this.#target = new Vector3();
11
+ }
12
+ this.#target.copy(target);
13
+ this.add(this.#target.sub(this).normalize().multiplyScalar(amount));
14
+ return this;
15
+ }
16
+ centerTowards(target) {
17
+ if (this.#target === undefined) {
18
+ this.#target = new Vector3();
19
+ }
20
+ return this.moveTowards(target, this.distanceTo(target) / 2);
21
+ }
22
+ addY(y) {
23
+ this.y += y;
24
+ return this;
25
+ }
26
+ addX(x) {
27
+ this.x += x;
28
+ return this;
29
+ }
30
+ scale(p) {
31
+ this.x *= p.x;
32
+ this.y *= p.y;
33
+ this.z *= p.z;
34
+ return this;
35
+ }
36
+ closest(...points) {
37
+ const withDistances = points.map(p => ({ point: p, distance: this.distanceTo(p) }));
38
+ const closest = withDistances.reduce((a, b) => a.distance < b.distance ? a : b);
39
+ return Vec3.fromPoint(closest.point);
40
+ }
41
+ toPointWithFlippedYZ() {
42
+ return new Vec3(this.x, this.z, this.y);
43
+ }
44
+ onPlan() {
45
+ return new Vec2(this.x, this.z);
46
+ }
47
+ horizontalDistanceTo(point) {
48
+ return new Vector3(this.x, 0, this.z).distanceTo(new Vector3(point.x, 0, point.z));
49
+ }
50
+ clone() {
51
+ return super.clone();
52
+ }
53
+ }
package/esm/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { Vec2 } from "./Vec2";
2
+ export { Vec3 } from "./Vec3";
3
+ export { Line2D } from "./Line2D";
4
+ export { Line3D } from "./Line3D";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@immugio/three-math-extensions",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
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",
@@ -0,0 +1,215 @@
1
+ import { Point2 } from "./Point2";
2
+ import { Vector2 } from "three";
3
+ import { Vec2 } from "./Vec2";
4
+ export declare class Line2D {
5
+ start: Vec2;
6
+ end: Vec2;
7
+ index: number;
8
+ constructor(start: Vec2, end: Vec2, index?: number);
9
+ static fromCoordinates(x1: number, y1: number, x2: number, y2: number, index?: number): Line2D;
10
+ static fromPoints(p1: Point2, p2: Point2, index?: number): Line2D;
11
+ /**
12
+ * Creates a polygon formed by an array of lines from points provided.
13
+ * The polygon will only be closed if either
14
+ * 1) the first and last points are the same or 2) `forceClosedPolygon` is true.
15
+ */
16
+ static fromPolygon(polygon: Point2[], forceClosedPolygon?: boolean): Line2D[];
17
+ static fromLength(length: number): Line2D;
18
+ get center(): Vec2;
19
+ /**
20
+ * Set the center of the line to the provided point. Length and direction remain unchanged.
21
+ * Modifies this line.
22
+ * @param value
23
+ */
24
+ set center(value: Point2);
25
+ /**
26
+ * Set the center of the line to the provided point. Length and direction remain unchanged.
27
+ * Modifies this line.
28
+ * @param value
29
+ */
30
+ setCenter(value: Point2): Line2D;
31
+ resize(amount: number): Line2D;
32
+ moveStartPoint(amount: number): Line2D;
33
+ /**
34
+ * Moves end point on the line by the given amount. Plus values move the point further away from the center.
35
+ * Modifies this line.
36
+ */
37
+ moveEndPoint(amount: number): Line2D;
38
+ private movePointOnThisLine;
39
+ /**
40
+ * Set the length of this line. Center and direction remain unchanged.
41
+ * Modifies this line.
42
+ * @param l
43
+ */
44
+ set length(l: number);
45
+ get length(): number;
46
+ /**
47
+ * Set the length of this line. Center and direction remain unchanged.
48
+ * @param length
49
+ */
50
+ setLength(length: number): this;
51
+ /**
52
+ * Returns the start and end points of the line as an array.
53
+ * Endpoints are not cloned.
54
+ */
55
+ get endpoints(): Vec2[];
56
+ /**
57
+ * Returns the direction of this line.
58
+ */
59
+ get direction(): Vec2;
60
+ /**
61
+ * Inverts the direction of the line.
62
+ * Modifies this line.
63
+ */
64
+ flip(): Line2D;
65
+ /**
66
+ * Rotates the line around the center by the given angle in radians.
67
+ * Modifies this line.
68
+ * @param radians Positive values rotate counter-clockwise.
69
+ * @param center
70
+ */
71
+ rotate(radians: number, center?: Vec2): Line2D;
72
+ /**
73
+ * Move the line by the given vector.
74
+ * Modifies this line.
75
+ */
76
+ translate(value: Point2): Line2D;
77
+ /**
78
+ * Move the line to its left by the given amount.
79
+ * Modifies this line.
80
+ */
81
+ translateLeft(amount: number): Line2D;
82
+ /**
83
+ * Move the line to its right by the given amount.
84
+ * Modifies this line.
85
+ */
86
+ translateRight(amount: number): Line2D;
87
+ /**
88
+ * Returns true when the point is actually inside the (finite) line segment.
89
+ * https://jsfiddle.net/c06zdxtL/2/
90
+ * https://stackoverflow.com/questions/6865832/detecting-if-a-point-is-of-a-line-segment/6877674
91
+ * @param point: Point2
92
+ */
93
+ isPointOnLineSection(point: Point2): boolean;
94
+ /**
95
+ * Returns true when the point is beside the line **segment** and within the maxDistance.
96
+ * @param point
97
+ * @param maxDistance
98
+ */
99
+ isPointCloseToAndBesideLineSection(point: Point2, maxDistance: number): boolean;
100
+ /**
101
+ * Returns true when the point is beside the line **segment**
102
+ * @param point
103
+ */
104
+ isPointBesideLineSection(point: Point2): boolean;
105
+ /**
106
+ * Returns true when the point is on the **infinite** line.
107
+ * @param point
108
+ */
109
+ isPointOnInfiniteLine(point: Point2): boolean;
110
+ /**
111
+ * Returns true if other line is collinear and overlaps or at least touching this line.
112
+ * @param other
113
+ */
114
+ isCollinearWithTouchOrOverlap(other: Line2D): boolean;
115
+ /**
116
+ * Returns true if there is any overlap between this line and the @other line section.
117
+ */
118
+ overlaps(other: Line2D): boolean;
119
+ /**
120
+ * Logical AND of this and the other line section.
121
+ * @param other
122
+ */
123
+ getOverlap(other: Line2D): Line2D;
124
+ /**
125
+ * Joins a copy of @line with the @other line.
126
+ * Other must be parallel to this line.
127
+ * Returns null if there is no overlap
128
+ * Clones the line, does not modify.
129
+ * @param line
130
+ * @param other
131
+ */
132
+ static joinLine(line: Line2D, other: Line2D): Line2D;
133
+ /**
134
+ * Joins provided lines into several joined lines.
135
+ * Lines must be parallel for joining.
136
+ * Clone the lines, does not modify.
137
+ * @param lines
138
+ */
139
+ static joinLines(lines: Line2D[]): Line2D[];
140
+ /**
141
+ * Divides the Line3D into a number of segments of the given length.
142
+ * Clone the line, does not modify.
143
+ * @param maxSegmentLength number
144
+ */
145
+ chunk(maxSegmentLength: number): Line2D[];
146
+ /**
147
+ * Returns the closest point parameter on the **infinite** line to the given point.
148
+ * @param point
149
+ */
150
+ closestPointToPointParameterOnInfiniteLine(point: Vector2): number;
151
+ /**
152
+ * Returns the closest point on the **infinite** line to the given point.
153
+ * @param point
154
+ */
155
+ closestPointOnInfiniteLine(point: Vector2): Vec2;
156
+ /**
157
+ * Returns the closest point on the line **section** to the given point.
158
+ * @param point
159
+ */
160
+ closestPointOnLine(point: Vector2): Vec2;
161
+ /**
162
+ * Returns the distance between the **infinite** line and the point.
163
+ * @param point
164
+ */
165
+ distanceToPointOnInfiniteLine(point: Point2): number;
166
+ /**
167
+ * Returns lines that are the result of clipping @source line by the @clips.
168
+ * Clips must be parallel to this line.
169
+ * Clones the line, does not modify this.
170
+ * @param source
171
+ * @param clips
172
+ */
173
+ static clipLines(source: Line2D, clips: Line2D[]): Line2D[];
174
+ /**
175
+ * Returns the original line section split into two parts, if the line **sections** overlap, otherwise null
176
+ */
177
+ splitAtIntersection(other: Line2D, tolerance?: number): Line2D[];
178
+ /**
179
+ * If lines **sections** overlap, returns the original line section split into two parts, sorted by length
180
+ * Else, if the **infinite** lines intersect, returns a new line extended to the intersection point
181
+ * Otherwise, null if the lines are parallel and do not intersect
182
+ */
183
+ splitAtOrExtendToIntersection(other: Line2D): Line2D[];
184
+ private static order;
185
+ private static subtractSingle;
186
+ /**
187
+ * If other line is not contained within this line, the excess is trimmed.
188
+ * Does not create a copy. Provided line is modified.
189
+ * @param lineToTrim
190
+ */
191
+ trimExcess(lineToTrim: Line2D): void;
192
+ /**
193
+ * If other line is shorter than this, endpoints are moved to extend other
194
+ * Does not create a copy. Provided line is modified.
195
+ * @param lineToExtend
196
+ * @param tolerance
197
+ */
198
+ extendToEnds(lineToExtend: Line2D, tolerance: number): void;
199
+ /**
200
+ * Returns the intersection point of two lines. The lines are assumed to be infinite.
201
+ */
202
+ intersect(other: Line2D): Vec2;
203
+ /**
204
+ * Check that the infinite lines intersect and that they are in the specified angle to each other
205
+ * @param other Line
206
+ * @param expectedAngleInRads number
207
+ */
208
+ hasIntersectionWithAngle(other: Line2D, expectedAngleInRads: number): Vec2;
209
+ /**
210
+ * Deep clone of this line
211
+ */
212
+ clone(): Line2D;
213
+ toString(): string;
214
+ equals(other: Line2D): boolean;
215
+ }