@js-draw/math 1.9.0 → 1.10.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|