@js-draw/math 1.9.0 → 1.10.0
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/dist/cjs/lib.d.ts +1 -0
- package/dist/cjs/lib.js +3 -1
- package/dist/cjs/shapes/Abstract2DShape.d.ts +4 -1
- package/dist/cjs/shapes/Abstract2DShape.js +6 -0
- package/dist/cjs/shapes/Path.d.ts +40 -7
- package/dist/cjs/shapes/Path.js +40 -6
- package/dist/mjs/lib.d.ts +1 -0
- package/dist/mjs/lib.mjs +1 -0
- package/dist/mjs/shapes/Abstract2DShape.d.ts +4 -1
- package/dist/mjs/shapes/Abstract2DShape.mjs +5 -1
- package/dist/mjs/shapes/Path.d.ts +40 -7
- package/dist/mjs/shapes/Path.mjs +40 -6
- package/package.json +2 -2
- package/src/lib.ts +1 -0
- package/src/shapes/Abstract2DShape.ts +5 -1
- package/src/shapes/Path.toString.test.ts +5 -5
- package/src/shapes/Path.ts +53 -14
package/dist/cjs/lib.d.ts
CHANGED
@@ -20,6 +20,7 @@ export { LineSegment2 } from './shapes/LineSegment2';
|
|
20
20
|
export { Path, PathCommandType, PathCommand, LinePathCommand, MoveToPathCommand, QuadraticBezierPathCommand, CubicBezierPathCommand, } from './shapes/Path';
|
21
21
|
export { Rect2 } from './shapes/Rect2';
|
22
22
|
export { QuadraticBezier } from './shapes/QuadraticBezier';
|
23
|
+
export { Abstract2DShape } from './shapes/Abstract2DShape';
|
23
24
|
export { Mat33, Mat33Array } from './Mat33';
|
24
25
|
export { Point2, Vec2 } from './Vec2';
|
25
26
|
export { Vec3 } from './Vec3';
|
package/dist/cjs/lib.js
CHANGED
@@ -18,7 +18,7 @@
|
|
18
18
|
* @packageDocumentation
|
19
19
|
*/
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
21
|
-
exports.toRoundedString = exports.Color4 = exports.Vec3 = exports.Vec2 = exports.Mat33 = exports.QuadraticBezier = exports.Rect2 = exports.PathCommandType = exports.Path = exports.LineSegment2 = void 0;
|
21
|
+
exports.toRoundedString = exports.Color4 = exports.Vec3 = exports.Vec2 = exports.Mat33 = exports.Abstract2DShape = exports.QuadraticBezier = exports.Rect2 = exports.PathCommandType = exports.Path = exports.LineSegment2 = void 0;
|
22
22
|
var LineSegment2_1 = require("./shapes/LineSegment2");
|
23
23
|
Object.defineProperty(exports, "LineSegment2", { enumerable: true, get: function () { return LineSegment2_1.LineSegment2; } });
|
24
24
|
var Path_1 = require("./shapes/Path");
|
@@ -28,6 +28,8 @@ var Rect2_1 = require("./shapes/Rect2");
|
|
28
28
|
Object.defineProperty(exports, "Rect2", { enumerable: true, get: function () { return Rect2_1.Rect2; } });
|
29
29
|
var QuadraticBezier_1 = require("./shapes/QuadraticBezier");
|
30
30
|
Object.defineProperty(exports, "QuadraticBezier", { enumerable: true, get: function () { return QuadraticBezier_1.QuadraticBezier; } });
|
31
|
+
var Abstract2DShape_1 = require("./shapes/Abstract2DShape");
|
32
|
+
Object.defineProperty(exports, "Abstract2DShape", { enumerable: true, get: function () { return Abstract2DShape_1.Abstract2DShape; } });
|
31
33
|
var Mat33_1 = require("./Mat33");
|
32
34
|
Object.defineProperty(exports, "Mat33", { enumerable: true, get: function () { return Mat33_1.Mat33; } });
|
33
35
|
var Vec2_1 = require("./Vec2");
|
@@ -1,7 +1,10 @@
|
|
1
1
|
import LineSegment2 from './LineSegment2';
|
2
2
|
import { Point2 } from '../Vec2';
|
3
3
|
import Rect2 from './Rect2';
|
4
|
-
|
4
|
+
/**
|
5
|
+
* An abstract base class for 2D shapes.
|
6
|
+
*/
|
7
|
+
export declare abstract class Abstract2DShape {
|
5
8
|
protected static readonly smallValue = 1e-12;
|
6
9
|
/**
|
7
10
|
* @returns the distance from `point` to this shape. If `point` is within this shape,
|
@@ -1,5 +1,9 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.Abstract2DShape = void 0;
|
4
|
+
/**
|
5
|
+
* An abstract base class for 2D shapes.
|
6
|
+
*/
|
3
7
|
class Abstract2DShape {
|
4
8
|
/**
|
5
9
|
* @returns the distance from `point` to this shape. If `point` is within this shape,
|
@@ -34,5 +38,7 @@ class Abstract2DShape {
|
|
34
38
|
return this.getTightBoundingBox();
|
35
39
|
}
|
36
40
|
}
|
41
|
+
exports.Abstract2DShape = Abstract2DShape;
|
42
|
+
// @internal
|
37
43
|
Abstract2DShape.smallValue = 1e-12;
|
38
44
|
exports.default = Abstract2DShape;
|
@@ -35,24 +35,29 @@ interface IntersectionResult {
|
|
35
35
|
parameterValue?: number;
|
36
36
|
point: Point2;
|
37
37
|
}
|
38
|
-
type GeometryType = Abstract2DShape;
|
39
|
-
type GeometryArrayType = Array<GeometryType>;
|
40
38
|
/**
|
41
39
|
* Represents a union of lines and curves.
|
42
40
|
*/
|
43
41
|
export declare class Path {
|
44
42
|
readonly startPoint: Point2;
|
45
|
-
readonly parts: PathCommand[];
|
46
43
|
/**
|
47
44
|
* A rough estimate of the bounding box of the path.
|
48
45
|
* A slight overestimate.
|
49
46
|
* See {@link getExactBBox}
|
50
47
|
*/
|
51
48
|
readonly bbox: Rect2;
|
52
|
-
|
49
|
+
/** The individual shapes that make up this path. */
|
50
|
+
readonly parts: Readonly<PathCommand>[];
|
51
|
+
/**
|
52
|
+
* Creates a new `Path` that starts at `startPoint` and is made up of the path commands,
|
53
|
+
* `parts`.
|
54
|
+
*
|
55
|
+
* See also {@link fromString}
|
56
|
+
*/
|
57
|
+
constructor(startPoint: Point2, parts: Readonly<PathCommand>[]);
|
53
58
|
getExactBBox(): Rect2;
|
54
59
|
private cachedGeometry;
|
55
|
-
get geometry():
|
60
|
+
get geometry(): Abstract2DShape[];
|
56
61
|
/**
|
57
62
|
* Iterates through the start/end points of each component in this path.
|
58
63
|
*
|
@@ -77,6 +82,8 @@ export declare class Path {
|
|
77
82
|
* intersections are approximated with the surface `strokeRadius` away from this.
|
78
83
|
*
|
79
84
|
* If `strokeRadius > 0`, the resultant `parameterValue` has no defined value.
|
85
|
+
*
|
86
|
+
* **Note**: `strokeRadius` is half of a stroke's width.
|
80
87
|
*/
|
81
88
|
intersection(line: LineSegment2, strokeRadius?: number): IntersectionResult[];
|
82
89
|
private static mapPathCommand;
|
@@ -84,6 +91,16 @@ export declare class Path {
|
|
84
91
|
transformedBy(affineTransfm: Mat33): Path;
|
85
92
|
union(other: Path | null): Path;
|
86
93
|
private getEndPoint;
|
94
|
+
/**
|
95
|
+
* Like {@link closedRoughlyIntersects} except takes stroke width into account.
|
96
|
+
*
|
97
|
+
* This is intended to be a very fast and rough approximation. Use {@link intersection}
|
98
|
+
* and {@link signedDistance} for more accurate (but much slower) intersection calculations.
|
99
|
+
*
|
100
|
+
* **Note**: Unlike other methods, this accepts `strokeWidth` (and not `strokeRadius`).
|
101
|
+
*
|
102
|
+
* `strokeRadius` is half of `strokeWidth`.
|
103
|
+
*/
|
87
104
|
roughlyIntersects(rect: Rect2, strokeWidth?: number): boolean;
|
88
105
|
closedRoughlyIntersects(rect: Rect2): boolean;
|
89
106
|
/**
|
@@ -95,16 +112,32 @@ export declare class Path {
|
|
95
112
|
*/
|
96
113
|
static fromRect(rect: Rect2, lineWidth?: number | null): Path;
|
97
114
|
private cachedStringVersion;
|
98
|
-
|
115
|
+
/**
|
116
|
+
* Convert to an [SVG path representation](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths).
|
117
|
+
*
|
118
|
+
* If `useNonAbsCommands` is given, relative path commands (e.g. `l10,0`) are to be used instead of
|
119
|
+
* absolute commands (e.g. `L10,0`).
|
120
|
+
*
|
121
|
+
* See also {@link fromString}.
|
122
|
+
*/
|
123
|
+
toString(useNonAbsCommands?: boolean, ignoreCache?: boolean): string;
|
99
124
|
serialize(): string;
|
100
125
|
static toString(startPoint: Point2, parts: PathCommand[], onlyAbsCommands?: boolean): string;
|
101
126
|
/**
|
102
|
-
* Create a Path from a SVG path specification.
|
127
|
+
* Create a `Path` from a subset of the SVG path specification.
|
103
128
|
*
|
104
129
|
* ## To-do
|
105
130
|
* - TODO: Support a larger subset of SVG paths
|
106
131
|
* - Elliptical arcs are currently unsupported.
|
107
132
|
* - TODO: Support `s`,`t` commands shorthands.
|
133
|
+
*
|
134
|
+
* @example
|
135
|
+
* ```ts,runnable,console
|
136
|
+
* import { Path } from '@js-draw/math';
|
137
|
+
*
|
138
|
+
* const path = Path.fromString('m0,0l100,100');
|
139
|
+
* console.log(path.toString(true)); // true: Prefer relative to absolute path commands
|
140
|
+
* ```
|
108
141
|
*/
|
109
142
|
static fromString(pathString: string): Path;
|
110
143
|
static empty: Path;
|
package/dist/cjs/shapes/Path.js
CHANGED
@@ -22,17 +22,23 @@ var PathCommandType;
|
|
22
22
|
* Represents a union of lines and curves.
|
23
23
|
*/
|
24
24
|
class Path {
|
25
|
+
/**
|
26
|
+
* Creates a new `Path` that starts at `startPoint` and is made up of the path commands,
|
27
|
+
* `parts`.
|
28
|
+
*
|
29
|
+
* See also {@link fromString}
|
30
|
+
*/
|
25
31
|
constructor(startPoint, parts) {
|
26
32
|
this.startPoint = startPoint;
|
27
|
-
this.parts = parts;
|
28
33
|
this.cachedGeometry = null;
|
29
34
|
this.cachedPolylineApproximation = null;
|
30
35
|
this.cachedStringVersion = null;
|
36
|
+
this.parts = parts;
|
31
37
|
// Initial bounding box contains one point: the start point.
|
32
38
|
this.bbox = Rect2_1.default.bboxOf([startPoint]);
|
33
39
|
// Convert into a representation of the geometry (cache for faster intersection
|
34
40
|
// calculation)
|
35
|
-
for (const part of parts) {
|
41
|
+
for (const part of this.parts) {
|
36
42
|
this.bbox = this.bbox.union(Path.computeBBoxForSegment(startPoint, part));
|
37
43
|
}
|
38
44
|
}
|
@@ -337,6 +343,8 @@ class Path {
|
|
337
343
|
* intersections are approximated with the surface `strokeRadius` away from this.
|
338
344
|
*
|
339
345
|
* If `strokeRadius > 0`, the resultant `parameterValue` has no defined value.
|
346
|
+
*
|
347
|
+
* **Note**: `strokeRadius` is half of a stroke's width.
|
340
348
|
*/
|
341
349
|
intersection(line, strokeRadius) {
|
342
350
|
let result = [];
|
@@ -432,6 +440,16 @@ class Path {
|
|
432
440
|
return lastPart.point;
|
433
441
|
}
|
434
442
|
}
|
443
|
+
/**
|
444
|
+
* Like {@link closedRoughlyIntersects} except takes stroke width into account.
|
445
|
+
*
|
446
|
+
* This is intended to be a very fast and rough approximation. Use {@link intersection}
|
447
|
+
* and {@link signedDistance} for more accurate (but much slower) intersection calculations.
|
448
|
+
*
|
449
|
+
* **Note**: Unlike other methods, this accepts `strokeWidth` (and not `strokeRadius`).
|
450
|
+
*
|
451
|
+
* `strokeRadius` is half of `strokeWidth`.
|
452
|
+
*/
|
435
453
|
roughlyIntersects(rect, strokeWidth = 0) {
|
436
454
|
if (this.parts.length === 0) {
|
437
455
|
return rect.containsPoint(this.startPoint);
|
@@ -459,7 +477,7 @@ class Path {
|
|
459
477
|
}
|
460
478
|
return false;
|
461
479
|
}
|
462
|
-
// Treats this as a closed path and returns true if part of `rect` is roughly within
|
480
|
+
// Treats this as a closed path and returns true if part of `rect` is *roughly* within
|
463
481
|
// this path's interior.
|
464
482
|
//
|
465
483
|
// Note: Assumes that this is a closed, non-self-intersecting path.
|
@@ -541,8 +559,16 @@ class Path {
|
|
541
559
|
});
|
542
560
|
return new Path(startPoint, commands);
|
543
561
|
}
|
544
|
-
|
545
|
-
|
562
|
+
/**
|
563
|
+
* Convert to an [SVG path representation](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths).
|
564
|
+
*
|
565
|
+
* If `useNonAbsCommands` is given, relative path commands (e.g. `l10,0`) are to be used instead of
|
566
|
+
* absolute commands (e.g. `L10,0`).
|
567
|
+
*
|
568
|
+
* See also {@link fromString}.
|
569
|
+
*/
|
570
|
+
toString(useNonAbsCommands, ignoreCache = false) {
|
571
|
+
if (this.cachedStringVersion && !ignoreCache) {
|
546
572
|
return this.cachedStringVersion;
|
547
573
|
}
|
548
574
|
if (useNonAbsCommands === undefined) {
|
@@ -632,12 +658,20 @@ class Path {
|
|
632
658
|
return result.join('');
|
633
659
|
}
|
634
660
|
/**
|
635
|
-
* Create a Path from a SVG path specification.
|
661
|
+
* Create a `Path` from a subset of the SVG path specification.
|
636
662
|
*
|
637
663
|
* ## To-do
|
638
664
|
* - TODO: Support a larger subset of SVG paths
|
639
665
|
* - Elliptical arcs are currently unsupported.
|
640
666
|
* - TODO: Support `s`,`t` commands shorthands.
|
667
|
+
*
|
668
|
+
* @example
|
669
|
+
* ```ts,runnable,console
|
670
|
+
* import { Path } from '@js-draw/math';
|
671
|
+
*
|
672
|
+
* const path = Path.fromString('m0,0l100,100');
|
673
|
+
* console.log(path.toString(true)); // true: Prefer relative to absolute path commands
|
674
|
+
* ```
|
641
675
|
*/
|
642
676
|
static fromString(pathString) {
|
643
677
|
// See the MDN reference:
|
package/dist/mjs/lib.d.ts
CHANGED
@@ -20,6 +20,7 @@ export { LineSegment2 } from './shapes/LineSegment2';
|
|
20
20
|
export { Path, PathCommandType, PathCommand, LinePathCommand, MoveToPathCommand, QuadraticBezierPathCommand, CubicBezierPathCommand, } from './shapes/Path';
|
21
21
|
export { Rect2 } from './shapes/Rect2';
|
22
22
|
export { QuadraticBezier } from './shapes/QuadraticBezier';
|
23
|
+
export { Abstract2DShape } from './shapes/Abstract2DShape';
|
23
24
|
export { Mat33, Mat33Array } from './Mat33';
|
24
25
|
export { Point2, Vec2 } from './Vec2';
|
25
26
|
export { Vec3 } from './Vec3';
|
package/dist/mjs/lib.mjs
CHANGED
@@ -20,6 +20,7 @@ export { LineSegment2 } from './shapes/LineSegment2.mjs';
|
|
20
20
|
export { Path, PathCommandType, } from './shapes/Path.mjs';
|
21
21
|
export { Rect2 } from './shapes/Rect2.mjs';
|
22
22
|
export { QuadraticBezier } from './shapes/QuadraticBezier.mjs';
|
23
|
+
export { Abstract2DShape } from './shapes/Abstract2DShape.mjs';
|
23
24
|
export { Mat33 } from './Mat33.mjs';
|
24
25
|
export { Vec2 } from './Vec2.mjs';
|
25
26
|
export { Vec3 } from './Vec3.mjs';
|
@@ -1,7 +1,10 @@
|
|
1
1
|
import LineSegment2 from './LineSegment2';
|
2
2
|
import { Point2 } from '../Vec2';
|
3
3
|
import Rect2 from './Rect2';
|
4
|
-
|
4
|
+
/**
|
5
|
+
* An abstract base class for 2D shapes.
|
6
|
+
*/
|
7
|
+
export declare abstract class Abstract2DShape {
|
5
8
|
protected static readonly smallValue = 1e-12;
|
6
9
|
/**
|
7
10
|
* @returns the distance from `point` to this shape. If `point` is within this shape,
|
@@ -1,4 +1,7 @@
|
|
1
|
-
|
1
|
+
/**
|
2
|
+
* An abstract base class for 2D shapes.
|
3
|
+
*/
|
4
|
+
export class Abstract2DShape {
|
2
5
|
/**
|
3
6
|
* @returns the distance from `point` to this shape. If `point` is within this shape,
|
4
7
|
* this returns the distance from `point` to the edge of this shape.
|
@@ -32,5 +35,6 @@ class Abstract2DShape {
|
|
32
35
|
return this.getTightBoundingBox();
|
33
36
|
}
|
34
37
|
}
|
38
|
+
// @internal
|
35
39
|
Abstract2DShape.smallValue = 1e-12;
|
36
40
|
export default Abstract2DShape;
|
@@ -35,24 +35,29 @@ interface IntersectionResult {
|
|
35
35
|
parameterValue?: number;
|
36
36
|
point: Point2;
|
37
37
|
}
|
38
|
-
type GeometryType = Abstract2DShape;
|
39
|
-
type GeometryArrayType = Array<GeometryType>;
|
40
38
|
/**
|
41
39
|
* Represents a union of lines and curves.
|
42
40
|
*/
|
43
41
|
export declare class Path {
|
44
42
|
readonly startPoint: Point2;
|
45
|
-
readonly parts: PathCommand[];
|
46
43
|
/**
|
47
44
|
* A rough estimate of the bounding box of the path.
|
48
45
|
* A slight overestimate.
|
49
46
|
* See {@link getExactBBox}
|
50
47
|
*/
|
51
48
|
readonly bbox: Rect2;
|
52
|
-
|
49
|
+
/** The individual shapes that make up this path. */
|
50
|
+
readonly parts: Readonly<PathCommand>[];
|
51
|
+
/**
|
52
|
+
* Creates a new `Path` that starts at `startPoint` and is made up of the path commands,
|
53
|
+
* `parts`.
|
54
|
+
*
|
55
|
+
* See also {@link fromString}
|
56
|
+
*/
|
57
|
+
constructor(startPoint: Point2, parts: Readonly<PathCommand>[]);
|
53
58
|
getExactBBox(): Rect2;
|
54
59
|
private cachedGeometry;
|
55
|
-
get geometry():
|
60
|
+
get geometry(): Abstract2DShape[];
|
56
61
|
/**
|
57
62
|
* Iterates through the start/end points of each component in this path.
|
58
63
|
*
|
@@ -77,6 +82,8 @@ export declare class Path {
|
|
77
82
|
* intersections are approximated with the surface `strokeRadius` away from this.
|
78
83
|
*
|
79
84
|
* If `strokeRadius > 0`, the resultant `parameterValue` has no defined value.
|
85
|
+
*
|
86
|
+
* **Note**: `strokeRadius` is half of a stroke's width.
|
80
87
|
*/
|
81
88
|
intersection(line: LineSegment2, strokeRadius?: number): IntersectionResult[];
|
82
89
|
private static mapPathCommand;
|
@@ -84,6 +91,16 @@ export declare class Path {
|
|
84
91
|
transformedBy(affineTransfm: Mat33): Path;
|
85
92
|
union(other: Path | null): Path;
|
86
93
|
private getEndPoint;
|
94
|
+
/**
|
95
|
+
* Like {@link closedRoughlyIntersects} except takes stroke width into account.
|
96
|
+
*
|
97
|
+
* This is intended to be a very fast and rough approximation. Use {@link intersection}
|
98
|
+
* and {@link signedDistance} for more accurate (but much slower) intersection calculations.
|
99
|
+
*
|
100
|
+
* **Note**: Unlike other methods, this accepts `strokeWidth` (and not `strokeRadius`).
|
101
|
+
*
|
102
|
+
* `strokeRadius` is half of `strokeWidth`.
|
103
|
+
*/
|
87
104
|
roughlyIntersects(rect: Rect2, strokeWidth?: number): boolean;
|
88
105
|
closedRoughlyIntersects(rect: Rect2): boolean;
|
89
106
|
/**
|
@@ -95,16 +112,32 @@ export declare class Path {
|
|
95
112
|
*/
|
96
113
|
static fromRect(rect: Rect2, lineWidth?: number | null): Path;
|
97
114
|
private cachedStringVersion;
|
98
|
-
|
115
|
+
/**
|
116
|
+
* Convert to an [SVG path representation](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths).
|
117
|
+
*
|
118
|
+
* If `useNonAbsCommands` is given, relative path commands (e.g. `l10,0`) are to be used instead of
|
119
|
+
* absolute commands (e.g. `L10,0`).
|
120
|
+
*
|
121
|
+
* See also {@link fromString}.
|
122
|
+
*/
|
123
|
+
toString(useNonAbsCommands?: boolean, ignoreCache?: boolean): string;
|
99
124
|
serialize(): string;
|
100
125
|
static toString(startPoint: Point2, parts: PathCommand[], onlyAbsCommands?: boolean): string;
|
101
126
|
/**
|
102
|
-
* Create a Path from a SVG path specification.
|
127
|
+
* Create a `Path` from a subset of the SVG path specification.
|
103
128
|
*
|
104
129
|
* ## To-do
|
105
130
|
* - TODO: Support a larger subset of SVG paths
|
106
131
|
* - Elliptical arcs are currently unsupported.
|
107
132
|
* - TODO: Support `s`,`t` commands shorthands.
|
133
|
+
*
|
134
|
+
* @example
|
135
|
+
* ```ts,runnable,console
|
136
|
+
* import { Path } from '@js-draw/math';
|
137
|
+
*
|
138
|
+
* const path = Path.fromString('m0,0l100,100');
|
139
|
+
* console.log(path.toString(true)); // true: Prefer relative to absolute path commands
|
140
|
+
* ```
|
108
141
|
*/
|
109
142
|
static fromString(pathString: string): Path;
|
110
143
|
static empty: Path;
|
package/dist/mjs/shapes/Path.mjs
CHANGED
@@ -16,17 +16,23 @@ export var PathCommandType;
|
|
16
16
|
* Represents a union of lines and curves.
|
17
17
|
*/
|
18
18
|
export class Path {
|
19
|
+
/**
|
20
|
+
* Creates a new `Path` that starts at `startPoint` and is made up of the path commands,
|
21
|
+
* `parts`.
|
22
|
+
*
|
23
|
+
* See also {@link fromString}
|
24
|
+
*/
|
19
25
|
constructor(startPoint, parts) {
|
20
26
|
this.startPoint = startPoint;
|
21
|
-
this.parts = parts;
|
22
27
|
this.cachedGeometry = null;
|
23
28
|
this.cachedPolylineApproximation = null;
|
24
29
|
this.cachedStringVersion = null;
|
30
|
+
this.parts = parts;
|
25
31
|
// Initial bounding box contains one point: the start point.
|
26
32
|
this.bbox = Rect2.bboxOf([startPoint]);
|
27
33
|
// Convert into a representation of the geometry (cache for faster intersection
|
28
34
|
// calculation)
|
29
|
-
for (const part of parts) {
|
35
|
+
for (const part of this.parts) {
|
30
36
|
this.bbox = this.bbox.union(Path.computeBBoxForSegment(startPoint, part));
|
31
37
|
}
|
32
38
|
}
|
@@ -331,6 +337,8 @@ export class Path {
|
|
331
337
|
* intersections are approximated with the surface `strokeRadius` away from this.
|
332
338
|
*
|
333
339
|
* If `strokeRadius > 0`, the resultant `parameterValue` has no defined value.
|
340
|
+
*
|
341
|
+
* **Note**: `strokeRadius` is half of a stroke's width.
|
334
342
|
*/
|
335
343
|
intersection(line, strokeRadius) {
|
336
344
|
let result = [];
|
@@ -426,6 +434,16 @@ export class Path {
|
|
426
434
|
return lastPart.point;
|
427
435
|
}
|
428
436
|
}
|
437
|
+
/**
|
438
|
+
* Like {@link closedRoughlyIntersects} except takes stroke width into account.
|
439
|
+
*
|
440
|
+
* This is intended to be a very fast and rough approximation. Use {@link intersection}
|
441
|
+
* and {@link signedDistance} for more accurate (but much slower) intersection calculations.
|
442
|
+
*
|
443
|
+
* **Note**: Unlike other methods, this accepts `strokeWidth` (and not `strokeRadius`).
|
444
|
+
*
|
445
|
+
* `strokeRadius` is half of `strokeWidth`.
|
446
|
+
*/
|
429
447
|
roughlyIntersects(rect, strokeWidth = 0) {
|
430
448
|
if (this.parts.length === 0) {
|
431
449
|
return rect.containsPoint(this.startPoint);
|
@@ -453,7 +471,7 @@ export class Path {
|
|
453
471
|
}
|
454
472
|
return false;
|
455
473
|
}
|
456
|
-
// Treats this as a closed path and returns true if part of `rect` is roughly within
|
474
|
+
// Treats this as a closed path and returns true if part of `rect` is *roughly* within
|
457
475
|
// this path's interior.
|
458
476
|
//
|
459
477
|
// Note: Assumes that this is a closed, non-self-intersecting path.
|
@@ -535,8 +553,16 @@ export class Path {
|
|
535
553
|
});
|
536
554
|
return new Path(startPoint, commands);
|
537
555
|
}
|
538
|
-
|
539
|
-
|
556
|
+
/**
|
557
|
+
* Convert to an [SVG path representation](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths).
|
558
|
+
*
|
559
|
+
* If `useNonAbsCommands` is given, relative path commands (e.g. `l10,0`) are to be used instead of
|
560
|
+
* absolute commands (e.g. `L10,0`).
|
561
|
+
*
|
562
|
+
* See also {@link fromString}.
|
563
|
+
*/
|
564
|
+
toString(useNonAbsCommands, ignoreCache = false) {
|
565
|
+
if (this.cachedStringVersion && !ignoreCache) {
|
540
566
|
return this.cachedStringVersion;
|
541
567
|
}
|
542
568
|
if (useNonAbsCommands === undefined) {
|
@@ -626,12 +652,20 @@ export class Path {
|
|
626
652
|
return result.join('');
|
627
653
|
}
|
628
654
|
/**
|
629
|
-
* Create a Path from a SVG path specification.
|
655
|
+
* Create a `Path` from a subset of the SVG path specification.
|
630
656
|
*
|
631
657
|
* ## To-do
|
632
658
|
* - TODO: Support a larger subset of SVG paths
|
633
659
|
* - Elliptical arcs are currently unsupported.
|
634
660
|
* - TODO: Support `s`,`t` commands shorthands.
|
661
|
+
*
|
662
|
+
* @example
|
663
|
+
* ```ts,runnable,console
|
664
|
+
* import { Path } from '@js-draw/math';
|
665
|
+
*
|
666
|
+
* const path = Path.fromString('m0,0l100,100');
|
667
|
+
* console.log(path.toString(true)); // true: Prefer relative to absolute path commands
|
668
|
+
* ```
|
635
669
|
*/
|
636
670
|
static fromString(pathString) {
|
637
671
|
// See the MDN reference:
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@js-draw/math",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.10.0",
|
4
4
|
"description": "A math library for js-draw. ",
|
5
5
|
"types": "./dist/mjs/lib.d.ts",
|
6
6
|
"main": "./dist/cjs/lib.js",
|
@@ -45,5 +45,5 @@
|
|
45
45
|
"svg",
|
46
46
|
"math"
|
47
47
|
],
|
48
|
-
"gitHead": "
|
48
|
+
"gitHead": "ccf1d0634e902c731fcd794df11cd001c3a30585"
|
49
49
|
}
|
package/src/lib.ts
CHANGED
@@ -30,6 +30,7 @@ export {
|
|
30
30
|
} from './shapes/Path';
|
31
31
|
export { Rect2 } from './shapes/Rect2';
|
32
32
|
export { QuadraticBezier } from './shapes/QuadraticBezier';
|
33
|
+
export { Abstract2DShape } from './shapes/Abstract2DShape';
|
33
34
|
|
34
35
|
export { Mat33, Mat33Array } from './Mat33';
|
35
36
|
export { Point2, Vec2 } from './Vec2';
|
@@ -2,7 +2,11 @@ import LineSegment2 from './LineSegment2';
|
|
2
2
|
import { Point2 } from '../Vec2';
|
3
3
|
import Rect2 from './Rect2';
|
4
4
|
|
5
|
-
|
5
|
+
/**
|
6
|
+
* An abstract base class for 2D shapes.
|
7
|
+
*/
|
8
|
+
export abstract class Abstract2DShape {
|
9
|
+
// @internal
|
6
10
|
protected static readonly smallValue = 1e-12;
|
7
11
|
|
8
12
|
/**
|
@@ -47,9 +47,9 @@ describe('Path.toString', () => {
|
|
47
47
|
|
48
48
|
it('deserialized path should serialize to the same/similar path, but with rounded components', () => {
|
49
49
|
const path1 = Path.fromString('M100,100 L101,101 Q102,102 90.000000001,89.99999999 Z');
|
50
|
-
|
50
|
+
const ignoreCache = true;
|
51
51
|
|
52
|
-
expect(path1.toString()).toBe([
|
52
|
+
expect(path1.toString(undefined, ignoreCache)).toBe([
|
53
53
|
'M100,100', 'l1,1', 'q1,1 -11-11', 'l10,10'
|
54
54
|
].join(''));
|
55
55
|
});
|
@@ -58,9 +58,9 @@ describe('Path.toString', () => {
|
|
58
58
|
const pathStr = 'M184.2,52.3l-.2-.2q-2.7,2.4 -3.2,3.5q-2.8,7 -.9,6.1q4.3-2.6 4.8-6.1q1.2-8.8 .4-8.3q-4.2,5.2 -3.9,3.9q.2-1.6 .3-2.1q.2-1.3 -.2-1q-3.8,6.5 -3.2,3.3q.6-4.1 1.1-5.3q4.1-10 3.3-8.3q-5.3,13.1 -6.6,14.1q-3.3,2.8 -1.8-1.5q2.8-9.7 2.7-8.4q0,.3 0,.4q-1.4,7.1 -2.7,8.5q-2.6,3.2 -2.5,2.9q-.3-1.9 -.7-1.9q-4.1,4.4 -2.9,1.9q1.1-3 .3-2.6q-1.8,2 -2.5,2.4q-4.5,2.8 -4.2,1.9q.3-1.6 .2-1.4q1.5,2.2 1.3,2.9q-.8,3.9 -.5,3.3q.8-7.6 2.5-13.3q2.6-9.2 2.9-6.9q.3,1.4 .3,1.2q-.7-.4 -.9,0q-2.2,11.6 -7.6,13.6q-3.9,1.6 -2.1-1.3q3-5.5 2.6-3.4q-.2,1.8 -.5,1.8q-3.2,.5 -4.1,1.2q-2.6,2.6 -1.9,2.5q4.7-4.4 3.7-5.5q-1.1-.9 -1.6-.6q-7.2,7.5 -3.9,6.5q.3-.1 .4-.4q.6-5.3 -.2-4.9q-2.8,2.3 -3.1,2.4q-3.7,1.5 -3.5,.5q.3-3.6 1.4-3.3q3.5,.7 1.9,2.4q-1.7,2.3 -1.6,.8q0-3.5 -.9-3.1q-5.1,3.3 -4.9,2.8q.1-4 -.8-3.5q-4.3,3.4 -4.6,2.5q-1-2.1 .5-8.7l-.2,0q-1.6,6.6 -.7,8.9q.7,1.2 5.2-2.3q.4-.5 .2,3.1q.1,1 5.5-2.4q.4-.4 .3,2.7q.1,2 2.4-.4q1.7-2.3 -2.1-3.2q-1.7-.3 -2,3.7q0,1.4 4.1-.1q.3-.1 3.1-2.4q.3-.5 -.4,4.5q0-.1 -.2,0q-2.6,1.2 4.5-5.7q0-.2 .8,.6q.9,.6 -3.7,4.7q-.5,1 2.7-1.7q.6-.7 3.7-1.2q.7-.2 .9-2.2q.1-2.7 -3.4,3.2q-1.8,3.4 2.7,1.9q5.6-2.1 7.8-14q-.1,.1 .3,.4q.6,.1 .3-1.6q-.7-2.8 -3.7,6.7q-1.8,5.8 -2.5,13.5q.1,1.1 1.3-3.1q.2-1 -1.3-3.3q-.5-.5 -1,1.6q-.1,1.3 4.8-1.5q1-1 3-2q.1-.4 -1.1,2q-1.1,3.1 3.7-1.3q-.4,0 -.1,1.5q.3,.8 3.3-2.5q1.3-1.6 2.7-8.9q0-.1 0-.4q-.3-1.9 -3.5,8.2q-1.3,4.9 2.4,2.1q1.4-1.2 6.6-14.3q.8-2.4 -3.9,7.9q-.6,1.3 -1.1,5.5q-.3,3.7 4-3.1q-.2,0 -.6,.6q-.2,.6 -.3,2.3q0,1.8 4.7-3.5q.1-.5 -1.2,7.9q-.5,3.2 -4.6,5.7q-1.3,1 1.5-5.5q.4-1.1 3.01-3.5';
|
59
59
|
|
60
60
|
const path1 = Path.fromString(pathStr);
|
61
|
-
|
62
|
-
const path = Path.fromString(path1.toString(true));
|
63
|
-
path1['cachedStringVersion'] = null; // Clear the cache
|
61
|
+
const ignoreCache = true;
|
62
|
+
const path = Path.fromString(path1.toString(true, ignoreCache));
|
63
|
+
path1['cachedStringVersion'] = null; // Clear the cache manually
|
64
64
|
|
65
65
|
expect(path.toString(true)).toBe(path1.toString(true));
|
66
66
|
});
|
package/src/shapes/Path.ts
CHANGED
@@ -51,9 +51,6 @@ interface IntersectionResult {
|
|
51
51
|
point: Point2;
|
52
52
|
}
|
53
53
|
|
54
|
-
type GeometryType = Abstract2DShape;
|
55
|
-
type GeometryArrayType = Array<GeometryType>;
|
56
|
-
|
57
54
|
/**
|
58
55
|
* Represents a union of lines and curves.
|
59
56
|
*/
|
@@ -65,13 +62,27 @@ export class Path {
|
|
65
62
|
*/
|
66
63
|
public readonly bbox: Rect2;
|
67
64
|
|
68
|
-
|
65
|
+
/** The individual shapes that make up this path. */
|
66
|
+
public readonly parts: Readonly<PathCommand>[];
|
67
|
+
|
68
|
+
/**
|
69
|
+
* Creates a new `Path` that starts at `startPoint` and is made up of the path commands,
|
70
|
+
* `parts`.
|
71
|
+
*
|
72
|
+
* See also {@link fromString}
|
73
|
+
*/
|
74
|
+
public constructor(
|
75
|
+
public readonly startPoint: Point2,
|
76
|
+
parts: Readonly<PathCommand>[],
|
77
|
+
) {
|
78
|
+
this.parts = parts;
|
79
|
+
|
69
80
|
// Initial bounding box contains one point: the start point.
|
70
81
|
this.bbox = Rect2.bboxOf([startPoint]);
|
71
82
|
|
72
83
|
// Convert into a representation of the geometry (cache for faster intersection
|
73
84
|
// calculation)
|
74
|
-
for (const part of parts) {
|
85
|
+
for (const part of this.parts) {
|
75
86
|
this.bbox = this.bbox.union(Path.computeBBoxForSegment(startPoint, part));
|
76
87
|
}
|
77
88
|
}
|
@@ -85,16 +96,16 @@ export class Path {
|
|
85
96
|
return Rect2.union(...bboxes);
|
86
97
|
}
|
87
98
|
|
88
|
-
private cachedGeometry:
|
99
|
+
private cachedGeometry: Abstract2DShape[]|null = null;
|
89
100
|
|
90
101
|
// Lazy-loads and returns this path's geometry
|
91
|
-
public get geometry():
|
102
|
+
public get geometry(): Abstract2DShape[] {
|
92
103
|
if (this.cachedGeometry) {
|
93
104
|
return this.cachedGeometry;
|
94
105
|
}
|
95
106
|
|
96
107
|
let startPoint = this.startPoint;
|
97
|
-
const geometry:
|
108
|
+
const geometry: Abstract2DShape[] = [];
|
98
109
|
|
99
110
|
for (const part of this.parts) {
|
100
111
|
let exhaustivenessCheck: never;
|
@@ -258,7 +269,7 @@ export class Path {
|
|
258
269
|
|
259
270
|
type DistanceFunction = (point: Point2) => number;
|
260
271
|
type DistanceFunctionRecord = {
|
261
|
-
part:
|
272
|
+
part: Abstract2DShape,
|
262
273
|
bbox: Rect2,
|
263
274
|
distFn: DistanceFunction,
|
264
275
|
};
|
@@ -297,7 +308,7 @@ export class Path {
|
|
297
308
|
|
298
309
|
// Returns the minimum distance to a part in this stroke, where only parts that the given
|
299
310
|
// line could intersect are considered.
|
300
|
-
const sdf = (point: Point2): [
|
311
|
+
const sdf = (point: Point2): [Abstract2DShape|null, number] => {
|
301
312
|
let minDist = Infinity;
|
302
313
|
let minDistPart: Abstract2DShape|null = null;
|
303
314
|
|
@@ -466,6 +477,8 @@ export class Path {
|
|
466
477
|
* intersections are approximated with the surface `strokeRadius` away from this.
|
467
478
|
*
|
468
479
|
* If `strokeRadius > 0`, the resultant `parameterValue` has no defined value.
|
480
|
+
*
|
481
|
+
* **Note**: `strokeRadius` is half of a stroke's width.
|
469
482
|
*/
|
470
483
|
public intersection(line: LineSegment2, strokeRadius?: number): IntersectionResult[] {
|
471
484
|
let result: IntersectionResult[] = [];
|
@@ -576,6 +589,16 @@ export class Path {
|
|
576
589
|
}
|
577
590
|
}
|
578
591
|
|
592
|
+
/**
|
593
|
+
* Like {@link closedRoughlyIntersects} except takes stroke width into account.
|
594
|
+
*
|
595
|
+
* This is intended to be a very fast and rough approximation. Use {@link intersection}
|
596
|
+
* and {@link signedDistance} for more accurate (but much slower) intersection calculations.
|
597
|
+
*
|
598
|
+
* **Note**: Unlike other methods, this accepts `strokeWidth` (and not `strokeRadius`).
|
599
|
+
*
|
600
|
+
* `strokeRadius` is half of `strokeWidth`.
|
601
|
+
*/
|
579
602
|
public roughlyIntersects(rect: Rect2, strokeWidth: number = 0) {
|
580
603
|
if (this.parts.length === 0) {
|
581
604
|
return rect.containsPoint(this.startPoint);
|
@@ -609,7 +632,7 @@ export class Path {
|
|
609
632
|
return false;
|
610
633
|
}
|
611
634
|
|
612
|
-
// Treats this as a closed path and returns true if part of `rect` is roughly within
|
635
|
+
// Treats this as a closed path and returns true if part of `rect` is *roughly* within
|
613
636
|
// this path's interior.
|
614
637
|
//
|
615
638
|
// Note: Assumes that this is a closed, non-self-intersecting path.
|
@@ -713,8 +736,16 @@ export class Path {
|
|
713
736
|
|
714
737
|
private cachedStringVersion: string|null = null;
|
715
738
|
|
716
|
-
|
717
|
-
|
739
|
+
/**
|
740
|
+
* Convert to an [SVG path representation](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths).
|
741
|
+
*
|
742
|
+
* If `useNonAbsCommands` is given, relative path commands (e.g. `l10,0`) are to be used instead of
|
743
|
+
* absolute commands (e.g. `L10,0`).
|
744
|
+
*
|
745
|
+
* See also {@link fromString}.
|
746
|
+
*/
|
747
|
+
public toString(useNonAbsCommands?: boolean, ignoreCache: boolean = false): string {
|
748
|
+
if (this.cachedStringVersion && !ignoreCache) {
|
718
749
|
return this.cachedStringVersion;
|
719
750
|
}
|
720
751
|
|
@@ -817,12 +848,20 @@ export class Path {
|
|
817
848
|
}
|
818
849
|
|
819
850
|
/**
|
820
|
-
* Create a Path from a SVG path specification.
|
851
|
+
* Create a `Path` from a subset of the SVG path specification.
|
821
852
|
*
|
822
853
|
* ## To-do
|
823
854
|
* - TODO: Support a larger subset of SVG paths
|
824
855
|
* - Elliptical arcs are currently unsupported.
|
825
856
|
* - TODO: Support `s`,`t` commands shorthands.
|
857
|
+
*
|
858
|
+
* @example
|
859
|
+
* ```ts,runnable,console
|
860
|
+
* import { Path } from '@js-draw/math';
|
861
|
+
*
|
862
|
+
* const path = Path.fromString('m0,0l100,100');
|
863
|
+
* console.log(path.toString(true)); // true: Prefer relative to absolute path commands
|
864
|
+
* ```
|
826
865
|
*/
|
827
866
|
public static fromString(pathString: string): Path {
|
828
867
|
// See the MDN reference:
|