@tldraw/editor 3.12.0-canary.fc675f45caa0 → 3.12.0-canary.fff04afa92e2
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/index.d.ts +153 -18
- package/dist-cjs/index.js +3 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +5 -0
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/GeometryDebuggingView.js +2 -2
- package/dist-cjs/lib/components/GeometryDebuggingView.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +10 -1
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +208 -18
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/managers/FocusManager.js +1 -1
- package/dist-cjs/lib/editor/managers/FocusManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js +12 -0
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +4 -13
- package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/tools/StateNode.js +1 -4
- package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
- package/dist-cjs/lib/editor/types/selection-types.js.map +1 -1
- package/dist-cjs/lib/exports/StyleEmbedder.js +19 -5
- package/dist-cjs/lib/exports/StyleEmbedder.js.map +2 -2
- package/dist-cjs/lib/exports/cssRules.js +127 -0
- package/dist-cjs/lib/exports/cssRules.js.map +7 -0
- package/dist-cjs/lib/exports/parseCss.js +0 -69
- package/dist-cjs/lib/exports/parseCss.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +8 -13
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +3 -3
- package/dist-cjs/lib/hooks/useDocumentEvents.js +16 -0
- package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
- package/dist-cjs/lib/license/Watermark.js +10 -20
- package/dist-cjs/lib/license/Watermark.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js +133 -16
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +3 -3
- package/dist-cjs/lib/primitives/geometry/Group2d.js +54 -11
- package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
- package/dist-cjs/lib/primitives/intersect.js +20 -0
- package/dist-cjs/lib/primitives/intersect.js.map +2 -2
- package/dist-cjs/lib/utils/reorderShapes.js +2 -8
- package/dist-cjs/lib/utils/reorderShapes.js.map +2 -2
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +153 -18
- package/dist-esm/index.mjs +8 -2
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +5 -0
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/GeometryDebuggingView.mjs +3 -3
- package/dist-esm/lib/components/GeometryDebuggingView.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +10 -1
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +209 -18
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/FocusManager.mjs +1 -1
- package/dist-esm/lib/editor/managers/FocusManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +12 -0
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +4 -13
- package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/StateNode.mjs +1 -4
- package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
- package/dist-esm/lib/exports/StyleEmbedder.mjs +21 -12
- package/dist-esm/lib/exports/StyleEmbedder.mjs.map +2 -2
- package/dist-esm/lib/exports/cssRules.mjs +107 -0
- package/dist-esm/lib/exports/cssRules.mjs.map +7 -0
- package/dist-esm/lib/exports/parseCss.mjs +0 -69
- package/dist-esm/lib/exports/parseCss.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +8 -13
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +3 -3
- package/dist-esm/lib/hooks/useDocumentEvents.mjs +16 -0
- package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
- package/dist-esm/lib/license/Watermark.mjs +10 -20
- package/dist-esm/lib/license/Watermark.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +137 -14
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Group2d.mjs +55 -12
- package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/intersect.mjs +20 -0
- package/dist-esm/lib/primitives/intersect.mjs.map +2 -2
- package/dist-esm/lib/utils/reorderShapes.mjs +2 -8
- package/dist-esm/lib/utils/reorderShapes.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +34 -19
- package/package.json +7 -7
- package/src/index.ts +11 -2
- package/src/lib/TldrawEditor.tsx +28 -1
- package/src/lib/components/GeometryDebuggingView.tsx +3 -3
- package/src/lib/components/default-components/DefaultCanvas.tsx +6 -1
- package/src/lib/editor/Editor.ts +315 -24
- package/src/lib/editor/managers/FocusManager.ts +1 -1
- package/src/lib/editor/shapes/ShapeUtil.ts +14 -0
- package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +7 -15
- package/src/lib/editor/tools/StateNode.ts +1 -6
- package/src/lib/editor/types/selection-types.ts +3 -0
- package/src/lib/exports/StyleEmbedder.ts +25 -15
- package/src/lib/exports/cssRules.ts +126 -0
- package/src/lib/exports/parseCss.ts +0 -79
- package/src/lib/hooks/useCanvasEvents.ts +8 -15
- package/src/lib/hooks/useDocumentEvents.ts +18 -0
- package/src/lib/license/Watermark.tsx +18 -29
- package/src/lib/primitives/geometry/Geometry2d.ts +196 -16
- package/src/lib/primitives/geometry/Group2d.ts +76 -13
- package/src/lib/primitives/intersect.ts +41 -0
- package/src/lib/utils/reorderShapes.ts +2 -9
- package/src/version.ts +3 -3
|
@@ -1,34 +1,57 @@
|
|
|
1
|
+
import { assert } from "@tldraw/utils";
|
|
1
2
|
import { Box } from "../Box.mjs";
|
|
3
|
+
import { Mat } from "../Mat.mjs";
|
|
2
4
|
import { Vec } from "../Vec.mjs";
|
|
3
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
intersectCirclePolygon,
|
|
7
|
+
intersectCirclePolyline,
|
|
8
|
+
intersectLineSegmentPolygon,
|
|
9
|
+
intersectLineSegmentPolyline,
|
|
10
|
+
intersectPolys
|
|
11
|
+
} from "../intersect.mjs";
|
|
12
|
+
import { approximately, pointInPolygon } from "../utils.mjs";
|
|
13
|
+
const Geometry2dFilters = {
|
|
14
|
+
EXCLUDE_NON_STANDARD: {
|
|
15
|
+
includeLabels: false,
|
|
16
|
+
includeInternal: false
|
|
17
|
+
},
|
|
18
|
+
INCLUDE_ALL: { includeLabels: true, includeInternal: true },
|
|
19
|
+
EXCLUDE_LABELS: { includeLabels: false, includeInternal: true },
|
|
20
|
+
EXCLUDE_INTERNAL: { includeLabels: true, includeInternal: false }
|
|
21
|
+
};
|
|
4
22
|
class Geometry2d {
|
|
5
23
|
isFilled = false;
|
|
6
24
|
isClosed = true;
|
|
7
25
|
isLabel = false;
|
|
26
|
+
isInternal = false;
|
|
8
27
|
debugColor;
|
|
9
28
|
ignore;
|
|
10
29
|
constructor(opts) {
|
|
11
30
|
this.isFilled = opts.isFilled;
|
|
12
31
|
this.isClosed = opts.isClosed;
|
|
13
32
|
this.isLabel = opts.isLabel ?? false;
|
|
33
|
+
this.isInternal = opts.isInternal ?? false;
|
|
14
34
|
this.debugColor = opts.debugColor;
|
|
15
35
|
this.ignore = opts.ignore;
|
|
16
36
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
37
|
+
isExcludedByFilter(filters) {
|
|
38
|
+
if (!filters) return false;
|
|
39
|
+
if (this.isLabel && !filters.includeLabels) return true;
|
|
40
|
+
if (this.isInternal && !filters.includeInternal) return true;
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
hitTestPoint(point, margin = 0, hitInside = false, filters) {
|
|
44
|
+
if (this.isExcludedByFilter(filters)) return false;
|
|
22
45
|
if (this.isClosed && (this.isFilled || hitInside) && pointInPolygon(point, this.vertices)) {
|
|
23
46
|
return true;
|
|
24
47
|
}
|
|
25
48
|
return Vec.Dist2(point, this.nearestPoint(point)) <= margin * margin;
|
|
26
49
|
}
|
|
27
|
-
distanceToPoint(point, hitInside = false) {
|
|
28
|
-
return point.dist(this.nearestPoint(point)) * (this.isClosed && (this.isFilled || hitInside) && pointInPolygon(point, this.vertices) ? -1 : 1);
|
|
50
|
+
distanceToPoint(point, hitInside = false, filters) {
|
|
51
|
+
return point.dist(this.nearestPoint(point, filters)) * (this.isClosed && (this.isFilled || hitInside) && pointInPolygon(point, this.vertices) ? -1 : 1);
|
|
29
52
|
}
|
|
30
|
-
distanceToLineSegment(A, B) {
|
|
31
|
-
if (A.equals(B)) return this.distanceToPoint(A);
|
|
53
|
+
distanceToLineSegment(A, B, filters) {
|
|
54
|
+
if (A.equals(B)) return this.distanceToPoint(A, false, filters);
|
|
32
55
|
const { vertices } = this;
|
|
33
56
|
let nearest;
|
|
34
57
|
let dist = Infinity;
|
|
@@ -45,9 +68,28 @@ class Geometry2d {
|
|
|
45
68
|
if (!nearest) throw Error("nearest point not found");
|
|
46
69
|
return this.isClosed && this.isFilled && pointInPolygon(nearest, this.vertices) ? -dist : dist;
|
|
47
70
|
}
|
|
48
|
-
hitTestLineSegment(A, B, distance = 0) {
|
|
49
|
-
return this.distanceToLineSegment(A, B) <= distance;
|
|
71
|
+
hitTestLineSegment(A, B, distance = 0, filters) {
|
|
72
|
+
return this.distanceToLineSegment(A, B, filters) <= distance;
|
|
73
|
+
}
|
|
74
|
+
intersectLineSegment(A, B, filters) {
|
|
75
|
+
if (this.isExcludedByFilter(filters)) return [];
|
|
76
|
+
const intersections = this.isClosed ? intersectLineSegmentPolygon(A, B, this.vertices) : intersectLineSegmentPolyline(A, B, this.vertices);
|
|
77
|
+
return intersections ?? [];
|
|
78
|
+
}
|
|
79
|
+
intersectCircle(center, radius, filters) {
|
|
80
|
+
if (this.isExcludedByFilter(filters)) return [];
|
|
81
|
+
const intersections = this.isClosed ? intersectCirclePolygon(center, radius, this.vertices) : intersectCirclePolyline(center, radius, this.vertices);
|
|
82
|
+
return intersections ?? [];
|
|
83
|
+
}
|
|
84
|
+
intersectPolygon(polygon, filters) {
|
|
85
|
+
if (this.isExcludedByFilter(filters)) return [];
|
|
86
|
+
return intersectPolys(polygon, this.vertices, true, this.isClosed);
|
|
87
|
+
}
|
|
88
|
+
intersectPolyline(polyline, filters) {
|
|
89
|
+
if (this.isExcludedByFilter(filters)) return [];
|
|
90
|
+
return intersectPolys(polyline, this.vertices, false, this.isClosed);
|
|
50
91
|
}
|
|
92
|
+
/** @deprecated Iterate the vertices instead. */
|
|
51
93
|
nearestPointOnLineSegment(A, B) {
|
|
52
94
|
const { vertices } = this;
|
|
53
95
|
let nearest;
|
|
@@ -69,11 +111,14 @@ class Geometry2d {
|
|
|
69
111
|
const { bounds } = this;
|
|
70
112
|
return !(point.x < bounds.minX - margin || point.y < bounds.minY - margin || point.x > bounds.maxX + margin || point.y > bounds.maxY + margin);
|
|
71
113
|
}
|
|
114
|
+
transform(transform) {
|
|
115
|
+
return new TransformedGeometry2d(this, transform);
|
|
116
|
+
}
|
|
72
117
|
_vertices;
|
|
73
118
|
// eslint-disable-next-line no-restricted-syntax
|
|
74
119
|
get vertices() {
|
|
75
120
|
if (!this._vertices) {
|
|
76
|
-
this._vertices = this.getVertices();
|
|
121
|
+
this._vertices = this.getVertices(Geometry2dFilters.EXCLUDE_LABELS);
|
|
77
122
|
}
|
|
78
123
|
return this._vertices;
|
|
79
124
|
}
|
|
@@ -145,7 +190,85 @@ class Geometry2d {
|
|
|
145
190
|
return Math.sqrt(length);
|
|
146
191
|
}
|
|
147
192
|
}
|
|
193
|
+
class TransformedGeometry2d extends Geometry2d {
|
|
194
|
+
constructor(geometry, matrix) {
|
|
195
|
+
super(geometry);
|
|
196
|
+
this.geometry = geometry;
|
|
197
|
+
this.matrix = matrix;
|
|
198
|
+
this.inverse = Mat.Inverse(matrix);
|
|
199
|
+
this.decomposed = Mat.Decompose(matrix);
|
|
200
|
+
assert(
|
|
201
|
+
approximately(this.decomposed.scaleX, this.decomposed.scaleY),
|
|
202
|
+
"non-uniform scaling is not yet supported"
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
inverse;
|
|
206
|
+
decomposed;
|
|
207
|
+
getVertices(filters) {
|
|
208
|
+
return this.geometry.getVertices(filters).map((v) => Mat.applyToPoint(this.matrix, v));
|
|
209
|
+
}
|
|
210
|
+
nearestPoint(point, filters) {
|
|
211
|
+
return Mat.applyToPoint(
|
|
212
|
+
this.matrix,
|
|
213
|
+
this.geometry.nearestPoint(Mat.applyToPoint(this.inverse, point), filters)
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
hitTestPoint(point, margin = 0, hitInside, filters) {
|
|
217
|
+
return this.geometry.hitTestPoint(
|
|
218
|
+
Mat.applyToPoint(this.inverse, point),
|
|
219
|
+
margin / this.decomposed.scaleX,
|
|
220
|
+
hitInside,
|
|
221
|
+
filters
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
distanceToPoint(point, hitInside = false, filters) {
|
|
225
|
+
return this.geometry.distanceToPoint(Mat.applyToPoint(this.inverse, point), hitInside, filters) * this.decomposed.scaleX;
|
|
226
|
+
}
|
|
227
|
+
distanceToLineSegment(A, B, filters) {
|
|
228
|
+
return this.geometry.distanceToLineSegment(
|
|
229
|
+
Mat.applyToPoint(this.inverse, A),
|
|
230
|
+
Mat.applyToPoint(this.inverse, B),
|
|
231
|
+
filters
|
|
232
|
+
) * this.decomposed.scaleX;
|
|
233
|
+
}
|
|
234
|
+
hitTestLineSegment(A, B, distance = 0, filters) {
|
|
235
|
+
return this.geometry.hitTestLineSegment(
|
|
236
|
+
Mat.applyToPoint(this.inverse, A),
|
|
237
|
+
Mat.applyToPoint(this.inverse, B),
|
|
238
|
+
distance / this.decomposed.scaleX,
|
|
239
|
+
filters
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
intersectLineSegment(A, B, filters) {
|
|
243
|
+
return this.geometry.intersectLineSegment(
|
|
244
|
+
Mat.applyToPoint(this.inverse, A),
|
|
245
|
+
Mat.applyToPoint(this.inverse, B),
|
|
246
|
+
filters
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
intersectCircle(center, radius, filters) {
|
|
250
|
+
return this.geometry.intersectCircle(
|
|
251
|
+
Mat.applyToPoint(this.inverse, center),
|
|
252
|
+
radius / this.decomposed.scaleX,
|
|
253
|
+
filters
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
intersectPolygon(polygon, filters) {
|
|
257
|
+
return this.geometry.intersectPolygon(Mat.applyToPoints(this.inverse, polygon), filters);
|
|
258
|
+
}
|
|
259
|
+
intersectPolyline(polyline, filters) {
|
|
260
|
+
return this.geometry.intersectPolyline(Mat.applyToPoints(this.inverse, polyline), filters);
|
|
261
|
+
}
|
|
262
|
+
transform(transform) {
|
|
263
|
+
return new TransformedGeometry2d(this.geometry, Mat.Multiply(transform, this.matrix));
|
|
264
|
+
}
|
|
265
|
+
getSvgPathData() {
|
|
266
|
+
throw new Error("Cannot get SVG path data for transformed geometry.");
|
|
267
|
+
}
|
|
268
|
+
}
|
|
148
269
|
export {
|
|
149
|
-
Geometry2d
|
|
270
|
+
Geometry2d,
|
|
271
|
+
Geometry2dFilters,
|
|
272
|
+
TransformedGeometry2d
|
|
150
273
|
};
|
|
151
274
|
//# sourceMappingURL=Geometry2d.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/primitives/geometry/Geometry2d.ts"],
|
|
4
|
-
"sourcesContent": ["import { Box } from '../Box'\nimport { Vec } from '../Vec'\nimport { pointInPolygon } from '../utils'\n\n/** @public */\nexport interface Geometry2dOptions {\n\tisFilled: boolean\n\tisClosed: boolean\n\tisLabel?: boolean\n\tdebugColor?: string\n\tignore?: boolean\n}\n\n/** @public */\nexport abstract class Geometry2d {\n\tisFilled = false\n\tisClosed = true\n\tisLabel = false\n\tdebugColor?: string\n\tignore?: boolean\n\n\tconstructor(opts: Geometry2dOptions) {\n\t\tthis.isFilled = opts.isFilled\n\t\tthis.isClosed = opts.isClosed\n\t\tthis.isLabel = opts.isLabel ?? false\n\t\tthis.debugColor = opts.debugColor\n\t\tthis.ignore = opts.ignore\n\t}\n\n\tabstract getVertices(): Vec[]\n\n\tabstract nearestPoint(point: Vec): Vec\n\n\t// hitTestPoint(point: Vec, margin = 0, hitInside = false) {\n\t// \t// We've removed the broad phase here; that should be done outside of the call\n\t// \treturn this.distanceToPoint(point, hitInside) <= margin\n\t// }\n\n\thitTestPoint(point: Vec, margin = 0, hitInside = false) {\n\t\t// First check whether the point is inside\n\t\tif (this.isClosed && (this.isFilled || hitInside) && pointInPolygon(point, this.vertices)) {\n\t\t\treturn true\n\t\t}\n\t\t// Then check whether the distance is within the margin\n\t\treturn Vec.Dist2(point, this.nearestPoint(point)) <= margin * margin\n\t}\n\n\tdistanceToPoint(point: Vec, hitInside = false) {\n\t\treturn (\n\t\t\tpoint.dist(this.nearestPoint(point)) *\n\t\t\t(this.isClosed && (this.isFilled || hitInside) && pointInPolygon(point, this.vertices)\n\t\t\t\t? -1\n\t\t\t\t: 1)\n\t\t)\n\t}\n\n\tdistanceToLineSegment(A: Vec, B: Vec) {\n\t\tif (A.equals(B)) return this.distanceToPoint(A)\n\t\tconst { vertices } = this\n\t\tlet nearest: Vec | undefined\n\t\tlet dist = Infinity\n\t\tlet d: number, p: Vec, q: Vec\n\t\tfor (let i = 0; i < vertices.length; i++) {\n\t\t\tp = vertices[i]\n\t\t\tq = Vec.NearestPointOnLineSegment(A, B, p, true)\n\t\t\td = Vec.Dist2(p, q)\n\t\t\tif (d < dist) {\n\t\t\t\tdist = d\n\t\t\t\tnearest = q\n\t\t\t}\n\t\t}\n\t\tif (!nearest) throw Error('nearest point not found')\n\t\treturn this.isClosed && this.isFilled && pointInPolygon(nearest, this.vertices) ? -dist : dist\n\t}\n\n\thitTestLineSegment(A: Vec, B: Vec, distance = 0): boolean {\n\t\treturn this.distanceToLineSegment(A, B) <= distance\n\t}\n\n\tnearestPointOnLineSegment(A: Vec, B: Vec): Vec {\n\t\tconst { vertices } = this\n\t\tlet nearest: Vec | undefined\n\t\tlet dist = Infinity\n\t\tlet d: number, p: Vec, q: Vec\n\t\tfor (let i = 0; i < vertices.length; i++) {\n\t\t\tp = vertices[i]\n\t\t\tq = Vec.NearestPointOnLineSegment(A, B, p, true)\n\t\t\td = Vec.Dist2(p, q)\n\t\t\tif (d < dist) {\n\t\t\t\tdist = d\n\t\t\t\tnearest = q\n\t\t\t}\n\t\t}\n\t\tif (!nearest) throw Error('nearest point not found')\n\t\treturn nearest\n\t}\n\n\tisPointInBounds(point: Vec, margin = 0) {\n\t\tconst { bounds } = this\n\t\treturn !(\n\t\t\tpoint.x < bounds.minX - margin ||\n\t\t\tpoint.y < bounds.minY - margin ||\n\t\t\tpoint.x > bounds.maxX + margin ||\n\t\t\tpoint.y > bounds.maxY + margin\n\t\t)\n\t}\n\n\tprivate _vertices: Vec[] | undefined\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget vertices(): Vec[] {\n\t\tif (!this._vertices) {\n\t\t\tthis._vertices = this.getVertices()\n\t\t}\n\n\t\treturn this._vertices\n\t}\n\n\tgetBounds() {\n\t\treturn Box.FromPoints(this.vertices)\n\t}\n\n\tprivate _bounds: Box | undefined\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget bounds(): Box {\n\t\tif (!this._bounds) {\n\t\t\tthis._bounds = this.getBounds()\n\t\t}\n\t\treturn this._bounds\n\t}\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget center() {\n\t\treturn this.bounds.center\n\t}\n\n\tprivate _area: number | undefined\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget area() {\n\t\tif (!this._area) {\n\t\t\tthis._area = this.getArea()\n\t\t}\n\t\treturn this._area\n\t}\n\n\tgetArea() {\n\t\tif (!this.isClosed) {\n\t\t\treturn 0\n\t\t}\n\t\tconst { vertices } = this\n\t\tlet area = 0\n\t\tfor (let i = 0, n = vertices.length; i < n; i++) {\n\t\t\tconst curr = vertices[i]\n\t\t\tconst next = vertices[(i + 1) % n]\n\t\t\tarea += curr.x * next.y - next.x * curr.y\n\t\t}\n\t\treturn area / 2\n\t}\n\n\ttoSimpleSvgPath() {\n\t\tlet path = ''\n\n\t\tconst { vertices } = this\n\t\tconst n = vertices.length\n\n\t\tif (n === 0) return path\n\n\t\tpath += `M${vertices[0].x},${vertices[0].y}`\n\n\t\tfor (let i = 1; i < n; i++) {\n\t\t\tpath += `L${vertices[i].x},${vertices[i].y}`\n\t\t}\n\n\t\tif (this.isClosed) {\n\t\t\tpath += 'Z'\n\t\t}\n\n\t\treturn path\n\t}\n\n\tprivate _length?: number\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget length() {\n\t\tif (this._length) return this._length\n\t\tthis._length = this.getLength()\n\t\treturn this._length\n\t}\n\n\tgetLength() {\n\t\tconst { vertices } = this\n\t\tlet n1: Vec,\n\t\t\tp1 = vertices[0],\n\t\t\tlength = 0\n\t\tfor (let i = 1; i < vertices.length; i++) {\n\t\t\tn1 = vertices[i]\n\t\t\tlength += Vec.Dist2(p1, n1)\n\t\t\tp1 = n1\n\t\t}\n\t\treturn Math.sqrt(length)\n\t}\n\n\tabstract getSvgPathData(first: boolean): string\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,
|
|
4
|
+
"sourcesContent": ["import { assert } from '@tldraw/utils'\nimport { Box } from '../Box'\nimport { Mat, MatModel } from '../Mat'\nimport { Vec, VecLike } from '../Vec'\nimport {\n\tintersectCirclePolygon,\n\tintersectCirclePolyline,\n\tintersectLineSegmentPolygon,\n\tintersectLineSegmentPolyline,\n\tintersectPolys,\n} from '../intersect'\nimport { approximately, pointInPolygon } from '../utils'\n\n/** @public */\nexport interface Geometry2dFilters {\n\treadonly includeLabels?: boolean\n\treadonly includeInternal?: boolean\n}\n\n/** @public */\nexport const Geometry2dFilters: {\n\tEXCLUDE_NON_STANDARD: Geometry2dFilters\n\tINCLUDE_ALL: Geometry2dFilters\n\tEXCLUDE_LABELS: Geometry2dFilters\n\tEXCLUDE_INTERNAL: Geometry2dFilters\n} = {\n\tEXCLUDE_NON_STANDARD: {\n\t\tincludeLabels: false,\n\t\tincludeInternal: false,\n\t},\n\tINCLUDE_ALL: { includeLabels: true, includeInternal: true },\n\tEXCLUDE_LABELS: { includeLabels: false, includeInternal: true },\n\tEXCLUDE_INTERNAL: { includeLabels: true, includeInternal: false },\n}\n\n/** @public */\nexport interface Geometry2dOptions {\n\tisFilled: boolean\n\tisClosed: boolean\n\tisLabel?: boolean\n\tisInternal?: boolean\n\tdebugColor?: string\n\tignore?: boolean\n}\n\n/** @public */\nexport abstract class Geometry2d {\n\tisFilled = false\n\tisClosed = true\n\tisLabel = false\n\tisInternal = false\n\tdebugColor?: string\n\tignore?: boolean\n\n\tconstructor(opts: Geometry2dOptions) {\n\t\tthis.isFilled = opts.isFilled\n\t\tthis.isClosed = opts.isClosed\n\t\tthis.isLabel = opts.isLabel ?? false\n\t\tthis.isInternal = opts.isInternal ?? false\n\t\tthis.debugColor = opts.debugColor\n\t\tthis.ignore = opts.ignore\n\t}\n\n\tisExcludedByFilter(filters?: Geometry2dFilters) {\n\t\tif (!filters) return false\n\t\tif (this.isLabel && !filters.includeLabels) return true\n\t\tif (this.isInternal && !filters.includeInternal) return true\n\t\treturn false\n\t}\n\n\tabstract getVertices(filters: Geometry2dFilters): Vec[]\n\n\tabstract nearestPoint(point: Vec, filters?: Geometry2dFilters): Vec\n\n\thitTestPoint(point: Vec, margin = 0, hitInside = false, filters?: Geometry2dFilters) {\n\t\tif (this.isExcludedByFilter(filters)) return false\n\t\t// First check whether the point is inside\n\t\tif (this.isClosed && (this.isFilled || hitInside) && pointInPolygon(point, this.vertices)) {\n\t\t\treturn true\n\t\t}\n\t\t// Then check whether the distance is within the margin\n\t\treturn Vec.Dist2(point, this.nearestPoint(point)) <= margin * margin\n\t}\n\n\tdistanceToPoint(point: Vec, hitInside = false, filters?: Geometry2dFilters) {\n\t\treturn (\n\t\t\tpoint.dist(this.nearestPoint(point, filters)) *\n\t\t\t(this.isClosed && (this.isFilled || hitInside) && pointInPolygon(point, this.vertices)\n\t\t\t\t? -1\n\t\t\t\t: 1)\n\t\t)\n\t}\n\n\tdistanceToLineSegment(A: Vec, B: Vec, filters?: Geometry2dFilters) {\n\t\tif (A.equals(B)) return this.distanceToPoint(A, false, filters)\n\t\tconst { vertices } = this\n\t\tlet nearest: Vec | undefined\n\t\tlet dist = Infinity\n\t\tlet d: number, p: Vec, q: Vec\n\t\tfor (let i = 0; i < vertices.length; i++) {\n\t\t\tp = vertices[i]\n\t\t\tq = Vec.NearestPointOnLineSegment(A, B, p, true)\n\t\t\td = Vec.Dist2(p, q)\n\t\t\tif (d < dist) {\n\t\t\t\tdist = d\n\t\t\t\tnearest = q\n\t\t\t}\n\t\t}\n\t\tif (!nearest) throw Error('nearest point not found')\n\t\treturn this.isClosed && this.isFilled && pointInPolygon(nearest, this.vertices) ? -dist : dist\n\t}\n\n\thitTestLineSegment(A: Vec, B: Vec, distance = 0, filters?: Geometry2dFilters): boolean {\n\t\treturn this.distanceToLineSegment(A, B, filters) <= distance\n\t}\n\n\tintersectLineSegment(A: VecLike, B: VecLike, filters?: Geometry2dFilters): VecLike[] {\n\t\tif (this.isExcludedByFilter(filters)) return []\n\n\t\tconst intersections = this.isClosed\n\t\t\t? intersectLineSegmentPolygon(A, B, this.vertices)\n\t\t\t: intersectLineSegmentPolyline(A, B, this.vertices)\n\n\t\treturn intersections ?? []\n\t}\n\n\tintersectCircle(center: VecLike, radius: number, filters?: Geometry2dFilters): VecLike[] {\n\t\tif (this.isExcludedByFilter(filters)) return []\n\t\tconst intersections = this.isClosed\n\t\t\t? intersectCirclePolygon(center, radius, this.vertices)\n\t\t\t: intersectCirclePolyline(center, radius, this.vertices)\n\n\t\treturn intersections ?? []\n\t}\n\n\tintersectPolygon(polygon: VecLike[], filters?: Geometry2dFilters): VecLike[] {\n\t\tif (this.isExcludedByFilter(filters)) return []\n\n\t\treturn intersectPolys(polygon, this.vertices, true, this.isClosed)\n\t}\n\n\tintersectPolyline(polyline: VecLike[], filters?: Geometry2dFilters): VecLike[] {\n\t\tif (this.isExcludedByFilter(filters)) return []\n\t\treturn intersectPolys(polyline, this.vertices, false, this.isClosed)\n\t}\n\n\t/** @deprecated Iterate the vertices instead. */\n\tnearestPointOnLineSegment(A: Vec, B: Vec): Vec {\n\t\tconst { vertices } = this\n\t\tlet nearest: Vec | undefined\n\t\tlet dist = Infinity\n\t\tlet d: number, p: Vec, q: Vec\n\t\tfor (let i = 0; i < vertices.length; i++) {\n\t\t\tp = vertices[i]\n\t\t\tq = Vec.NearestPointOnLineSegment(A, B, p, true)\n\t\t\td = Vec.Dist2(p, q)\n\t\t\tif (d < dist) {\n\t\t\t\tdist = d\n\t\t\t\tnearest = q\n\t\t\t}\n\t\t}\n\t\tif (!nearest) throw Error('nearest point not found')\n\t\treturn nearest\n\t}\n\n\tisPointInBounds(point: Vec, margin = 0) {\n\t\tconst { bounds } = this\n\t\treturn !(\n\t\t\tpoint.x < bounds.minX - margin ||\n\t\t\tpoint.y < bounds.minY - margin ||\n\t\t\tpoint.x > bounds.maxX + margin ||\n\t\t\tpoint.y > bounds.maxY + margin\n\t\t)\n\t}\n\n\ttransform(transform: MatModel): Geometry2d {\n\t\treturn new TransformedGeometry2d(this, transform)\n\t}\n\n\tprivate _vertices: Vec[] | undefined\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget vertices(): Vec[] {\n\t\tif (!this._vertices) {\n\t\t\tthis._vertices = this.getVertices(Geometry2dFilters.EXCLUDE_LABELS)\n\t\t}\n\n\t\treturn this._vertices\n\t}\n\n\tgetBounds() {\n\t\treturn Box.FromPoints(this.vertices)\n\t}\n\n\tprivate _bounds: Box | undefined\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget bounds(): Box {\n\t\tif (!this._bounds) {\n\t\t\tthis._bounds = this.getBounds()\n\t\t}\n\t\treturn this._bounds\n\t}\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget center() {\n\t\treturn this.bounds.center\n\t}\n\n\tprivate _area: number | undefined\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget area() {\n\t\tif (!this._area) {\n\t\t\tthis._area = this.getArea()\n\t\t}\n\t\treturn this._area\n\t}\n\n\tgetArea() {\n\t\tif (!this.isClosed) {\n\t\t\treturn 0\n\t\t}\n\t\tconst { vertices } = this\n\t\tlet area = 0\n\t\tfor (let i = 0, n = vertices.length; i < n; i++) {\n\t\t\tconst curr = vertices[i]\n\t\t\tconst next = vertices[(i + 1) % n]\n\t\t\tarea += curr.x * next.y - next.x * curr.y\n\t\t}\n\t\treturn area / 2\n\t}\n\n\ttoSimpleSvgPath() {\n\t\tlet path = ''\n\n\t\tconst { vertices } = this\n\t\tconst n = vertices.length\n\n\t\tif (n === 0) return path\n\n\t\tpath += `M${vertices[0].x},${vertices[0].y}`\n\n\t\tfor (let i = 1; i < n; i++) {\n\t\t\tpath += `L${vertices[i].x},${vertices[i].y}`\n\t\t}\n\n\t\tif (this.isClosed) {\n\t\t\tpath += 'Z'\n\t\t}\n\n\t\treturn path\n\t}\n\n\tprivate _length?: number\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget length() {\n\t\tif (this._length) return this._length\n\t\tthis._length = this.getLength()\n\t\treturn this._length\n\t}\n\n\tgetLength() {\n\t\tconst { vertices } = this\n\t\tlet n1: Vec,\n\t\t\tp1 = vertices[0],\n\t\t\tlength = 0\n\t\tfor (let i = 1; i < vertices.length; i++) {\n\t\t\tn1 = vertices[i]\n\t\t\tlength += Vec.Dist2(p1, n1)\n\t\t\tp1 = n1\n\t\t}\n\t\treturn Math.sqrt(length)\n\t}\n\n\tabstract getSvgPathData(first: boolean): string\n}\n\n// =================================================================================================\n// Because Geometry2d.transform depends on TransformedGeometry2d, we need to define it here instead\n// of in its own files. This prevents a circular import error.\n// =================================================================================================\n\n/** @public */\nexport class TransformedGeometry2d extends Geometry2d {\n\tprivate readonly inverse: MatModel\n\tprivate readonly decomposed\n\n\tconstructor(\n\t\tprivate readonly geometry: Geometry2d,\n\t\tprivate readonly matrix: MatModel\n\t) {\n\t\tsuper(geometry)\n\t\tthis.inverse = Mat.Inverse(matrix)\n\t\tthis.decomposed = Mat.Decompose(matrix)\n\n\t\tassert(\n\t\t\tapproximately(this.decomposed.scaleX, this.decomposed.scaleY),\n\t\t\t'non-uniform scaling is not yet supported'\n\t\t)\n\t}\n\n\tgetVertices(filters: Geometry2dFilters): Vec[] {\n\t\treturn this.geometry.getVertices(filters).map((v) => Mat.applyToPoint(this.matrix, v))\n\t}\n\n\tnearestPoint(point: Vec, filters?: Geometry2dFilters): Vec {\n\t\treturn Mat.applyToPoint(\n\t\t\tthis.matrix,\n\t\t\tthis.geometry.nearestPoint(Mat.applyToPoint(this.inverse, point), filters)\n\t\t)\n\t}\n\n\toverride hitTestPoint(\n\t\tpoint: Vec,\n\t\tmargin = 0,\n\t\thitInside?: boolean,\n\t\tfilters?: Geometry2dFilters\n\t): boolean {\n\t\treturn this.geometry.hitTestPoint(\n\t\t\tMat.applyToPoint(this.inverse, point),\n\t\t\tmargin / this.decomposed.scaleX,\n\t\t\thitInside,\n\t\t\tfilters\n\t\t)\n\t}\n\n\toverride distanceToPoint(point: Vec, hitInside = false, filters?: Geometry2dFilters) {\n\t\treturn (\n\t\t\tthis.geometry.distanceToPoint(Mat.applyToPoint(this.inverse, point), hitInside, filters) *\n\t\t\tthis.decomposed.scaleX\n\t\t)\n\t}\n\n\toverride distanceToLineSegment(A: Vec, B: Vec, filters?: Geometry2dFilters) {\n\t\treturn (\n\t\t\tthis.geometry.distanceToLineSegment(\n\t\t\t\tMat.applyToPoint(this.inverse, A),\n\t\t\t\tMat.applyToPoint(this.inverse, B),\n\t\t\t\tfilters\n\t\t\t) * this.decomposed.scaleX\n\t\t)\n\t}\n\n\toverride hitTestLineSegment(A: Vec, B: Vec, distance = 0, filters?: Geometry2dFilters): boolean {\n\t\treturn this.geometry.hitTestLineSegment(\n\t\t\tMat.applyToPoint(this.inverse, A),\n\t\t\tMat.applyToPoint(this.inverse, B),\n\t\t\tdistance / this.decomposed.scaleX,\n\t\t\tfilters\n\t\t)\n\t}\n\n\toverride intersectLineSegment(A: VecLike, B: VecLike, filters?: Geometry2dFilters) {\n\t\treturn this.geometry.intersectLineSegment(\n\t\t\tMat.applyToPoint(this.inverse, A),\n\t\t\tMat.applyToPoint(this.inverse, B),\n\t\t\tfilters\n\t\t)\n\t}\n\n\toverride intersectCircle(center: VecLike, radius: number, filters?: Geometry2dFilters) {\n\t\treturn this.geometry.intersectCircle(\n\t\t\tMat.applyToPoint(this.inverse, center),\n\t\t\tradius / this.decomposed.scaleX,\n\t\t\tfilters\n\t\t)\n\t}\n\n\toverride intersectPolygon(polygon: VecLike[], filters?: Geometry2dFilters): VecLike[] {\n\t\treturn this.geometry.intersectPolygon(Mat.applyToPoints(this.inverse, polygon), filters)\n\t}\n\n\toverride intersectPolyline(polyline: VecLike[], filters?: Geometry2dFilters): VecLike[] {\n\t\treturn this.geometry.intersectPolyline(Mat.applyToPoints(this.inverse, polyline), filters)\n\t}\n\n\toverride transform(transform: MatModel): Geometry2d {\n\t\treturn new TransformedGeometry2d(this.geometry, Mat.Multiply(transform, this.matrix))\n\t}\n\n\tgetSvgPathData(): string {\n\t\tthrow new Error('Cannot get SVG path data for transformed geometry.')\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { EMPTY_ARRAY } from "@tldraw/state";
|
|
1
2
|
import { Box } from "../Box.mjs";
|
|
2
3
|
import { Vec } from "../Vec.mjs";
|
|
3
|
-
import { Geometry2d } from "./Geometry2d.mjs";
|
|
4
|
+
import { Geometry2d, Geometry2dFilters } from "./Geometry2d.mjs";
|
|
4
5
|
class Group2d extends Geometry2d {
|
|
5
6
|
children = [];
|
|
6
7
|
ignoredChildren = [];
|
|
@@ -15,10 +16,11 @@ class Group2d extends Geometry2d {
|
|
|
15
16
|
}
|
|
16
17
|
if (this.children.length === 0) throw Error("Group2d must have at least one child");
|
|
17
18
|
}
|
|
18
|
-
getVertices() {
|
|
19
|
-
|
|
19
|
+
getVertices(filters) {
|
|
20
|
+
if (this.isExcludedByFilter(filters)) return [];
|
|
21
|
+
return this.children.filter((c) => !c.isExcludedByFilter(filters)).flatMap((c) => c.getVertices(filters));
|
|
20
22
|
}
|
|
21
|
-
nearestPoint(point) {
|
|
23
|
+
nearestPoint(point, filters) {
|
|
22
24
|
let dist = Infinity;
|
|
23
25
|
let nearest;
|
|
24
26
|
const { children } = this;
|
|
@@ -28,7 +30,8 @@ class Group2d extends Geometry2d {
|
|
|
28
30
|
let p;
|
|
29
31
|
let d;
|
|
30
32
|
for (const child of children) {
|
|
31
|
-
|
|
33
|
+
if (child.isExcludedByFilter(filters)) continue;
|
|
34
|
+
p = child.nearestPoint(point, filters);
|
|
32
35
|
d = Vec.Dist2(p, point);
|
|
33
36
|
if (d < dist) {
|
|
34
37
|
dist = d;
|
|
@@ -38,14 +41,54 @@ class Group2d extends Geometry2d {
|
|
|
38
41
|
if (!nearest) throw Error("nearest point not found");
|
|
39
42
|
return nearest;
|
|
40
43
|
}
|
|
41
|
-
distanceToPoint(point, hitInside = false) {
|
|
42
|
-
|
|
44
|
+
distanceToPoint(point, hitInside = false, filters) {
|
|
45
|
+
let smallestDistance = Infinity;
|
|
46
|
+
for (const child of this.children) {
|
|
47
|
+
if (child.isExcludedByFilter(filters)) continue;
|
|
48
|
+
const distance = child.distanceToPoint(point, hitInside, filters);
|
|
49
|
+
if (distance < smallestDistance) {
|
|
50
|
+
smallestDistance = distance;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return smallestDistance;
|
|
54
|
+
}
|
|
55
|
+
hitTestPoint(point, margin, hitInside, filters = Geometry2dFilters.EXCLUDE_LABELS) {
|
|
56
|
+
return !!this.children.filter((c) => !c.isExcludedByFilter(filters)).find((c) => c.hitTestPoint(point, margin, hitInside));
|
|
57
|
+
}
|
|
58
|
+
hitTestLineSegment(A, B, zoom, filters = Geometry2dFilters.EXCLUDE_LABELS) {
|
|
59
|
+
return !!this.children.filter((c) => !c.isExcludedByFilter(filters)).find((c) => c.hitTestLineSegment(A, B, zoom));
|
|
60
|
+
}
|
|
61
|
+
intersectLineSegment(A, B, filters) {
|
|
62
|
+
return this.children.flatMap((child) => {
|
|
63
|
+
if (child.isExcludedByFilter(filters)) return EMPTY_ARRAY;
|
|
64
|
+
return child.intersectLineSegment(A, B, filters);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
intersectCircle(center, radius, filters) {
|
|
68
|
+
return this.children.flatMap((child) => {
|
|
69
|
+
if (child.isExcludedByFilter(filters)) return EMPTY_ARRAY;
|
|
70
|
+
return child.intersectCircle(center, radius, filters);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
intersectPolygon(polygon, filters) {
|
|
74
|
+
return this.children.flatMap((child) => {
|
|
75
|
+
if (child.isExcludedByFilter(filters)) return EMPTY_ARRAY;
|
|
76
|
+
return child.intersectPolygon(polygon, filters);
|
|
77
|
+
});
|
|
43
78
|
}
|
|
44
|
-
|
|
45
|
-
return
|
|
79
|
+
intersectPolyline(polyline, filters) {
|
|
80
|
+
return this.children.flatMap((child) => {
|
|
81
|
+
if (child.isExcludedByFilter(filters)) return EMPTY_ARRAY;
|
|
82
|
+
return child.intersectPolyline(polyline, filters);
|
|
83
|
+
});
|
|
46
84
|
}
|
|
47
|
-
|
|
48
|
-
return
|
|
85
|
+
transform(transform) {
|
|
86
|
+
return new Group2d({
|
|
87
|
+
children: this.children.map((c) => c.transform(transform)),
|
|
88
|
+
isLabel: this.isLabel,
|
|
89
|
+
debugColor: this.debugColor,
|
|
90
|
+
ignore: this.ignore
|
|
91
|
+
});
|
|
49
92
|
}
|
|
50
93
|
getArea() {
|
|
51
94
|
return this.children[0].area;
|
|
@@ -73,7 +116,7 @@ class Group2d extends Geometry2d {
|
|
|
73
116
|
return this.children.reduce((a, c) => c.isLabel ? a : a + c.length, 0);
|
|
74
117
|
}
|
|
75
118
|
getSvgPathData() {
|
|
76
|
-
return this.children.map((c) => c.isLabel ? "" : c.getSvgPathData(
|
|
119
|
+
return this.children.map((c, i) => c.isLabel ? "" : c.getSvgPathData(i === 0)).join(" ");
|
|
77
120
|
}
|
|
78
121
|
}
|
|
79
122
|
export {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/primitives/geometry/Group2d.ts"],
|
|
4
|
-
"sourcesContent": ["import { Box } from '../Box'\nimport { Vec } from '../Vec'\nimport { Geometry2d, Geometry2dOptions } from './Geometry2d'\n\n/** @public */\nexport class Group2d extends Geometry2d {\n\tchildren: Geometry2d[] = []\n\tignoredChildren: Geometry2d[] = []\n\n\tconstructor(\n\t\tconfig: Omit<Geometry2dOptions, 'isClosed' | 'isFilled'> & {\n\t\t\tchildren: Geometry2d[]\n\t\t}\n\t) {\n\t\tsuper({ ...config, isClosed: true, isFilled: false })\n\n\t\tfor (const child of config.children) {\n\t\t\tif (child.ignore) {\n\t\t\t\tthis.ignoredChildren.push(child)\n\t\t\t} else {\n\t\t\t\tthis.children.push(child)\n\t\t\t}\n\t\t}\n\n\t\tif (this.children.length === 0) throw Error('Group2d must have at least one child')\n\t}\n\n\toverride getVertices(): Vec[] {\n\t\treturn this.children.filter((c) => !c.
|
|
5
|
-
"mappings": "AAAA,SAAS,
|
|
4
|
+
"sourcesContent": ["import { EMPTY_ARRAY } from '@tldraw/state'\nimport { Box } from '../Box'\nimport { Mat } from '../Mat'\nimport { Vec, VecLike } from '../Vec'\nimport { Geometry2d, Geometry2dFilters, Geometry2dOptions } from './Geometry2d'\n\n/** @public */\nexport class Group2d extends Geometry2d {\n\tchildren: Geometry2d[] = []\n\tignoredChildren: Geometry2d[] = []\n\n\tconstructor(\n\t\tconfig: Omit<Geometry2dOptions, 'isClosed' | 'isFilled'> & {\n\t\t\tchildren: Geometry2d[]\n\t\t}\n\t) {\n\t\tsuper({ ...config, isClosed: true, isFilled: false })\n\n\t\tfor (const child of config.children) {\n\t\t\tif (child.ignore) {\n\t\t\t\tthis.ignoredChildren.push(child)\n\t\t\t} else {\n\t\t\t\tthis.children.push(child)\n\t\t\t}\n\t\t}\n\n\t\tif (this.children.length === 0) throw Error('Group2d must have at least one child')\n\t}\n\n\toverride getVertices(filters: Geometry2dFilters): Vec[] {\n\t\tif (this.isExcludedByFilter(filters)) return []\n\t\treturn this.children\n\t\t\t.filter((c) => !c.isExcludedByFilter(filters))\n\t\t\t.flatMap((c) => c.getVertices(filters))\n\t}\n\n\toverride nearestPoint(point: Vec, filters?: Geometry2dFilters): Vec {\n\t\tlet dist = Infinity\n\t\tlet nearest: Vec | undefined\n\n\t\tconst { children } = this\n\n\t\tif (children.length === 0) {\n\t\t\tthrow Error('no children')\n\t\t}\n\n\t\tlet p: Vec\n\t\tlet d: number\n\t\tfor (const child of children) {\n\t\t\tif (child.isExcludedByFilter(filters)) continue\n\t\t\tp = child.nearestPoint(point, filters)\n\t\t\td = Vec.Dist2(p, point)\n\t\t\tif (d < dist) {\n\t\t\t\tdist = d\n\t\t\t\tnearest = p\n\t\t\t}\n\t\t}\n\t\tif (!nearest) throw Error('nearest point not found')\n\t\treturn nearest\n\t}\n\n\toverride distanceToPoint(point: Vec, hitInside = false, filters?: Geometry2dFilters) {\n\t\tlet smallestDistance = Infinity\n\t\tfor (const child of this.children) {\n\t\t\tif (child.isExcludedByFilter(filters)) continue\n\t\t\tconst distance = child.distanceToPoint(point, hitInside, filters)\n\t\t\tif (distance < smallestDistance) {\n\t\t\t\tsmallestDistance = distance\n\t\t\t}\n\t\t}\n\t\treturn smallestDistance\n\t}\n\n\toverride hitTestPoint(\n\t\tpoint: Vec,\n\t\tmargin: number,\n\t\thitInside: boolean,\n\t\tfilters = Geometry2dFilters.EXCLUDE_LABELS\n\t): boolean {\n\t\treturn !!this.children\n\t\t\t.filter((c) => !c.isExcludedByFilter(filters))\n\t\t\t.find((c) => c.hitTestPoint(point, margin, hitInside))\n\t}\n\n\toverride hitTestLineSegment(\n\t\tA: Vec,\n\t\tB: Vec,\n\t\tzoom: number,\n\t\tfilters = Geometry2dFilters.EXCLUDE_LABELS\n\t): boolean {\n\t\treturn !!this.children\n\t\t\t.filter((c) => !c.isExcludedByFilter(filters))\n\t\t\t.find((c) => c.hitTestLineSegment(A, B, zoom))\n\t}\n\n\toverride intersectLineSegment(A: VecLike, B: VecLike, filters?: Geometry2dFilters) {\n\t\treturn this.children.flatMap((child) => {\n\t\t\tif (child.isExcludedByFilter(filters)) return EMPTY_ARRAY\n\t\t\treturn child.intersectLineSegment(A, B, filters)\n\t\t})\n\t}\n\n\toverride intersectCircle(center: VecLike, radius: number, filters?: Geometry2dFilters) {\n\t\treturn this.children.flatMap((child) => {\n\t\t\tif (child.isExcludedByFilter(filters)) return EMPTY_ARRAY\n\t\t\treturn child.intersectCircle(center, radius, filters)\n\t\t})\n\t}\n\n\toverride intersectPolygon(polygon: VecLike[], filters?: Geometry2dFilters) {\n\t\treturn this.children.flatMap((child) => {\n\t\t\tif (child.isExcludedByFilter(filters)) return EMPTY_ARRAY\n\t\t\treturn child.intersectPolygon(polygon, filters)\n\t\t})\n\t}\n\n\toverride intersectPolyline(polyline: VecLike[], filters?: Geometry2dFilters) {\n\t\treturn this.children.flatMap((child) => {\n\t\t\tif (child.isExcludedByFilter(filters)) return EMPTY_ARRAY\n\t\t\treturn child.intersectPolyline(polyline, filters)\n\t\t})\n\t}\n\n\toverride transform(transform: Mat): Geometry2d {\n\t\treturn new Group2d({\n\t\t\tchildren: this.children.map((c) => c.transform(transform)),\n\t\t\tisLabel: this.isLabel,\n\t\t\tdebugColor: this.debugColor,\n\t\t\tignore: this.ignore,\n\t\t})\n\t}\n\n\tgetArea() {\n\t\t// todo: this is a temporary solution, assuming that the first child defines the group size; we would want to flatten the group and then find the area of the hull polygon\n\t\treturn this.children[0].area\n\t}\n\n\ttoSimpleSvgPath() {\n\t\tlet path = ''\n\t\tfor (const child of this.children) {\n\t\t\tpath += child.toSimpleSvgPath()\n\t\t}\n\n\t\tconst corners = Box.FromPoints(this.vertices).corners\n\t\t// draw just a few pixels around each corner, e.g. an L shape for the bottom left\n\n\t\tfor (let i = 0, n = corners.length; i < n; i++) {\n\t\t\tconst corner = corners[i]\n\t\t\tconst prevCorner = corners[(i - 1 + n) % n]\n\t\t\tconst prevDist = corner.dist(prevCorner)\n\t\t\tconst nextCorner = corners[(i + 1) % n]\n\t\t\tconst nextDist = corner.dist(nextCorner)\n\n\t\t\tconst A = corner.clone().lrp(prevCorner, 4 / prevDist)\n\t\t\tconst B = corner\n\t\t\tconst C = corner.clone().lrp(nextCorner, 4 / nextDist)\n\n\t\t\tpath += `M${A.x},${A.y} L${B.x},${B.y} L${C.x},${C.y} `\n\t\t}\n\t\treturn path\n\t}\n\n\tgetLength(): number {\n\t\treturn this.children.reduce((a, c) => (c.isLabel ? a : a + c.length), 0)\n\t}\n\n\tgetSvgPathData(): string {\n\t\treturn this.children.map((c, i) => (c.isLabel ? '' : c.getSvgPathData(i === 0))).join(' ')\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -155,6 +155,25 @@ function intersectPolygonPolygon(polygonA, polygonB) {
|
|
|
155
155
|
if (result.size === 0) return null;
|
|
156
156
|
return orderClockwise([...result.values()]);
|
|
157
157
|
}
|
|
158
|
+
function intersectPolys(polyA, polyB, isAClosed, isBClosed) {
|
|
159
|
+
const result = /* @__PURE__ */ new Map();
|
|
160
|
+
for (let i = 0, n = isAClosed ? polyA.length : polyA.length - 1; i < n; i++) {
|
|
161
|
+
const currentA = polyA[i];
|
|
162
|
+
const nextA = polyA[(i + 1) % polyA.length];
|
|
163
|
+
for (let j = 0, m = isBClosed ? polyB.length : polyB.length - 1; j < m; j++) {
|
|
164
|
+
const currentB = polyB[j];
|
|
165
|
+
const nextB = polyB[(j + 1) % polyB.length];
|
|
166
|
+
const intersection = intersectLineSegmentLineSegment(currentA, nextA, currentB, nextB);
|
|
167
|
+
if (intersection !== null) {
|
|
168
|
+
const id = getPointId(intersection);
|
|
169
|
+
if (!result.has(id)) {
|
|
170
|
+
result.set(id, intersection);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return [...result.values()];
|
|
176
|
+
}
|
|
158
177
|
function getPointId(point) {
|
|
159
178
|
return `${point.x},${point.y}`;
|
|
160
179
|
}
|
|
@@ -198,6 +217,7 @@ export {
|
|
|
198
217
|
intersectLineSegmentPolyline,
|
|
199
218
|
intersectPolygonBounds,
|
|
200
219
|
intersectPolygonPolygon,
|
|
220
|
+
intersectPolys,
|
|
201
221
|
linesIntersect,
|
|
202
222
|
polygonIntersectsPolyline,
|
|
203
223
|
polygonsIntersect
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/primitives/intersect.ts"],
|
|
4
|
-
"sourcesContent": ["import { Box } from './Box'\nimport { pointInPolygon } from './utils'\nimport { Vec, VecLike } from './Vec'\n\n// need even more intersections? See https://gist.github.com/steveruizok/35c02d526c707003a5c79761bfb89a52\n\n/**\n * Find the intersection between a line segment and a line segment.\n *\n * @param a1 - The first segment's first point.\n * @param a2 - The first segment's second point.\n * @param b1 - The second segment's first point.\n * @param b2 - The second segment's second point.\n * @public\n */\nexport function intersectLineSegmentLineSegment(\n\ta1: VecLike,\n\ta2: VecLike,\n\tb1: VecLike,\n\tb2: VecLike\n) {\n\tconst ABx = a1.x - b1.x\n\tconst ABy = a1.y - b1.y\n\tconst BVx = b2.x - b1.x\n\tconst BVy = b2.y - b1.y\n\tconst AVx = a2.x - a1.x\n\tconst AVy = a2.y - a1.y\n\tconst ua_t = BVx * ABy - BVy * ABx\n\tconst ub_t = AVx * ABy - AVy * ABx\n\tconst u_b = BVy * AVx - BVx * AVy\n\n\tif (ua_t === 0 || ub_t === 0) return null // coincident\n\n\tif (u_b === 0) return null // parallel\n\n\tif (u_b !== 0) {\n\t\tconst ua = ua_t / u_b\n\t\tconst ub = ub_t / u_b\n\t\tif (0 <= ua && ua <= 1 && 0 <= ub && ub <= 1) {\n\t\t\treturn Vec.AddXY(a1, ua * AVx, ua * AVy)\n\t\t}\n\t}\n\n\treturn null // no intersection\n}\n\n/**\n * Find the intersections between a line segment and a circle.\n *\n * @param a1 - The segment's first point.\n * @param a2 - The segment's second point.\n * @param c - The circle's center.\n * @param r - The circle's radius.\n * @public\n */\nexport function intersectLineSegmentCircle(a1: VecLike, a2: VecLike, c: VecLike, r: number) {\n\tconst a = (a2.x - a1.x) * (a2.x - a1.x) + (a2.y - a1.y) * (a2.y - a1.y)\n\tconst b = 2 * ((a2.x - a1.x) * (a1.x - c.x) + (a2.y - a1.y) * (a1.y - c.y))\n\tconst cc =\n\t\tc.x * c.x + c.y * c.y + a1.x * a1.x + a1.y * a1.y - 2 * (c.x * a1.x + c.y * a1.y) - r * r\n\tconst deter = b * b - 4 * a * cc\n\n\tif (deter < 0) return null // outside\n\tif (deter === 0) return null // tangent\n\n\tconst e = Math.sqrt(deter)\n\tconst u1 = (-b + e) / (2 * a)\n\tconst u2 = (-b - e) / (2 * a)\n\n\tif ((u1 < 0 || u1 > 1) && (u2 < 0 || u2 > 1)) {\n\t\treturn null // outside or inside\n\t\t// if ((u1 < 0 && u2 < 0) || (u1 > 1 && u2 > 1)) {\n\t\t// \treturn null // outside\n\t\t// } else return null // inside'\n\t}\n\n\tconst result: VecLike[] = []\n\n\tif (0 <= u1 && u1 <= 1) result.push(Vec.Lrp(a1, a2, u1))\n\tif (0 <= u2 && u2 <= 1) result.push(Vec.Lrp(a1, a2, u2))\n\n\tif (result.length === 0) return null // no intersection\n\n\treturn result\n}\n\n/**\n * Find the intersections between a line segment and a polyline.\n *\n * @param a1 - The segment's first point.\n * @param a2 - The segment's second point.\n * @param points - The points in the polyline.\n * @public\n */\nexport function intersectLineSegmentPolyline(a1: VecLike, a2: VecLike, points: VecLike[]) {\n\tconst result: VecLike[] = []\n\tlet segmentIntersection: VecLike | null\n\n\tfor (let i = 0, n = points.length - 1; i < n; i++) {\n\t\tsegmentIntersection = intersectLineSegmentLineSegment(a1, a2, points[i], points[i + 1])\n\t\tif (segmentIntersection) result.push(segmentIntersection)\n\t}\n\n\tif (result.length === 0) return null // no intersection\n\n\treturn result\n}\n\n/**\n * Find the intersections between a line segment and a closed polygon.\n *\n * @param a1 - The segment's first point.\n * @param a2 - The segment's second point.\n * @param points - The points in the polygon.\n * @public\n */\nexport function intersectLineSegmentPolygon(a1: VecLike, a2: VecLike, points: VecLike[]) {\n\tconst result: VecLike[] = []\n\tlet segmentIntersection: VecLike | null\n\n\tfor (let i = 1, n = points.length; i < n + 1; i++) {\n\t\tsegmentIntersection = intersectLineSegmentLineSegment(\n\t\t\ta1,\n\t\t\ta2,\n\t\t\tpoints[i - 1],\n\t\t\tpoints[i % points.length]\n\t\t)\n\t\tif (segmentIntersection) result.push(segmentIntersection)\n\t}\n\n\tif (result.length === 0) return null // no intersection\n\n\treturn result\n}\n\n/**\n * Find the intersections between a circle and a circle.\n *\n * @param c1 - The first circle's center.\n * @param r1 - The first circle's radius.\n * @param c2 - The second circle's center.\n * @param r2 - The second circle's radius.\n * @public\n */\nexport function intersectCircleCircle(c1: VecLike, r1: number, c2: VecLike, r2: number) {\n\tlet dx = c2.x - c1.x\n\tlet dy = c2.y - c1.y\n\tconst d = Math.sqrt(dx * dx + dy * dy),\n\t\tx = (d * d - r2 * r2 + r1 * r1) / (2 * d),\n\t\ty = Math.sqrt(r1 * r1 - x * x)\n\tdx /= d\n\tdy /= d\n\treturn [\n\t\tnew Vec(c1.x + dx * x - dy * y, c1.y + dy * x + dx * y),\n\t\tnew Vec(c1.x + dx * x + dy * y, c1.y + dy * x - dx * y),\n\t]\n}\n\n/**\n * Find the intersections between a circle and a bounding box.\n *\n * @param c - The circle's center.\n * @param r - The circle's radius.\n * @param points - The points in the polygon.\n * @public\n */\nexport function intersectCirclePolygon(c: VecLike, r: number, points: VecLike[]) {\n\tconst result: VecLike[] = []\n\tlet a: VecLike, b: VecLike, int: VecLike[] | null\n\n\tfor (let i = 0, n = points.length; i < n; i++) {\n\t\ta = points[i]\n\t\tb = points[(i + 1) % points.length]\n\t\tint = intersectLineSegmentCircle(a, b, c, r)\n\t\tif (int) result.push(...int)\n\t}\n\n\tif (result.length === 0) return null // no intersection\n\n\treturn result\n}\n\n/**\n * Find the intersections between a circle and a bounding box.\n *\n * @param c - The circle's center.\n * @param r - The circle's radius.\n * @param points - The points in the polyline.\n * @public\n */\nexport function intersectCirclePolyline(c: VecLike, r: number, points: VecLike[]) {\n\tconst result: VecLike[] = []\n\tlet a: VecLike, b: VecLike, int: VecLike[] | null\n\n\tfor (let i = 1, n = points.length; i < n; i++) {\n\t\ta = points[i - 1]\n\t\tb = points[i]\n\t\tint = intersectLineSegmentCircle(a, b, c, r)\n\t\tif (int) result.push(...int)\n\t}\n\n\tif (result.length === 0) return null // no intersection\n\n\treturn result\n}\n\n/**\n * Find the intersections between a polygon and a bounding box.\n *\n * @public\n */\nexport function intersectPolygonBounds(points: VecLike[], bounds: Box) {\n\tconst result: VecLike[] = []\n\tlet segmentIntersection: VecLike[] | null\n\n\tfor (const side of bounds.sides) {\n\t\tsegmentIntersection = intersectLineSegmentPolygon(side[0], side[1], points)\n\t\tif (segmentIntersection) result.push(...segmentIntersection)\n\t}\n\n\tif (result.length === 0) return null // no intersection\n\n\treturn result\n}\n\nfunction ccw(A: VecLike, B: VecLike, C: VecLike) {\n\treturn (C.y - A.y) * (B.x - A.x) > (B.y - A.y) * (C.x - A.x)\n}\n\n/** @public */\nexport function linesIntersect(A: VecLike, B: VecLike, C: VecLike, D: VecLike) {\n\treturn ccw(A, C, D) !== ccw(B, C, D) && ccw(A, B, C) !== ccw(A, B, D)\n}\n\n/**\n * Create a new convex polygon as the intersection of two convex polygons.\n *\n * @param polygonA - An array of points representing the first polygon.\n * @param polygonB - An array of points representing the second polygon.\n * @public\n */\nexport function intersectPolygonPolygon(\n\tpolygonA: VecLike[],\n\tpolygonB: VecLike[]\n): VecLike[] | null {\n\t// Create an empty polygon as result\n\tconst result: Map<string, VecLike> = new Map()\n\tlet a: VecLike, b: VecLike, c: VecLike, d: VecLike\n\n\t// Add all corners of PolygonA that is inside PolygonB to result\n\tfor (let i = 0, n = polygonA.length; i < n; i++) {\n\t\ta = polygonA[i]\n\t\tif (pointInPolygon(a, polygonB)) {\n\t\t\tconst id = getPointId(a)\n\t\t\tif (!result.has(id)) {\n\t\t\t\tresult.set(id, a)\n\t\t\t}\n\t\t}\n\t}\n\t// Add all corners of PolygonB that is inside PolygonA to result\n\tfor (let i = 0, n = polygonB.length; i < n; i++) {\n\t\ta = polygonB[i]\n\t\tif (pointInPolygon(a, polygonA)) {\n\t\t\tconst id = getPointId(a)\n\t\t\tif (!result.has(id)) {\n\t\t\t\tresult.set(id, a)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Add all intersection points to result\n\tfor (let i = 0, n = polygonA.length; i < n; i++) {\n\t\ta = polygonA[i]\n\t\tb = polygonA[(i + 1) % polygonA.length]\n\n\t\tfor (let j = 0, m = polygonB.length; j < m; j++) {\n\t\t\tc = polygonB[j]\n\t\t\td = polygonB[(j + 1) % polygonB.length]\n\t\t\tconst intersection = intersectLineSegmentLineSegment(a, b, c, d)\n\n\t\t\tif (intersection !== null) {\n\t\t\t\tconst id = getPointId(intersection)\n\t\t\t\tif (!result.has(id)) {\n\t\t\t\t\tresult.set(id, intersection)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (result.size === 0) return null // no intersection\n\n\t// Order all points in the result counter-clockwise.\n\treturn orderClockwise([...result.values()])\n}\n\nfunction getPointId(point: VecLike) {\n\treturn `${point.x},${point.y}`\n}\n\nfunction orderClockwise(points: VecLike[]): VecLike[] {\n\tconst C = Vec.Average(points)\n\treturn points.sort((A, B) => Vec.Angle(C, A) - Vec.Angle(C, B))\n}\n\n/** @public */\nexport function polygonsIntersect(a: VecLike[], b: VecLike[]) {\n\tlet a0: VecLike, a1: VecLike, b0: VecLike, b1: VecLike\n\tfor (let i = 0, n = a.length; i < n; i++) {\n\t\ta0 = a[i]\n\t\ta1 = a[(i + 1) % n]\n\t\tfor (let j = 0, m = b.length; j < m; j++) {\n\t\t\tb0 = b[j]\n\t\t\tb1 = b[(j + 1) % m]\n\t\t\tif (linesIntersect(a0, a1, b0, b1)) return true\n\t\t}\n\t}\n\treturn false\n}\n\n/** @public */\nexport function polygonIntersectsPolyline(polygon: VecLike[], polyline: VecLike[]) {\n\tlet a: VecLike, b: VecLike, c: VecLike, d: VecLike\n\tfor (let i = 0, n = polygon.length; i < n; i++) {\n\t\ta = polygon[i]\n\t\tb = polygon[(i + 1) % n]\n\n\t\tfor (let j = 1, m = polyline.length; j < m; j++) {\n\t\t\tc = polyline[j - 1]\n\t\t\td = polyline[j]\n\t\t\tif (linesIntersect(a, b, c, d)) return true\n\t\t}\n\t}\n\treturn false\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { Box } from './Box'\nimport { pointInPolygon } from './utils'\nimport { Vec, VecLike } from './Vec'\n\n// need even more intersections? See https://gist.github.com/steveruizok/35c02d526c707003a5c79761bfb89a52\n\n/**\n * Find the intersection between a line segment and a line segment.\n *\n * @param a1 - The first segment's first point.\n * @param a2 - The first segment's second point.\n * @param b1 - The second segment's first point.\n * @param b2 - The second segment's second point.\n * @public\n */\nexport function intersectLineSegmentLineSegment(\n\ta1: VecLike,\n\ta2: VecLike,\n\tb1: VecLike,\n\tb2: VecLike\n) {\n\tconst ABx = a1.x - b1.x\n\tconst ABy = a1.y - b1.y\n\tconst BVx = b2.x - b1.x\n\tconst BVy = b2.y - b1.y\n\tconst AVx = a2.x - a1.x\n\tconst AVy = a2.y - a1.y\n\tconst ua_t = BVx * ABy - BVy * ABx\n\tconst ub_t = AVx * ABy - AVy * ABx\n\tconst u_b = BVy * AVx - BVx * AVy\n\n\tif (ua_t === 0 || ub_t === 0) return null // coincident\n\n\tif (u_b === 0) return null // parallel\n\n\tif (u_b !== 0) {\n\t\tconst ua = ua_t / u_b\n\t\tconst ub = ub_t / u_b\n\t\tif (0 <= ua && ua <= 1 && 0 <= ub && ub <= 1) {\n\t\t\treturn Vec.AddXY(a1, ua * AVx, ua * AVy)\n\t\t}\n\t}\n\n\treturn null // no intersection\n}\n\n/**\n * Find the intersections between a line segment and a circle.\n *\n * @param a1 - The segment's first point.\n * @param a2 - The segment's second point.\n * @param c - The circle's center.\n * @param r - The circle's radius.\n * @public\n */\nexport function intersectLineSegmentCircle(a1: VecLike, a2: VecLike, c: VecLike, r: number) {\n\tconst a = (a2.x - a1.x) * (a2.x - a1.x) + (a2.y - a1.y) * (a2.y - a1.y)\n\tconst b = 2 * ((a2.x - a1.x) * (a1.x - c.x) + (a2.y - a1.y) * (a1.y - c.y))\n\tconst cc =\n\t\tc.x * c.x + c.y * c.y + a1.x * a1.x + a1.y * a1.y - 2 * (c.x * a1.x + c.y * a1.y) - r * r\n\tconst deter = b * b - 4 * a * cc\n\n\tif (deter < 0) return null // outside\n\tif (deter === 0) return null // tangent\n\n\tconst e = Math.sqrt(deter)\n\tconst u1 = (-b + e) / (2 * a)\n\tconst u2 = (-b - e) / (2 * a)\n\n\tif ((u1 < 0 || u1 > 1) && (u2 < 0 || u2 > 1)) {\n\t\treturn null // outside or inside\n\t\t// if ((u1 < 0 && u2 < 0) || (u1 > 1 && u2 > 1)) {\n\t\t// \treturn null // outside\n\t\t// } else return null // inside'\n\t}\n\n\tconst result: VecLike[] = []\n\n\tif (0 <= u1 && u1 <= 1) result.push(Vec.Lrp(a1, a2, u1))\n\tif (0 <= u2 && u2 <= 1) result.push(Vec.Lrp(a1, a2, u2))\n\n\tif (result.length === 0) return null // no intersection\n\n\treturn result\n}\n\n/**\n * Find the intersections between a line segment and a polyline.\n *\n * @param a1 - The segment's first point.\n * @param a2 - The segment's second point.\n * @param points - The points in the polyline.\n * @public\n */\nexport function intersectLineSegmentPolyline(a1: VecLike, a2: VecLike, points: VecLike[]) {\n\tconst result: VecLike[] = []\n\tlet segmentIntersection: VecLike | null\n\n\tfor (let i = 0, n = points.length - 1; i < n; i++) {\n\t\tsegmentIntersection = intersectLineSegmentLineSegment(a1, a2, points[i], points[i + 1])\n\t\tif (segmentIntersection) result.push(segmentIntersection)\n\t}\n\n\tif (result.length === 0) return null // no intersection\n\n\treturn result\n}\n\n/**\n * Find the intersections between a line segment and a closed polygon.\n *\n * @param a1 - The segment's first point.\n * @param a2 - The segment's second point.\n * @param points - The points in the polygon.\n * @public\n */\nexport function intersectLineSegmentPolygon(a1: VecLike, a2: VecLike, points: VecLike[]) {\n\tconst result: VecLike[] = []\n\tlet segmentIntersection: VecLike | null\n\n\tfor (let i = 1, n = points.length; i < n + 1; i++) {\n\t\tsegmentIntersection = intersectLineSegmentLineSegment(\n\t\t\ta1,\n\t\t\ta2,\n\t\t\tpoints[i - 1],\n\t\t\tpoints[i % points.length]\n\t\t)\n\t\tif (segmentIntersection) result.push(segmentIntersection)\n\t}\n\n\tif (result.length === 0) return null // no intersection\n\n\treturn result\n}\n\n/**\n * Find the intersections between a circle and a circle.\n *\n * @param c1 - The first circle's center.\n * @param r1 - The first circle's radius.\n * @param c2 - The second circle's center.\n * @param r2 - The second circle's radius.\n * @public\n */\nexport function intersectCircleCircle(c1: VecLike, r1: number, c2: VecLike, r2: number) {\n\tlet dx = c2.x - c1.x\n\tlet dy = c2.y - c1.y\n\tconst d = Math.sqrt(dx * dx + dy * dy),\n\t\tx = (d * d - r2 * r2 + r1 * r1) / (2 * d),\n\t\ty = Math.sqrt(r1 * r1 - x * x)\n\tdx /= d\n\tdy /= d\n\treturn [\n\t\tnew Vec(c1.x + dx * x - dy * y, c1.y + dy * x + dx * y),\n\t\tnew Vec(c1.x + dx * x + dy * y, c1.y + dy * x - dx * y),\n\t]\n}\n\n/**\n * Find the intersections between a circle and a bounding box.\n *\n * @param c - The circle's center.\n * @param r - The circle's radius.\n * @param points - The points in the polygon.\n * @public\n */\nexport function intersectCirclePolygon(c: VecLike, r: number, points: VecLike[]) {\n\tconst result: VecLike[] = []\n\tlet a: VecLike, b: VecLike, int: VecLike[] | null\n\n\tfor (let i = 0, n = points.length; i < n; i++) {\n\t\ta = points[i]\n\t\tb = points[(i + 1) % points.length]\n\t\tint = intersectLineSegmentCircle(a, b, c, r)\n\t\tif (int) result.push(...int)\n\t}\n\n\tif (result.length === 0) return null // no intersection\n\n\treturn result\n}\n\n/**\n * Find the intersections between a circle and a bounding box.\n *\n * @param c - The circle's center.\n * @param r - The circle's radius.\n * @param points - The points in the polyline.\n * @public\n */\nexport function intersectCirclePolyline(c: VecLike, r: number, points: VecLike[]) {\n\tconst result: VecLike[] = []\n\tlet a: VecLike, b: VecLike, int: VecLike[] | null\n\n\tfor (let i = 1, n = points.length; i < n; i++) {\n\t\ta = points[i - 1]\n\t\tb = points[i]\n\t\tint = intersectLineSegmentCircle(a, b, c, r)\n\t\tif (int) result.push(...int)\n\t}\n\n\tif (result.length === 0) return null // no intersection\n\n\treturn result\n}\n\n/**\n * Find the intersections between a polygon and a bounding box.\n *\n * @public\n */\nexport function intersectPolygonBounds(points: VecLike[], bounds: Box) {\n\tconst result: VecLike[] = []\n\tlet segmentIntersection: VecLike[] | null\n\n\tfor (const side of bounds.sides) {\n\t\tsegmentIntersection = intersectLineSegmentPolygon(side[0], side[1], points)\n\t\tif (segmentIntersection) result.push(...segmentIntersection)\n\t}\n\n\tif (result.length === 0) return null // no intersection\n\n\treturn result\n}\n\nfunction ccw(A: VecLike, B: VecLike, C: VecLike) {\n\treturn (C.y - A.y) * (B.x - A.x) > (B.y - A.y) * (C.x - A.x)\n}\n\n/** @public */\nexport function linesIntersect(A: VecLike, B: VecLike, C: VecLike, D: VecLike) {\n\treturn ccw(A, C, D) !== ccw(B, C, D) && ccw(A, B, C) !== ccw(A, B, D)\n}\n\n/**\n * Create a new convex polygon as the intersection of two convex polygons.\n *\n * @param polygonA - An array of points representing the first polygon.\n * @param polygonB - An array of points representing the second polygon.\n * @public\n */\nexport function intersectPolygonPolygon(\n\tpolygonA: VecLike[],\n\tpolygonB: VecLike[]\n): VecLike[] | null {\n\t// Create an empty polygon as result\n\tconst result: Map<string, VecLike> = new Map()\n\tlet a: VecLike, b: VecLike, c: VecLike, d: VecLike\n\n\t// Add all corners of PolygonA that is inside PolygonB to result\n\tfor (let i = 0, n = polygonA.length; i < n; i++) {\n\t\ta = polygonA[i]\n\t\tif (pointInPolygon(a, polygonB)) {\n\t\t\tconst id = getPointId(a)\n\t\t\tif (!result.has(id)) {\n\t\t\t\tresult.set(id, a)\n\t\t\t}\n\t\t}\n\t}\n\t// Add all corners of PolygonB that is inside PolygonA to result\n\tfor (let i = 0, n = polygonB.length; i < n; i++) {\n\t\ta = polygonB[i]\n\t\tif (pointInPolygon(a, polygonA)) {\n\t\t\tconst id = getPointId(a)\n\t\t\tif (!result.has(id)) {\n\t\t\t\tresult.set(id, a)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Add all intersection points to result\n\tfor (let i = 0, n = polygonA.length; i < n; i++) {\n\t\ta = polygonA[i]\n\t\tb = polygonA[(i + 1) % polygonA.length]\n\n\t\tfor (let j = 0, m = polygonB.length; j < m; j++) {\n\t\t\tc = polygonB[j]\n\t\t\td = polygonB[(j + 1) % polygonB.length]\n\t\t\tconst intersection = intersectLineSegmentLineSegment(a, b, c, d)\n\n\t\t\tif (intersection !== null) {\n\t\t\t\tconst id = getPointId(intersection)\n\t\t\t\tif (!result.has(id)) {\n\t\t\t\t\tresult.set(id, intersection)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (result.size === 0) return null // no intersection\n\n\t// Order all points in the result counter-clockwise.\n\treturn orderClockwise([...result.values()])\n}\n\n/**\n * Find all the points where `polyA` and `polyB` intersect and returns them in an undefined order.\n * To find the polygon that's the intersection of polyA and polyB, use `intersectPolygonPolygon`\n * instead, which orders the points and includes internal points.\n *\n * @param polyA - The first polygon.\n * @param polyB - The second polygon.\n * @param isAClosed - Whether `polyA` is a closed polygon or a polyline.\n * @param isBClosed - Whether `polyB` is a closed polygon or a polyline.\n * @public\n */\nexport function intersectPolys(\n\tpolyA: VecLike[],\n\tpolyB: VecLike[],\n\tisAClosed: boolean,\n\tisBClosed: boolean\n): VecLike[] {\n\tconst result: Map<string, VecLike> = new Map()\n\n\t// Add all intersection points to result\n\tfor (let i = 0, n = isAClosed ? polyA.length : polyA.length - 1; i < n; i++) {\n\t\tconst currentA = polyA[i]\n\t\tconst nextA = polyA[(i + 1) % polyA.length]\n\n\t\tfor (let j = 0, m = isBClosed ? polyB.length : polyB.length - 1; j < m; j++) {\n\t\t\tconst currentB = polyB[j]\n\t\t\tconst nextB = polyB[(j + 1) % polyB.length]\n\t\t\tconst intersection = intersectLineSegmentLineSegment(currentA, nextA, currentB, nextB)\n\n\t\t\tif (intersection !== null) {\n\t\t\t\tconst id = getPointId(intersection)\n\t\t\t\tif (!result.has(id)) {\n\t\t\t\t\tresult.set(id, intersection)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn [...result.values()]\n}\n\nfunction getPointId(point: VecLike) {\n\treturn `${point.x},${point.y}`\n}\n\nfunction orderClockwise(points: VecLike[]): VecLike[] {\n\tconst C = Vec.Average(points)\n\treturn points.sort((A, B) => Vec.Angle(C, A) - Vec.Angle(C, B))\n}\n\n/** @public */\nexport function polygonsIntersect(a: VecLike[], b: VecLike[]) {\n\tlet a0: VecLike, a1: VecLike, b0: VecLike, b1: VecLike\n\tfor (let i = 0, n = a.length; i < n; i++) {\n\t\ta0 = a[i]\n\t\ta1 = a[(i + 1) % n]\n\t\tfor (let j = 0, m = b.length; j < m; j++) {\n\t\t\tb0 = b[j]\n\t\t\tb1 = b[(j + 1) % m]\n\t\t\tif (linesIntersect(a0, a1, b0, b1)) return true\n\t\t}\n\t}\n\treturn false\n}\n\n/** @public */\nexport function polygonIntersectsPolyline(polygon: VecLike[], polyline: VecLike[]) {\n\tlet a: VecLike, b: VecLike, c: VecLike, d: VecLike\n\tfor (let i = 0, n = polygon.length; i < n; i++) {\n\t\ta = polygon[i]\n\t\tb = polygon[(i + 1) % n]\n\n\t\tfor (let j = 1, m = polyline.length; j < m; j++) {\n\t\t\tc = polyline[j - 1]\n\t\t\td = polyline[j]\n\t\t\tif (linesIntersect(a, b, c, d)) return true\n\t\t}\n\t}\n\treturn false\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -88,20 +88,14 @@ function reorderToFront(moving, children, changes) {
|
|
|
88
88
|
);
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
-
function getVerticesInPageSpace(editor, shape) {
|
|
92
|
-
const geo = editor.getShapeGeometry(shape);
|
|
93
|
-
const pageTransform = editor.getShapePageTransform(shape);
|
|
94
|
-
if (!geo || !pageTransform) return null;
|
|
95
|
-
return pageTransform.applyToPoints(geo.vertices);
|
|
96
|
-
}
|
|
97
91
|
function getOverlapChecker(editor, moving) {
|
|
98
92
|
const movingVertices = Array.from(moving).map((shape) => {
|
|
99
|
-
const vertices =
|
|
93
|
+
const vertices = editor.getShapePageGeometry(shape).vertices;
|
|
100
94
|
if (!vertices) return null;
|
|
101
95
|
return { shape, vertices };
|
|
102
96
|
}).filter(Boolean);
|
|
103
97
|
const isOverlapping = (child) => {
|
|
104
|
-
const vertices =
|
|
98
|
+
const vertices = editor.getShapePageGeometry(child).vertices;
|
|
105
99
|
if (!vertices) return false;
|
|
106
100
|
return movingVertices.some((other) => {
|
|
107
101
|
return polygonsIntersect(other.vertices, vertices);
|