@tldraw/editor 5.4.0-next.ef99ab47e5ce → 5.4.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/index.d.ts +114 -47
- package/dist-cjs/index.js +4 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +7 -2
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/MenuClickCapture.js +6 -8
- package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
- package/dist-cjs/lib/components/default-components/CanvasOverlays.js +1 -3
- package/dist-cjs/lib/components/default-components/CanvasOverlays.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +1 -1
- package/dist-cjs/lib/config/TLUserPreferences.js +6 -2
- package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
- package/dist-cjs/lib/config/createTLStore.js +1 -1
- package/dist-cjs/lib/config/createTLStore.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +181 -294
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/shapeIdsInCurrentPage.js +7 -3
- package/dist-cjs/lib/editor/derivations/shapeIdsInCurrentPage.js.map +2 -2
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +3 -3
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js +8 -8
- package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/FontManager/FontManager.js +2 -1
- package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js +79 -6
- package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js +7 -0
- package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js +0 -2
- package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +1 -2
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TickManager/TickManager.js +6 -3
- package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +12 -1
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
- package/dist-cjs/lib/editor/overlays/OverlayManager.js +3 -7
- package/dist-cjs/lib/editor/overlays/OverlayManager.js.map +2 -2
- package/dist-cjs/lib/editor/overlays/strokeShapeIndicators.js +0 -1
- package/dist-cjs/lib/editor/overlays/strokeShapeIndicators.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js +3 -1
- package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/shared/getPerfectDashProps.js +1 -0
- package/dist-cjs/lib/editor/shapes/shared/getPerfectDashProps.js.map +2 -2
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js +1 -1
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +2 -2
- package/dist-cjs/lib/editor/tools/StateNode.js +3 -2
- package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
- package/dist-cjs/lib/globals/editors.js +57 -0
- package/dist-cjs/lib/globals/editors.js.map +7 -0
- package/dist-cjs/lib/globals/menus.js +9 -4
- package/dist-cjs/lib/globals/menus.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +2 -0
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useDocumentEvents.js +39 -9
- package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useLocalStore.js +10 -6
- package/dist-cjs/lib/hooks/useLocalStore.js.map +2 -2
- package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js +1 -0
- package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/usePeerIds.js +2 -1
- package/dist-cjs/lib/hooks/usePeerIds.js.map +2 -2
- package/dist-cjs/lib/license/LicenseManager.js +9 -2
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/license/LicenseProvider.js +16 -3
- package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
- package/dist-cjs/lib/license/useLicenseManagerState.js +5 -4
- package/dist-cjs/lib/license/useLicenseManagerState.js.map +2 -2
- package/dist-cjs/lib/primitives/Box.js +2 -1
- package/dist-cjs/lib/primitives/Box.js.map +2 -2
- package/dist-cjs/lib/primitives/Vec.js +4 -3
- package/dist-cjs/lib/primitives/Vec.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Group2d.js +63 -21
- package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
- package/dist-cjs/lib/primitives/utils.js +2 -1
- package/dist-cjs/lib/primitives/utils.js.map +2 -2
- package/dist-cjs/lib/utils/deepLinks.js +5 -1
- package/dist-cjs/lib/utils/deepLinks.js.map +2 -2
- package/dist-cjs/lib/utils/normalizeWheel.js +2 -0
- package/dist-cjs/lib/utils/normalizeWheel.js.map +2 -2
- package/dist-cjs/lib/utils/rotation.js +1 -9
- package/dist-cjs/lib/utils/rotation.js.map +2 -2
- package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +17 -0
- package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js.map +2 -2
- package/dist-cjs/lib/utils/sync/alerts.js +1 -1
- package/dist-cjs/lib/utils/sync/alerts.js.map +1 -1
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +114 -47
- package/dist-esm/index.mjs +9 -2
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +9 -4
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/MenuClickCapture.mjs +6 -8
- package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/CanvasOverlays.mjs +1 -3
- package/dist-esm/lib/components/default-components/CanvasOverlays.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +1 -1
- package/dist-esm/lib/config/TLUserPreferences.mjs +6 -2
- package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
- package/dist-esm/lib/config/createTLStore.mjs +1 -1
- package/dist-esm/lib/config/createTLStore.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +189 -295
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/shapeIdsInCurrentPage.mjs +7 -3
- package/dist-esm/lib/editor/derivations/shapeIdsInCurrentPage.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +3 -3
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs +9 -9
- package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs +2 -1
- package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs +81 -8
- package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs +7 -0
- package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs +0 -2
- package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +2 -3
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs +6 -3
- package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +12 -1
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
- package/dist-esm/lib/editor/overlays/OverlayManager.mjs +3 -7
- package/dist-esm/lib/editor/overlays/OverlayManager.mjs.map +2 -2
- package/dist-esm/lib/editor/overlays/strokeShapeIndicators.mjs +0 -1
- package/dist-esm/lib/editor/overlays/strokeShapeIndicators.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs +3 -1
- package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/shared/getPerfectDashProps.mjs +1 -0
- package/dist-esm/lib/editor/shapes/shared/getPerfectDashProps.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs +1 -1
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/StateNode.mjs +3 -2
- package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
- package/dist-esm/lib/globals/editors.mjs +37 -0
- package/dist-esm/lib/globals/editors.mjs.map +7 -0
- package/dist-esm/lib/globals/menus.mjs +9 -4
- package/dist-esm/lib/globals/menus.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +2 -0
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useDocumentEvents.mjs +40 -10
- package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useLocalStore.mjs +11 -7
- package/dist-esm/lib/hooks/useLocalStore.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs +1 -0
- package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePeerIds.mjs +2 -1
- package/dist-esm/lib/hooks/usePeerIds.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseManager.mjs +9 -2
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseProvider.mjs +16 -3
- package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
- package/dist-esm/lib/license/useLicenseManagerState.mjs +5 -4
- package/dist-esm/lib/license/useLicenseManagerState.mjs.map +2 -2
- package/dist-esm/lib/primitives/Box.mjs +2 -1
- package/dist-esm/lib/primitives/Box.mjs.map +2 -2
- package/dist-esm/lib/primitives/Vec.mjs +4 -3
- package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Group2d.mjs +63 -21
- package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/utils.mjs +2 -1
- package/dist-esm/lib/primitives/utils.mjs.map +2 -2
- package/dist-esm/lib/utils/deepLinks.mjs +5 -1
- package/dist-esm/lib/utils/deepLinks.mjs.map +2 -2
- package/dist-esm/lib/utils/normalizeWheel.mjs +2 -0
- package/dist-esm/lib/utils/normalizeWheel.mjs.map +2 -2
- package/dist-esm/lib/utils/rotation.mjs +1 -9
- package/dist-esm/lib/utils/rotation.mjs.map +2 -2
- package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +17 -0
- package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs.map +2 -2
- package/dist-esm/lib/utils/sync/alerts.mjs +1 -1
- package/dist-esm/lib/utils/sync/alerts.mjs.map +1 -1
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +13 -7
- package/src/index.ts +6 -1
- package/src/lib/TldrawEditor.tsx +16 -4
- package/src/lib/components/MenuClickCapture.tsx +19 -18
- package/src/lib/components/default-components/CanvasOverlays.tsx +1 -3
- package/src/lib/components/default-components/DefaultErrorFallback.tsx +1 -1
- package/src/lib/config/TLUserPreferences.test.ts +18 -1
- package/src/lib/config/TLUserPreferences.ts +8 -4
- package/src/lib/config/createTLStore.ts +1 -1
- package/src/lib/editor/Editor.ts +266 -383
- package/src/lib/editor/derivations/shapeIdsInCurrentPage.ts +7 -3
- package/src/lib/editor/managers/ClickManager/ClickManager.ts +5 -3
- package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.ts +9 -9
- package/src/lib/editor/managers/FontManager/FontManager.ts +2 -1
- package/src/lib/editor/managers/InputsManager/InputsManager.test.ts +199 -3
- package/src/lib/editor/managers/InputsManager/InputsManager.ts +128 -9
- package/src/lib/editor/managers/ScribbleManager/ScribbleManager.ts +12 -1
- package/src/lib/editor/managers/SnapManager/BoundsSnaps.ts +0 -2
- package/src/lib/editor/managers/TextManager/TextManager.ts +2 -6
- package/src/lib/editor/managers/TickManager/TickManager.test.ts +13 -0
- package/src/lib/editor/managers/TickManager/TickManager.ts +9 -3
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +64 -3
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +18 -1
- package/src/lib/editor/overlays/OverlayManager.ts +3 -7
- package/src/lib/editor/overlays/strokeShapeIndicators.ts +0 -1
- package/src/lib/editor/shapes/BaseFrameLikeShapeUtil.tsx +5 -1
- package/src/lib/editor/shapes/shared/getPerfectDashProps.ts +3 -0
- package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +4 -1
- package/src/lib/editor/tools/StateNode.test.ts +64 -0
- package/src/lib/editor/tools/StateNode.ts +12 -2
- package/src/lib/globals/editors.test.ts +76 -0
- package/src/lib/globals/editors.ts +53 -0
- package/src/lib/globals/menus.test.ts +33 -0
- package/src/lib/globals/menus.ts +11 -4
- package/src/lib/hooks/useCanvasEvents.ts +2 -0
- package/src/lib/hooks/useDocumentEvents.ts +60 -16
- package/src/lib/hooks/useLocalStore.ts +16 -8
- package/src/lib/hooks/usePassThroughWheelEvents.ts +3 -0
- package/src/lib/hooks/usePeerIds.ts +2 -1
- package/src/lib/license/LicenseManager.test.ts +160 -0
- package/src/lib/license/LicenseManager.ts +13 -4
- package/src/lib/license/LicenseProvider.tsx +24 -3
- package/src/lib/license/useLicenseManagerState.ts +8 -6
- package/src/lib/primitives/Box.test.ts +9 -1
- package/src/lib/primitives/Box.ts +3 -1
- package/src/lib/primitives/Vec.test.ts +10 -0
- package/src/lib/primitives/Vec.ts +4 -4
- package/src/lib/primitives/geometry/Arc2d.test.ts +226 -3
- package/src/lib/primitives/geometry/CubicBezier2d.test.ts +173 -3
- package/src/lib/primitives/geometry/CubicSpline2d.test.ts +160 -3
- package/src/lib/primitives/geometry/Ellipse2d.test.ts +243 -3
- package/src/lib/primitives/geometry/Geometry2d.test.ts +553 -1
- package/src/lib/primitives/geometry/Group2d.test.ts +398 -3
- package/src/lib/primitives/geometry/Group2d.ts +63 -27
- package/src/lib/primitives/geometry/Polyline2d.test.ts +207 -0
- package/src/lib/primitives/geometry/Stadium2d.test.ts +191 -3
- package/src/lib/primitives/utils.test.ts +10 -1
- package/src/lib/primitives/utils.ts +4 -1
- package/src/lib/test/useCanvasEvents.test.tsx +74 -0
- package/src/lib/test/useDocumentEvents.test.tsx +107 -0
- package/src/lib/test/usePassThroughWheelEvents.test.tsx +25 -2
- package/src/lib/utils/deepLinks.test.ts +15 -0
- package/src/lib/utils/deepLinks.ts +7 -1
- package/src/lib/utils/normalizeWheel.test.ts +39 -0
- package/src/lib/utils/normalizeWheel.ts +6 -0
- package/src/lib/utils/rotation.ts +4 -12
- package/src/lib/utils/sync/TLLocalSyncClient.test.ts +56 -0
- package/src/lib/utils/sync/TLLocalSyncClient.ts +24 -0
- package/src/lib/utils/sync/alerts.ts +1 -1
- package/src/version.ts +3 -3
- package/src/lib/primitives/geometry/Polyline.test.ts +0 -5
|
@@ -1,5 +1,400 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { Mat } from '../Mat'
|
|
2
|
+
import { Vec, VecLike } from '../Vec'
|
|
3
|
+
import { Edge2d } from './Edge2d'
|
|
4
|
+
import { Geometry2dFilters, TransformedGeometry2d } from './Geometry2d'
|
|
5
|
+
import { Group2d } from './Group2d'
|
|
6
|
+
import { Rectangle2d } from './Rectangle2d'
|
|
7
|
+
|
|
8
|
+
// Two rectangles side by side with a gap between them
|
|
9
|
+
const rectA = () => new Rectangle2d({ width: 100, height: 50, isFilled: true })
|
|
10
|
+
const rectB = () => new Rectangle2d({ x: 200, width: 50, height: 50, isFilled: false })
|
|
11
|
+
// A small filled label to the right of both, and an internal geometry further right
|
|
12
|
+
const label = () =>
|
|
13
|
+
new Rectangle2d({ x: 300, width: 20, height: 20, isFilled: true, isLabel: true })
|
|
14
|
+
const internal = () =>
|
|
15
|
+
new Rectangle2d({ x: 400, width: 10, height: 10, isFilled: true, isInternal: true })
|
|
16
|
+
|
|
17
|
+
const group = () => new Group2d({ children: [rectA(), rectB()] })
|
|
18
|
+
const groupWithLabel = () => new Group2d({ children: [rectA(), label(), rectB()] })
|
|
19
|
+
|
|
20
|
+
// An L shaped path made of two edges, 200 units long in total
|
|
21
|
+
const path = () =>
|
|
22
|
+
new Group2d({
|
|
23
|
+
children: [
|
|
24
|
+
new Edge2d({ start: new Vec(0, 0), end: new Vec(100, 0) }),
|
|
25
|
+
new Edge2d({ start: new Vec(100, 0), end: new Vec(100, 100) }),
|
|
26
|
+
],
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
function sortByX(points: VecLike[]) {
|
|
30
|
+
const round = (n: number) => Math.round(n * 1e6) / 1e6
|
|
31
|
+
return [...points]
|
|
32
|
+
.map((p) => ({ x: round(p.x), y: round(p.y) }))
|
|
33
|
+
.sort((a, b) => a.x - b.x || a.y - b.y)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
describe('Group2d construction', () => {
|
|
37
|
+
it('is closed and unfilled and passes through the other options', () => {
|
|
38
|
+
const g = new Group2d({
|
|
39
|
+
children: [rectA()],
|
|
40
|
+
isLabel: true,
|
|
41
|
+
debugColor: 'red',
|
|
42
|
+
excludeFromShapeBounds: true,
|
|
43
|
+
})
|
|
44
|
+
expect(g).toMatchObject({
|
|
45
|
+
isClosed: true,
|
|
46
|
+
isFilled: false,
|
|
47
|
+
isLabel: true,
|
|
48
|
+
debugColor: 'red',
|
|
49
|
+
excludeFromShapeBounds: true,
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('keeps the children in order', () => {
|
|
54
|
+
const a = rectA()
|
|
55
|
+
const b = rectB()
|
|
56
|
+
const g = new Group2d({ children: [a, b] })
|
|
57
|
+
expect(g.children).toEqual([a, b])
|
|
58
|
+
expect(g.ignoredChildren).toEqual([])
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('flattens nested groups', () => {
|
|
62
|
+
const a = rectA()
|
|
63
|
+
const b = rectB()
|
|
64
|
+
const c = label()
|
|
65
|
+
const g = new Group2d({ children: [a, new Group2d({ children: [b, c] })] })
|
|
66
|
+
expect(g.children).toEqual([a, b, c])
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('separates ignored children', () => {
|
|
70
|
+
const a = rectA()
|
|
71
|
+
const ignored = new Rectangle2d({ width: 10, height: 10, isFilled: true, ignore: true })
|
|
72
|
+
const g = new Group2d({ children: [a, ignored] })
|
|
73
|
+
expect(g.children).toEqual([a])
|
|
74
|
+
expect(g.ignoredChildren).toEqual([ignored])
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('throws without any non-ignored children', () => {
|
|
78
|
+
expect(() => new Group2d({ children: [] })).toThrow('Group2d must have at least one child')
|
|
79
|
+
expect(
|
|
80
|
+
() =>
|
|
81
|
+
new Group2d({
|
|
82
|
+
children: [new Rectangle2d({ width: 10, height: 10, isFilled: true, ignore: true })],
|
|
83
|
+
})
|
|
84
|
+
).toThrow('Group2d must have at least one child')
|
|
85
|
+
})
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
describe('Group2d.getVertices', () => {
|
|
89
|
+
it('concatenates the vertices of the children', () => {
|
|
90
|
+
expect(group().vertices).toMatchObject([
|
|
91
|
+
{ x: 0, y: 0 },
|
|
92
|
+
{ x: 100, y: 0 },
|
|
93
|
+
{ x: 100, y: 50 },
|
|
94
|
+
{ x: 0, y: 50 },
|
|
95
|
+
{ x: 200, y: 0 },
|
|
96
|
+
{ x: 250, y: 0 },
|
|
97
|
+
{ x: 250, y: 50 },
|
|
98
|
+
{ x: 200, y: 50 },
|
|
99
|
+
])
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('excludes labels by default but keeps internal geometry', () => {
|
|
103
|
+
const g = new Group2d({ children: [rectA(), label(), internal()] })
|
|
104
|
+
expect(g.vertices.length).toBe(8)
|
|
105
|
+
expect(g.getVertices(Geometry2dFilters.EXCLUDE_LABELS).length).toBe(8)
|
|
106
|
+
expect(g.getVertices(Geometry2dFilters.INCLUDE_ALL).length).toBe(12)
|
|
107
|
+
expect(g.getVertices(Geometry2dFilters.EXCLUDE_INTERNAL).length).toBe(8)
|
|
108
|
+
expect(g.getVertices(Geometry2dFilters.EXCLUDE_NON_STANDARD).length).toBe(4)
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('returns nothing when the group itself is excluded by the filter', () => {
|
|
112
|
+
const g = new Group2d({ children: [rectA()], isLabel: true })
|
|
113
|
+
expect(g.getVertices(Geometry2dFilters.EXCLUDE_LABELS)).toEqual([])
|
|
114
|
+
expect(g.getVertices(Geometry2dFilters.INCLUDE_ALL).length).toBe(4)
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('ignores ignored children', () => {
|
|
118
|
+
const ignored = new Rectangle2d({ x: 500, width: 10, height: 10, isFilled: true, ignore: true })
|
|
119
|
+
const g = new Group2d({ children: [rectA(), ignored] })
|
|
120
|
+
expect(g.getVertices(Geometry2dFilters.INCLUDE_ALL).length).toBe(4)
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
describe('Group2d.bounds', () => {
|
|
125
|
+
it('is the union of the children bounds', () => {
|
|
126
|
+
expect(group().bounds).toMatchObject({ x: 0, y: 0, w: 250, h: 50 })
|
|
127
|
+
expect(group().center).toMatchObject({ x: 125, y: 25 })
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
it('includes labels', () => {
|
|
131
|
+
expect(groupWithLabel().bounds).toMatchObject({ x: 0, y: 0, w: 320, h: 50 })
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
describe('Group2d.getLength', () => {
|
|
136
|
+
it('sums the child lengths, excluding labels by default', () => {
|
|
137
|
+
expect(group().length).toBe(500)
|
|
138
|
+
expect(groupWithLabel().length).toBe(500)
|
|
139
|
+
expect(groupWithLabel().getLength(Geometry2dFilters.INCLUDE_ALL)).toBe(580)
|
|
140
|
+
expect(groupWithLabel().getLength(Geometry2dFilters.EXCLUDE_LABELS)).toBe(500)
|
|
141
|
+
})
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
describe('Group2d.getArea', () => {
|
|
145
|
+
it('uses the area of the first child', () => {
|
|
146
|
+
expect(group().area).toBe(5000)
|
|
147
|
+
expect(new Group2d({ children: [rectB(), rectA()] }).area).toBe(2500)
|
|
148
|
+
})
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
describe('Group2d.nearestPoint', () => {
|
|
152
|
+
it('returns the nearest point across the children, preferring earlier children on ties', () => {
|
|
153
|
+
expect(group().nearestPoint(new Vec(190, 25))).toMatchObject({ x: 200, y: 25 })
|
|
154
|
+
expect(group().nearestPoint(new Vec(50, -10))).toMatchObject({ x: 50, y: 0 })
|
|
155
|
+
expect(group().nearestPoint(new Vec(150, 25))).toMatchObject({ x: 100, y: 25 })
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
it('respects the filters', () => {
|
|
159
|
+
const g = groupWithLabel()
|
|
160
|
+
expect(g.nearestPoint(new Vec(310, 30), Geometry2dFilters.INCLUDE_ALL)).toMatchObject({
|
|
161
|
+
x: 310,
|
|
162
|
+
y: 20,
|
|
163
|
+
})
|
|
164
|
+
expect(g.nearestPoint(new Vec(310, 30), Geometry2dFilters.EXCLUDE_LABELS)).toMatchObject({
|
|
165
|
+
x: 250,
|
|
166
|
+
y: 30,
|
|
167
|
+
})
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
it('uses the label when no filters are given', () => {
|
|
171
|
+
expect(groupWithLabel().nearestPoint(new Vec(310, 30))).toMatchObject({ x: 310, y: 20 })
|
|
172
|
+
})
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
describe('Group2d.distanceToPoint', () => {
|
|
176
|
+
it('is the smallest child distance, negative inside a filled child', () => {
|
|
177
|
+
expect(group().distanceToPoint(new Vec(50, 25))).toBe(-25)
|
|
178
|
+
expect(group().distanceToPoint(new Vec(225, 25))).toBe(25)
|
|
179
|
+
expect(group().distanceToPoint(new Vec(225, 25), true)).toBe(-25)
|
|
180
|
+
expect(group().distanceToPoint(new Vec(150, 25))).toBe(50)
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
it('respects the filters', () => {
|
|
184
|
+
const g = groupWithLabel()
|
|
185
|
+
expect(g.distanceToPoint(new Vec(310, 10), false, Geometry2dFilters.INCLUDE_ALL)).toBe(-10)
|
|
186
|
+
expect(g.distanceToPoint(new Vec(310, 10), false, Geometry2dFilters.EXCLUDE_LABELS)).toBe(60)
|
|
187
|
+
})
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
describe('Group2d.hitTestPoint', () => {
|
|
191
|
+
it('hits when any child hits', () => {
|
|
192
|
+
expect(group().hitTestPoint(new Vec(50, 25), 0, false)).toBe(true)
|
|
193
|
+
expect(group().hitTestPoint(new Vec(225, 25), 0, false)).toBe(false)
|
|
194
|
+
expect(group().hitTestPoint(new Vec(225, 25), 0, true)).toBe(true)
|
|
195
|
+
expect(group().hitTestPoint(new Vec(150, 25), 0, true)).toBe(false)
|
|
196
|
+
expect(group().hitTestPoint(new Vec(150, 25), 50, false)).toBe(true)
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
it('excludes labels by default', () => {
|
|
200
|
+
const g = groupWithLabel()
|
|
201
|
+
expect(g.hitTestPoint(new Vec(310, 10), 0, false)).toBe(false)
|
|
202
|
+
expect(g.hitTestPoint(new Vec(310, 10), 0, false, Geometry2dFilters.INCLUDE_ALL)).toBe(true)
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
it('never hits ignored children', () => {
|
|
206
|
+
const ignored = new Rectangle2d({ x: 500, width: 10, height: 10, isFilled: true, ignore: true })
|
|
207
|
+
const g = new Group2d({ children: [rectA(), ignored] })
|
|
208
|
+
expect(g.hitTestPoint(new Vec(505, 5), 0, true)).toBe(false)
|
|
209
|
+
})
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
describe('Group2d.hitTestLineSegment', () => {
|
|
213
|
+
it('hits when any child hits', () => {
|
|
214
|
+
expect(group().hitTestLineSegment(new Vec(90, 25), new Vec(110, 25), 0)).toBe(true)
|
|
215
|
+
expect(group().hitTestLineSegment(new Vec(240, 25), new Vec(260, 25), 0)).toBe(true)
|
|
216
|
+
expect(group().hitTestLineSegment(new Vec(150, -10), new Vec(150, 60), 0)).toBe(false)
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
it('passes the distance to the children', () => {
|
|
220
|
+
expect(group().hitTestLineSegment(new Vec(150, 0), new Vec(150, 50), 50)).toBe(true)
|
|
221
|
+
expect(group().hitTestLineSegment(new Vec(150, 0), new Vec(150, 50), 49)).toBe(false)
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
it('excludes labels by default', () => {
|
|
225
|
+
const g = groupWithLabel()
|
|
226
|
+
expect(g.hitTestLineSegment(new Vec(310, -10), new Vec(310, 30), 0)).toBe(false)
|
|
227
|
+
expect(
|
|
228
|
+
g.hitTestLineSegment(new Vec(310, -10), new Vec(310, 30), 0, Geometry2dFilters.INCLUDE_ALL)
|
|
229
|
+
).toBe(true)
|
|
230
|
+
})
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
describe('Group2d.intersectLineSegment', () => {
|
|
234
|
+
it('collects the intersections from every child', () => {
|
|
235
|
+
const hits = group().intersectLineSegment(new Vec(-10, 25), new Vec(300, 25))
|
|
236
|
+
expect(sortByX(hits)).toEqual([
|
|
237
|
+
{ x: 0, y: 25 },
|
|
238
|
+
{ x: 100, y: 25 },
|
|
239
|
+
{ x: 200, y: 25 },
|
|
240
|
+
{ x: 250, y: 25 },
|
|
241
|
+
])
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
it('respects the filters', () => {
|
|
245
|
+
const g = groupWithLabel()
|
|
246
|
+
const A = new Vec(-10, 10)
|
|
247
|
+
const B = new Vec(400, 10)
|
|
248
|
+
expect(g.intersectLineSegment(A, B).length).toBe(6)
|
|
249
|
+
expect(g.intersectLineSegment(A, B, Geometry2dFilters.EXCLUDE_LABELS).length).toBe(4)
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
it('returns an empty array when nothing is hit', () => {
|
|
253
|
+
expect(group().intersectLineSegment(new Vec(150, -10), new Vec(150, 60))).toEqual([])
|
|
254
|
+
})
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
describe('Group2d.intersectCircle', () => {
|
|
258
|
+
it('collects the intersections from every child', () => {
|
|
259
|
+
const hits = group().intersectCircle(new Vec(0, 25), 10)
|
|
260
|
+
expect(sortByX(hits)).toEqual([
|
|
261
|
+
{ x: 0, y: 15 },
|
|
262
|
+
{ x: 0, y: 35 },
|
|
263
|
+
])
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
it('respects the filters', () => {
|
|
267
|
+
const g = groupWithLabel()
|
|
268
|
+
expect(g.intersectCircle(new Vec(300, 10), 5).length).toBe(2)
|
|
269
|
+
expect(g.intersectCircle(new Vec(300, 10), 5, Geometry2dFilters.EXCLUDE_LABELS)).toEqual([])
|
|
270
|
+
})
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
describe('Group2d.intersectPolygon and intersectPolyline', () => {
|
|
274
|
+
const polygon = [new Vec(50, -10), new Vec(110, -10), new Vec(110, 60), new Vec(50, 60)]
|
|
275
|
+
|
|
276
|
+
it('collects polygon intersections from every child', () => {
|
|
277
|
+
expect(sortByX(group().intersectPolygon(polygon))).toEqual([
|
|
278
|
+
{ x: 50, y: 0 },
|
|
279
|
+
{ x: 50, y: 50 },
|
|
280
|
+
])
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
it('collects polyline intersections from every child', () => {
|
|
284
|
+
const polyline = [new Vec(50, -10), new Vec(50, 60)]
|
|
285
|
+
expect(sortByX(group().intersectPolyline(polyline))).toEqual([
|
|
286
|
+
{ x: 50, y: 0 },
|
|
287
|
+
{ x: 50, y: 50 },
|
|
288
|
+
])
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
it('respects the filters', () => {
|
|
292
|
+
const g = groupWithLabel()
|
|
293
|
+
const labelPolygon = [new Vec(310, -10), new Vec(330, -10), new Vec(330, 30), new Vec(310, 30)]
|
|
294
|
+
expect(g.intersectPolygon(labelPolygon).length).toBe(2)
|
|
295
|
+
expect(g.intersectPolygon(labelPolygon, Geometry2dFilters.EXCLUDE_LABELS)).toEqual([])
|
|
296
|
+
const labelPolyline = [new Vec(310, -10), new Vec(310, 30)]
|
|
297
|
+
expect(g.intersectPolyline(labelPolyline).length).toBe(2)
|
|
298
|
+
expect(g.intersectPolyline(labelPolyline, Geometry2dFilters.EXCLUDE_LABELS)).toEqual([])
|
|
299
|
+
})
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
describe('Group2d.interpolateAlongEdge', () => {
|
|
303
|
+
it('walks through the children in order', () => {
|
|
304
|
+
const p = path()
|
|
305
|
+
expect(p.interpolateAlongEdge(0)).toMatchObject({ x: 0, y: 0 })
|
|
306
|
+
expect(p.interpolateAlongEdge(0.25)).toMatchObject({ x: 50, y: 0 })
|
|
307
|
+
expect(p.interpolateAlongEdge(0.5)).toMatchObject({ x: 100, y: 0 })
|
|
308
|
+
expect(p.interpolateAlongEdge(0.75)).toMatchObject({ x: 100, y: 50 })
|
|
309
|
+
expect(p.interpolateAlongEdge(1)).toMatchObject({ x: 100, y: 100 })
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
it('clamps to the end of the last child', () => {
|
|
313
|
+
expect(path().interpolateAlongEdge(1.5)).toMatchObject({ x: 100, y: 100 })
|
|
314
|
+
})
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
describe('Group2d.uninterpolateAlongEdge', () => {
|
|
318
|
+
it('is the inverse of interpolateAlongEdge', () => {
|
|
319
|
+
const p = path()
|
|
320
|
+
expect(p.uninterpolateAlongEdge(new Vec(0, 0))).toBe(0)
|
|
321
|
+
expect(p.uninterpolateAlongEdge(new Vec(50, 0))).toBe(0.25)
|
|
322
|
+
expect(p.uninterpolateAlongEdge(new Vec(100, 0))).toBe(0.5)
|
|
323
|
+
expect(p.uninterpolateAlongEdge(new Vec(100, 50))).toBe(0.75)
|
|
324
|
+
expect(p.uninterpolateAlongEdge(new Vec(100, 100))).toBe(1)
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
it('snaps points off the path to the nearest child', () => {
|
|
328
|
+
expect(path().uninterpolateAlongEdge(new Vec(50, -20))).toBe(0.25)
|
|
329
|
+
expect(path().uninterpolateAlongEdge(new Vec(120, 50))).toBe(0.75)
|
|
330
|
+
})
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
describe('Group2d.transform', () => {
|
|
334
|
+
it('transforms every child', () => {
|
|
335
|
+
const t = group().transform(Mat.Translate(10, 20))
|
|
336
|
+
expect(t).toBeInstanceOf(Group2d)
|
|
337
|
+
expect((t as Group2d).children.every((c) => c instanceof TransformedGeometry2d)).toBe(true)
|
|
338
|
+
expect(t.bounds).toMatchObject({ x: 10, y: 20, w: 250, h: 50 })
|
|
339
|
+
expect(t.vertices[0]).toMatchObject({ x: 10, y: 20 })
|
|
340
|
+
expect(t.vertices.length).toBe(8)
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
it('carries the label, debug colour and ignore flags forward', () => {
|
|
344
|
+
const g = new Group2d({
|
|
345
|
+
children: [rectA()],
|
|
346
|
+
isLabel: true,
|
|
347
|
+
debugColor: 'red',
|
|
348
|
+
ignore: true,
|
|
349
|
+
})
|
|
350
|
+
expect(g.transform(Mat.Identity())).toMatchObject({
|
|
351
|
+
isLabel: true,
|
|
352
|
+
debugColor: 'red',
|
|
353
|
+
ignore: true,
|
|
354
|
+
})
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
it('scales hit testing with the transform', () => {
|
|
358
|
+
const t = group().transform(Mat.Scale(2, 2))
|
|
359
|
+
expect(t.hitTestPoint(new Vec(100, 50), 0, false)).toBe(true)
|
|
360
|
+
expect(t.hitTestPoint(new Vec(300, 50), 0, false)).toBe(false)
|
|
361
|
+
expect(t.distanceToPoint(new Vec(300, 50))).toBe(100)
|
|
362
|
+
})
|
|
363
|
+
|
|
364
|
+
// Locks in current behaviour, see #10562.
|
|
365
|
+
it('drops the ignored children', () => {
|
|
366
|
+
const ignored = new Rectangle2d({ x: 500, width: 10, height: 10, isFilled: true, ignore: true })
|
|
367
|
+
const g = new Group2d({ children: [rectA(), ignored] })
|
|
368
|
+
expect(g.ignoredChildren.length).toBe(1)
|
|
369
|
+
expect((g.transform(Mat.Identity()) as Group2d).ignoredChildren).toEqual([])
|
|
370
|
+
})
|
|
371
|
+
})
|
|
372
|
+
|
|
373
|
+
describe('Group2d.overlapsPolygon', () => {
|
|
374
|
+
it('overlaps when any child overlaps', () => {
|
|
375
|
+
const aroundB = [new Vec(190, -10), new Vec(260, -10), new Vec(260, 60), new Vec(190, 60)]
|
|
376
|
+
expect(group().overlapsPolygon(aroundB)).toBe(true)
|
|
377
|
+
const gap = [new Vec(120, 10), new Vec(180, 10), new Vec(180, 40), new Vec(120, 40)]
|
|
378
|
+
expect(group().overlapsPolygon(gap)).toBe(false)
|
|
379
|
+
})
|
|
380
|
+
})
|
|
381
|
+
|
|
382
|
+
describe('Group2d svg output', () => {
|
|
383
|
+
it('joins the children paths and skips labels', () => {
|
|
384
|
+
expect(group().getSvgPathData()).toBe('M0,0 h100 v50 h-100z M200,0 h50 v50 h-50z')
|
|
385
|
+
expect(groupWithLabel().getSvgPathData()).toBe('M0,0 h100 v50 h-100z M200,0 h50 v50 h-50z')
|
|
386
|
+
})
|
|
387
|
+
|
|
388
|
+
it('draws the children plus a small corner mark at each bounds corner', () => {
|
|
389
|
+
const g = new Group2d({
|
|
390
|
+
children: [new Rectangle2d({ width: 128, height: 64, isFilled: true })],
|
|
391
|
+
})
|
|
392
|
+
expect(g.toSimpleSvgPath()).toBe(
|
|
393
|
+
'M0,0L128,0L128,64L0,64Z' +
|
|
394
|
+
'M0,4 L0,0 L4,0 ' +
|
|
395
|
+
'M124,0 L128,0 L128,4 ' +
|
|
396
|
+
'M128,60 L128,64 L124,64 ' +
|
|
397
|
+
'M4,64 L0,64 L0,60 '
|
|
398
|
+
)
|
|
4
399
|
})
|
|
5
400
|
})
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { EMPTY_ARRAY } from '@tldraw/state'
|
|
2
1
|
import { assert, invLerp, lerp } from '@tldraw/utils'
|
|
3
2
|
import { Box } from '../Box'
|
|
4
3
|
import { Mat } from '../Mat'
|
|
@@ -36,9 +35,15 @@ export class Group2d extends Geometry2d {
|
|
|
36
35
|
|
|
37
36
|
override getVertices(filters: Geometry2dFilters): Vec[] {
|
|
38
37
|
if (this.isExcludedByFilter(filters)) return []
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
const vertices: Vec[] = []
|
|
39
|
+
for (const child of this.children) {
|
|
40
|
+
if (child.isExcludedByFilter(filters)) continue
|
|
41
|
+
const childVertices = child.getVertices(filters)
|
|
42
|
+
for (let i = 0, n = childVertices.length; i < n; i++) {
|
|
43
|
+
vertices.push(childVertices[i])
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return vertices
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
override nearestPoint(point: VecLike, filters?: Geometry2dFilters): Vec {
|
|
@@ -84,9 +89,11 @@ export class Group2d extends Geometry2d {
|
|
|
84
89
|
hitInside: boolean,
|
|
85
90
|
filters = Geometry2dFilters.EXCLUDE_LABELS
|
|
86
91
|
): boolean {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
92
|
+
for (const child of this.children) {
|
|
93
|
+
if (child.isExcludedByFilter(filters)) continue
|
|
94
|
+
if (child.hitTestPoint(point, margin, hitInside)) return true
|
|
95
|
+
}
|
|
96
|
+
return false
|
|
90
97
|
}
|
|
91
98
|
|
|
92
99
|
override hitTestLineSegment(
|
|
@@ -95,42 +102,71 @@ export class Group2d extends Geometry2d {
|
|
|
95
102
|
zoom: number,
|
|
96
103
|
filters = Geometry2dFilters.EXCLUDE_LABELS
|
|
97
104
|
): boolean {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
105
|
+
for (const child of this.children) {
|
|
106
|
+
if (child.isExcludedByFilter(filters)) continue
|
|
107
|
+
if (child.hitTestLineSegment(A, B, zoom)) return true
|
|
108
|
+
}
|
|
109
|
+
return false
|
|
101
110
|
}
|
|
102
111
|
|
|
103
112
|
override intersectLineSegment(A: VecLike, B: VecLike, filters?: Geometry2dFilters) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
113
|
+
const result: VecLike[] = []
|
|
114
|
+
for (const child of this.children) {
|
|
115
|
+
if (child.isExcludedByFilter(filters)) continue
|
|
116
|
+
const hits = child.intersectLineSegment(A, B, filters)
|
|
117
|
+
for (let i = 0, n = hits.length; i < n; i++) {
|
|
118
|
+
result.push(hits[i])
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return result
|
|
108
122
|
}
|
|
109
123
|
|
|
110
124
|
override intersectCircle(center: VecLike, radius: number, filters?: Geometry2dFilters) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
125
|
+
const result: VecLike[] = []
|
|
126
|
+
for (const child of this.children) {
|
|
127
|
+
if (child.isExcludedByFilter(filters)) continue
|
|
128
|
+
const hits = child.intersectCircle(center, radius, filters)
|
|
129
|
+
for (let i = 0, n = hits.length; i < n; i++) {
|
|
130
|
+
result.push(hits[i])
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return result
|
|
115
134
|
}
|
|
116
135
|
|
|
117
136
|
override getBoundsVertices(): Vec[] {
|
|
118
137
|
if (this.excludeFromShapeBounds) return []
|
|
119
|
-
|
|
138
|
+
const vertices: Vec[] = []
|
|
139
|
+
for (const child of this.children) {
|
|
140
|
+
const childVertices = child.getBoundsVertices()
|
|
141
|
+
for (let i = 0, n = childVertices.length; i < n; i++) {
|
|
142
|
+
vertices.push(childVertices[i])
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return vertices
|
|
120
146
|
}
|
|
121
147
|
|
|
122
148
|
override intersectPolygon(polygon: VecLike[], filters?: Geometry2dFilters) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
149
|
+
const result: VecLike[] = []
|
|
150
|
+
for (const child of this.children) {
|
|
151
|
+
if (child.isExcludedByFilter(filters)) continue
|
|
152
|
+
const hits = child.intersectPolygon(polygon, filters)
|
|
153
|
+
for (let i = 0, n = hits.length; i < n; i++) {
|
|
154
|
+
result.push(hits[i])
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return result
|
|
127
158
|
}
|
|
128
159
|
|
|
129
160
|
override intersectPolyline(polyline: VecLike[], filters?: Geometry2dFilters) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
161
|
+
const result: VecLike[] = []
|
|
162
|
+
for (const child of this.children) {
|
|
163
|
+
if (child.isExcludedByFilter(filters)) continue
|
|
164
|
+
const hits = child.intersectPolyline(polyline, filters)
|
|
165
|
+
for (let i = 0, n = hits.length; i < n; i++) {
|
|
166
|
+
result.push(hits[i])
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return result
|
|
134
170
|
}
|
|
135
171
|
|
|
136
172
|
override interpolateAlongEdge(t: number, filters?: Geometry2dFilters): Vec {
|