@js-draw/math 1.26.0 → 1.27.1
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/Color4.d.ts +2 -0
- package/dist/cjs/Color4.js +4 -0
- package/dist/cjs/shapes/Path.d.ts +5 -1
- package/dist/cjs/shapes/Path.js +25 -2
- package/dist/mjs/Color4.d.ts +2 -0
- package/dist/mjs/Color4.mjs +4 -0
- package/dist/mjs/shapes/Path.d.ts +5 -1
- package/dist/mjs/shapes/Path.mjs +25 -2
- package/package.json +3 -3
- package/src/Color4.ts +5 -0
- package/src/shapes/Path.test.ts +17 -0
- package/src/shapes/Path.ts +27 -2
package/dist/cjs/Color4.d.ts
CHANGED
@@ -69,6 +69,8 @@ export declare class Color4 {
|
|
69
69
|
* ```
|
70
70
|
*/
|
71
71
|
mix(other: Color4, fractionTo: number): Color4;
|
72
|
+
/** Returns a new color with a different opacity. */
|
73
|
+
withAlpha(a: number): Color4;
|
72
74
|
/**
|
73
75
|
* Ignoring this color's alpha component, returns a vector with components,
|
74
76
|
* $$
|
package/dist/cjs/Color4.js
CHANGED
@@ -183,6 +183,10 @@ class Color4 {
|
|
183
183
|
const fractionOfThis = 1 - fractionTo;
|
184
184
|
return new Color4(this.r * fractionOfThis + other.r * fractionTo, this.g * fractionOfThis + other.g * fractionTo, this.b * fractionOfThis + other.b * fractionTo, this.a * fractionOfThis + other.a * fractionTo);
|
185
185
|
}
|
186
|
+
/** Returns a new color with a different opacity. */
|
187
|
+
withAlpha(a) {
|
188
|
+
return new Color4(this.r, this.g, this.b, a);
|
189
|
+
}
|
186
190
|
/**
|
187
191
|
* Ignoring this color's alpha component, returns a vector with components,
|
188
192
|
* $$
|
@@ -185,9 +185,13 @@ export declare class Path {
|
|
185
185
|
mapPoints(mapping: (point: Point2) => Point2): Path;
|
186
186
|
transformedBy(affineTransfm: Mat33): Path;
|
187
187
|
/**
|
188
|
-
* @internal
|
188
|
+
* @internal -- TODO: This method may have incorrect output in some cases.
|
189
189
|
*/
|
190
190
|
closedContainsPoint(point: Point2): boolean;
|
191
|
+
/**
|
192
|
+
* @returns `true` if this path (interpreted as a closed path) contains the given rectangle.
|
193
|
+
*/
|
194
|
+
closedContainsRect(rect: Rect2): boolean;
|
191
195
|
union(other: Path | PathCommand[] | null, options?: {
|
192
196
|
allowReverse?: boolean;
|
193
197
|
}): Path;
|
package/dist/cjs/shapes/Path.js
CHANGED
@@ -751,7 +751,7 @@ class Path {
|
|
751
751
|
return this.mapPoints((point) => affineTransfm.transformVec2(point));
|
752
752
|
}
|
753
753
|
/**
|
754
|
-
* @internal
|
754
|
+
* @internal -- TODO: This method may have incorrect output in some cases.
|
755
755
|
*/
|
756
756
|
closedContainsPoint(point) {
|
757
757
|
const bbox = this.getExactBBox();
|
@@ -761,7 +761,30 @@ class Path {
|
|
761
761
|
const pointOutside = point.plus(Vec2_1.Vec2.of(bbox.width, 0));
|
762
762
|
const asClosed = this.asClosed();
|
763
763
|
const lineToOutside = new LineSegment2_1.default(point, pointOutside);
|
764
|
-
|
764
|
+
const intersections = asClosed.intersection(lineToOutside);
|
765
|
+
const filteredIntersections = intersections.filter((intersection, index) => {
|
766
|
+
if (index === 0)
|
767
|
+
return true; // No previous
|
768
|
+
const previousIntersection = intersections[index - 1];
|
769
|
+
const isRepeatedIntersection = previousIntersection.parameterValue >= 1 && intersection.parameterValue <= 0;
|
770
|
+
return !isRepeatedIntersection;
|
771
|
+
});
|
772
|
+
return filteredIntersections.length % 2 === 1;
|
773
|
+
}
|
774
|
+
/**
|
775
|
+
* @returns `true` if this path (interpreted as a closed path) contains the given rectangle.
|
776
|
+
*/
|
777
|
+
closedContainsRect(rect) {
|
778
|
+
if (!this.bbox.containsRect(rect))
|
779
|
+
return false;
|
780
|
+
if (!rect.corners.every((corner) => this.closedContainsPoint(corner)))
|
781
|
+
return false;
|
782
|
+
for (const edge of rect.getEdges()) {
|
783
|
+
if (this.intersection(edge).length) {
|
784
|
+
return false;
|
785
|
+
}
|
786
|
+
}
|
787
|
+
return true;
|
765
788
|
}
|
766
789
|
// Creates a new path by joining [other] to the end of this path
|
767
790
|
union(other,
|
package/dist/mjs/Color4.d.ts
CHANGED
@@ -69,6 +69,8 @@ export declare class Color4 {
|
|
69
69
|
* ```
|
70
70
|
*/
|
71
71
|
mix(other: Color4, fractionTo: number): Color4;
|
72
|
+
/** Returns a new color with a different opacity. */
|
73
|
+
withAlpha(a: number): Color4;
|
72
74
|
/**
|
73
75
|
* Ignoring this color's alpha component, returns a vector with components,
|
74
76
|
* $$
|
package/dist/mjs/Color4.mjs
CHANGED
@@ -177,6 +177,10 @@ export class Color4 {
|
|
177
177
|
const fractionOfThis = 1 - fractionTo;
|
178
178
|
return new Color4(this.r * fractionOfThis + other.r * fractionTo, this.g * fractionOfThis + other.g * fractionTo, this.b * fractionOfThis + other.b * fractionTo, this.a * fractionOfThis + other.a * fractionTo);
|
179
179
|
}
|
180
|
+
/** Returns a new color with a different opacity. */
|
181
|
+
withAlpha(a) {
|
182
|
+
return new Color4(this.r, this.g, this.b, a);
|
183
|
+
}
|
180
184
|
/**
|
181
185
|
* Ignoring this color's alpha component, returns a vector with components,
|
182
186
|
* $$
|
@@ -185,9 +185,13 @@ export declare class Path {
|
|
185
185
|
mapPoints(mapping: (point: Point2) => Point2): Path;
|
186
186
|
transformedBy(affineTransfm: Mat33): Path;
|
187
187
|
/**
|
188
|
-
* @internal
|
188
|
+
* @internal -- TODO: This method may have incorrect output in some cases.
|
189
189
|
*/
|
190
190
|
closedContainsPoint(point: Point2): boolean;
|
191
|
+
/**
|
192
|
+
* @returns `true` if this path (interpreted as a closed path) contains the given rectangle.
|
193
|
+
*/
|
194
|
+
closedContainsRect(rect: Rect2): boolean;
|
191
195
|
union(other: Path | PathCommand[] | null, options?: {
|
192
196
|
allowReverse?: boolean;
|
193
197
|
}): Path;
|
package/dist/mjs/shapes/Path.mjs
CHANGED
@@ -743,7 +743,7 @@ export class Path {
|
|
743
743
|
return this.mapPoints((point) => affineTransfm.transformVec2(point));
|
744
744
|
}
|
745
745
|
/**
|
746
|
-
* @internal
|
746
|
+
* @internal -- TODO: This method may have incorrect output in some cases.
|
747
747
|
*/
|
748
748
|
closedContainsPoint(point) {
|
749
749
|
const bbox = this.getExactBBox();
|
@@ -753,7 +753,30 @@ export class Path {
|
|
753
753
|
const pointOutside = point.plus(Vec2.of(bbox.width, 0));
|
754
754
|
const asClosed = this.asClosed();
|
755
755
|
const lineToOutside = new LineSegment2(point, pointOutside);
|
756
|
-
|
756
|
+
const intersections = asClosed.intersection(lineToOutside);
|
757
|
+
const filteredIntersections = intersections.filter((intersection, index) => {
|
758
|
+
if (index === 0)
|
759
|
+
return true; // No previous
|
760
|
+
const previousIntersection = intersections[index - 1];
|
761
|
+
const isRepeatedIntersection = previousIntersection.parameterValue >= 1 && intersection.parameterValue <= 0;
|
762
|
+
return !isRepeatedIntersection;
|
763
|
+
});
|
764
|
+
return filteredIntersections.length % 2 === 1;
|
765
|
+
}
|
766
|
+
/**
|
767
|
+
* @returns `true` if this path (interpreted as a closed path) contains the given rectangle.
|
768
|
+
*/
|
769
|
+
closedContainsRect(rect) {
|
770
|
+
if (!this.bbox.containsRect(rect))
|
771
|
+
return false;
|
772
|
+
if (!rect.corners.every((corner) => this.closedContainsPoint(corner)))
|
773
|
+
return false;
|
774
|
+
for (const edge of rect.getEdges()) {
|
775
|
+
if (this.intersection(edge).length) {
|
776
|
+
return false;
|
777
|
+
}
|
778
|
+
}
|
779
|
+
return true;
|
757
780
|
}
|
758
781
|
// Creates a new path by joining [other] to the end of this path
|
759
782
|
union(other,
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@js-draw/math",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.27.1",
|
4
4
|
"description": "A math library for js-draw. ",
|
5
5
|
"types": "./dist/mjs/lib.d.ts",
|
6
6
|
"main": "./dist/cjs/lib.js",
|
@@ -27,7 +27,7 @@
|
|
27
27
|
"bezier-js": "6.1.3"
|
28
28
|
},
|
29
29
|
"devDependencies": {
|
30
|
-
"@js-draw/build-tool": "^1.
|
30
|
+
"@js-draw/build-tool": "^1.27.1",
|
31
31
|
"@types/bezier-js": "4.1.0",
|
32
32
|
"@types/jest": "29.5.5",
|
33
33
|
"@types/jsdom": "21.1.3"
|
@@ -44,5 +44,5 @@
|
|
44
44
|
"svg",
|
45
45
|
"math"
|
46
46
|
],
|
47
|
-
"gitHead": "
|
47
|
+
"gitHead": "e11574b7b329e7867358c400457a3d99b1d2c469"
|
48
48
|
}
|
package/src/Color4.ts
CHANGED
@@ -224,6 +224,11 @@ export class Color4 {
|
|
224
224
|
);
|
225
225
|
}
|
226
226
|
|
227
|
+
/** Returns a new color with a different opacity. */
|
228
|
+
public withAlpha(a: number) {
|
229
|
+
return new Color4(this.r, this.g, this.b, a);
|
230
|
+
}
|
231
|
+
|
227
232
|
/**
|
228
233
|
* Ignoring this color's alpha component, returns a vector with components,
|
229
234
|
* $$
|
package/src/shapes/Path.test.ts
CHANGED
@@ -536,4 +536,21 @@ describe('Path', () => {
|
|
536
536
|
expect(path.tangentAt(at)).objEq(expected);
|
537
537
|
},
|
538
538
|
);
|
539
|
+
|
540
|
+
it.each([
|
541
|
+
// A rectangle completely contained
|
542
|
+
['m0,0 l10,0 l0,10 l-10,0', new Rect2(3, 3, 3, 3), true],
|
543
|
+
// A rectangle partially contained
|
544
|
+
['m0,0 l10,0 l0,10 l-10,0', new Rect2(3, 3, 33, 3), false],
|
545
|
+
// A rectangle not contained
|
546
|
+
['m0,0 l10,0 l0,10 l-10,0', new Rect2(13, 3, 1, 1), false],
|
547
|
+
// More complicated path containing a rectangle
|
548
|
+
['M0,0 Q10,15 10,5', new Rect2(5, 5, 1, 1), true],
|
549
|
+
['M0,0 Q10,15 10,5', new Rect2(15, 5, 1, 1), false],
|
550
|
+
])(
|
551
|
+
'.closedContainsRect should return whether a rectangle is contained within a path (case %#: path(%s), rect(%s))',
|
552
|
+
(pathString, rect, expected) => {
|
553
|
+
expect(Path.fromString(pathString).closedContainsRect(rect)).toBe(expected);
|
554
|
+
},
|
555
|
+
);
|
539
556
|
});
|
package/src/shapes/Path.ts
CHANGED
@@ -969,7 +969,7 @@ export class Path {
|
|
969
969
|
}
|
970
970
|
|
971
971
|
/**
|
972
|
-
* @internal
|
972
|
+
* @internal -- TODO: This method may have incorrect output in some cases.
|
973
973
|
*/
|
974
974
|
public closedContainsPoint(point: Point2) {
|
975
975
|
const bbox = this.getExactBBox();
|
@@ -981,7 +981,32 @@ export class Path {
|
|
981
981
|
const asClosed = this.asClosed();
|
982
982
|
|
983
983
|
const lineToOutside = new LineSegment2(point, pointOutside);
|
984
|
-
|
984
|
+
|
985
|
+
const intersections = asClosed.intersection(lineToOutside);
|
986
|
+
const filteredIntersections = intersections.filter((intersection, index) => {
|
987
|
+
if (index === 0) return true; // No previous
|
988
|
+
const previousIntersection = intersections[index - 1];
|
989
|
+
const isRepeatedIntersection =
|
990
|
+
previousIntersection.parameterValue >= 1 && intersection.parameterValue <= 0;
|
991
|
+
return !isRepeatedIntersection;
|
992
|
+
});
|
993
|
+
return filteredIntersections.length % 2 === 1;
|
994
|
+
}
|
995
|
+
|
996
|
+
/**
|
997
|
+
* @returns `true` if this path (interpreted as a closed path) contains the given rectangle.
|
998
|
+
*/
|
999
|
+
public closedContainsRect(rect: Rect2) {
|
1000
|
+
if (!this.bbox.containsRect(rect)) return false;
|
1001
|
+
if (!rect.corners.every((corner) => this.closedContainsPoint(corner))) return false;
|
1002
|
+
|
1003
|
+
for (const edge of rect.getEdges()) {
|
1004
|
+
if (this.intersection(edge).length) {
|
1005
|
+
return false;
|
1006
|
+
}
|
1007
|
+
}
|
1008
|
+
|
1009
|
+
return true;
|
985
1010
|
}
|
986
1011
|
|
987
1012
|
// Creates a new path by joining [other] to the end of this path
|