@yuzhouu/canvas-kit 0.1.2
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/README.md +145 -0
- package/_vendor/canvas-core/bindings/BindingUtil.ts +92 -0
- package/_vendor/canvas-core/bindings/BindingUtilRegistry.ts +22 -0
- package/_vendor/canvas-core/bindings/arrow/arrowBindingHelpers.ts +52 -0
- package/_vendor/canvas-core/contextMenu.ts +85 -0
- package/_vendor/canvas-core/editor/Editor.ts +2614 -0
- package/_vendor/canvas-core/editor/HistoryManager.ts +83 -0
- package/_vendor/canvas-core/editor/StateNode.ts +162 -0
- package/_vendor/canvas-core/editor/camera.ts +6 -0
- package/_vendor/canvas-core/editor/clipboard.ts +478 -0
- package/_vendor/canvas-core/editor/commands.ts +833 -0
- package/_vendor/canvas-core/editor/edgeScroll.ts +37 -0
- package/_vendor/canvas-core/editor/editorComputedHelpers.ts +257 -0
- package/_vendor/canvas-core/editor/editorSelectionTransforms.ts +116 -0
- package/_vendor/canvas-core/editor/events.ts +93 -0
- package/_vendor/canvas-core/editor/index.ts +12 -0
- package/_vendor/canvas-core/editor/interactions.ts +101 -0
- package/_vendor/canvas-core/editor/internal.ts +22 -0
- package/_vendor/canvas-core/editor/managers/BindingManager.ts +262 -0
- package/_vendor/canvas-core/editor/managers/CameraManager.ts +147 -0
- package/_vendor/canvas-core/editor/managers/ClipboardManager.ts +32 -0
- package/_vendor/canvas-core/editor/managers/DocumentSnapshotManager.ts +256 -0
- package/_vendor/canvas-core/editor/managers/InputsManager.ts +319 -0
- package/_vendor/canvas-core/editor/managers/InteractionTransientManager.ts +218 -0
- package/_vendor/canvas-core/editor/managers/QueryManager.ts +837 -0
- package/_vendor/canvas-core/editor/managers/RenderWindowManager.ts +347 -0
- package/_vendor/canvas-core/editor/managers/SelectionLayoutManager.ts +196 -0
- package/_vendor/canvas-core/editor/managers/SelectionManager.ts +98 -0
- package/_vendor/canvas-core/editor/managers/SelectionOverlayManager.ts +308 -0
- package/_vendor/canvas-core/editor/managers/ShapeEditingManager.ts +226 -0
- package/_vendor/canvas-core/editor/managers/ShapeGeometryManager.ts +162 -0
- package/_vendor/canvas-core/editor/managers/ShapeHierarchyManager.ts +797 -0
- package/_vendor/canvas-core/editor/managers/SideEffectManager.ts +83 -0
- package/_vendor/canvas-core/editor/managers/SnapManager.ts +433 -0
- package/_vendor/canvas-core/editor/managers/SnapSnapshotBuilder.ts +430 -0
- package/_vendor/canvas-core/editor/managers/SpatialIndexManager.ts +354 -0
- package/_vendor/canvas-core/editor/managers/ToolManager.ts +81 -0
- package/_vendor/canvas-core/editor/managers/queryState.ts +583 -0
- package/_vendor/canvas-core/editor/managers/selectionGeometry.ts +287 -0
- package/_vendor/canvas-core/editor/managers/shapeOrder.ts +350 -0
- package/_vendor/canvas-core/editor/managers/shapeReparenting.ts +160 -0
- package/_vendor/canvas-core/editor/managers/snapCalculations.ts +412 -0
- package/_vendor/canvas-core/editor/managers/snapGeometry.ts +202 -0
- package/_vendor/canvas-core/editor/managers/snapIndicators.ts +403 -0
- package/_vendor/canvas-core/editor/managers/snapTypes.ts +122 -0
- package/_vendor/canvas-core/editor/queries/shapeTransforms.ts +171 -0
- package/_vendor/canvas-core/editor/renderWindow.ts +439 -0
- package/_vendor/canvas-core/editor/resizeGeometry.ts +654 -0
- package/_vendor/canvas-core/editor/selection.ts +489 -0
- package/_vendor/canvas-core/editor/selectionHandleInteractions.ts +43 -0
- package/_vendor/canvas-core/editor/selectionOverlay.ts +567 -0
- package/_vendor/canvas-core/exports/integrity.ts +174 -0
- package/_vendor/canvas-core/exports/svg.ts +494 -0
- package/_vendor/canvas-core/geometry/Box.ts +80 -0
- package/_vendor/canvas-core/geometry/Ellipse2d.ts +67 -0
- package/_vendor/canvas-core/geometry/Geometry2d.ts +52 -0
- package/_vendor/canvas-core/geometry/Mat.ts +92 -0
- package/_vendor/canvas-core/geometry/Polyline2d.ts +63 -0
- package/_vendor/canvas-core/geometry/Rectangle2d.ts +64 -0
- package/_vendor/canvas-core/geometry/Vec.ts +123 -0
- package/_vendor/canvas-core/geometry/index.ts +13 -0
- package/_vendor/canvas-core/geometry/segments.ts +65 -0
- package/_vendor/canvas-core/index.ts +391 -0
- package/_vendor/canvas-core/plugins/index.ts +5 -0
- package/_vendor/canvas-core/plugins/types.ts +53 -0
- package/_vendor/canvas-core/reactivity.ts +16 -0
- package/_vendor/canvas-core/schema/records.ts +221 -0
- package/_vendor/canvas-core/schema/snapshots.ts +527 -0
- package/_vendor/canvas-core/shapes/ShapeUtil.ts +516 -0
- package/_vendor/canvas-core/shapes/ShapeUtilRegistry.ts +26 -0
- package/_vendor/canvas-core/shapes/capabilities.ts +67 -0
- package/_vendor/canvas-core/shapes/types.ts +20 -0
- package/_vendor/canvas-core/toolbar.ts +148 -0
- package/_vendor/canvas-core/tools/hand/HandTool.ts +75 -0
- package/_vendor/canvas-core/tools/index.ts +2 -0
- package/_vendor/canvas-core/tools/select/SelectTool.ts +33 -0
- package/_vendor/canvas-core/tools/select/selectContainment.ts +104 -0
- package/_vendor/canvas-core/tools/select/selectToolHelpers.ts +801 -0
- package/_vendor/canvas-core/tools/select/states/BrushingState.ts +145 -0
- package/_vendor/canvas-core/tools/select/states/DraggingSelectionHandleInteractionState.ts +116 -0
- package/_vendor/canvas-core/tools/select/states/IdleState.ts +159 -0
- package/_vendor/canvas-core/tools/select/states/PointingCanvasState.ts +41 -0
- package/_vendor/canvas-core/tools/select/states/PointingResizeHandleState.ts +78 -0
- package/_vendor/canvas-core/tools/select/states/PointingRotateHandleState.ts +64 -0
- package/_vendor/canvas-core/tools/select/states/PointingSelectionHandleInteractionState.ts +34 -0
- package/_vendor/canvas-core/tools/select/states/PointingShapeState.ts +140 -0
- package/_vendor/canvas-core/tools/select/states/ResizingState.ts +171 -0
- package/_vendor/canvas-core/tools/select/states/RotatingState.ts +124 -0
- package/_vendor/canvas-core/tools/select/states/SelectStateNode.ts +128 -0
- package/_vendor/canvas-core/tools/select/states/TranslatingState.ts +139 -0
- package/_vendor/canvas-core/tools/select/states/index.ts +11 -0
- package/_vendor/canvas-plugin-api/feature.ts +204 -0
- package/_vendor/canvas-plugin-api/index.ts +142 -0
- package/_vendor/canvas-product-react/api/apiRegistry.ts +35 -0
- package/_vendor/canvas-product-react/api/canvasProductApi.ts +422 -0
- package/_vendor/canvas-product-react/api/index.ts +31 -0
- package/_vendor/canvas-product-react/capabilities/clipboard/clipboardService.ts +36 -0
- package/_vendor/canvas-product-react/capabilities/clipboard/systemClipboard.ts +245 -0
- package/_vendor/canvas-product-react/capabilities/context-menu/systemContextMenu.ts +396 -0
- package/_vendor/canvas-product-react/capabilities/context-menu/useContextMenuSurface.ts +59 -0
- package/_vendor/canvas-product-react/capabilities/export/useSvgExport.ts +156 -0
- package/_vendor/canvas-product-react/capabilities/history/useHistoryControls.ts +23 -0
- package/_vendor/canvas-product-react/capabilities/pages/usePageControls.ts +41 -0
- package/_vendor/canvas-product-react/capabilities/toolbar/systemToolbar.ts +490 -0
- package/_vendor/canvas-product-react/capabilities/toolbar/useToolbarSurfaces.ts +92 -0
- package/_vendor/canvas-product-react/capabilities/zoom/useZoomControls.ts +27 -0
- package/_vendor/canvas-product-react/index.ts +84 -0
- package/_vendor/canvas-product-react/persistence/index.ts +18 -0
- package/_vendor/canvas-product-react/persistence/localSnapshotPersistence.ts +294 -0
- package/_vendor/canvas-product-react/runtime/CanvasProductRoot.tsx +250 -0
- package/_vendor/canvas-product-react/runtime/productDefinition.ts +72 -0
- package/_vendor/canvas-product-react/runtime/productServices.ts +96 -0
- package/_vendor/canvas-react/components/CanvasView.tsx +796 -0
- package/_vendor/canvas-react/components/OverlayLayer.tsx +879 -0
- package/_vendor/canvas-react/components/PageSpace.tsx +34 -0
- package/_vendor/canvas-react/components/ShapeLayer.tsx +428 -0
- package/_vendor/canvas-react/components/index.ts +4 -0
- package/_vendor/canvas-react/hooks/useEditor.ts +11 -0
- package/_vendor/canvas-react/hooks/useValue.ts +14 -0
- package/_vendor/canvas-react/host/CanvasRendererRegistryContext.tsx +14 -0
- package/_vendor/canvas-react/host/contextMenuRegistry.ts +61 -0
- package/_vendor/canvas-react/host/domEventGuards.ts +61 -0
- package/_vendor/canvas-react/host/index.ts +38 -0
- package/_vendor/canvas-react/host/pluginHost.ts +635 -0
- package/_vendor/canvas-react/host/rendererRegistry.tsx +58 -0
- package/_vendor/canvas-react/host/toolbarRegistry.ts +100 -0
- package/_vendor/canvas-react/index.ts +3 -0
- package/_vendor/plugin-arrow/ArrowBindingUtil.ts +239 -0
- package/_vendor/plugin-arrow/ArrowShapeUtil.ts +311 -0
- package/_vendor/plugin-arrow/ArrowTool.ts +208 -0
- package/_vendor/plugin-arrow/arrowGeometry.ts +441 -0
- package/_vendor/plugin-arrow/arrowTerminalBindingResolver.ts +253 -0
- package/_vendor/plugin-arrow/arrowTerminalCommands.ts +230 -0
- package/_vendor/plugin-arrow/canvas.tsx +92 -0
- package/_vendor/plugin-arrow/core.ts +409 -0
- package/_vendor/plugin-arrow/feature.ts +20 -0
- package/_vendor/plugin-arrow/index.ts +28 -0
- package/_vendor/plugin-arrow/selectionHandleInteractions.ts +154 -0
- package/_vendor/plugin-arrow/types.ts +63 -0
- package/_vendor/plugin-draw/DrawShapeRenderer.tsx +60 -0
- package/_vendor/plugin-draw/DrawShapeUtil.ts +372 -0
- package/_vendor/plugin-draw/DrawTool.ts +444 -0
- package/_vendor/plugin-draw/canvas.tsx +24 -0
- package/_vendor/plugin-draw/core.ts +515 -0
- package/_vendor/plugin-draw/drawGeometry.ts +491 -0
- package/_vendor/plugin-draw/drawHitTest.ts +271 -0
- package/_vendor/plugin-draw/drawInterpolation.ts +250 -0
- package/_vendor/plugin-draw/drawPath.ts +550 -0
- package/_vendor/plugin-draw/drawSegments.ts +106 -0
- package/_vendor/plugin-draw/drawSelectionTransform.ts +67 -0
- package/_vendor/plugin-draw/drawShapeGeometry.ts +307 -0
- package/_vendor/plugin-draw/drawStrokeGeometry.ts +454 -0
- package/_vendor/plugin-draw/feature.ts +20 -0
- package/_vendor/plugin-draw/index.ts +31 -0
- package/_vendor/plugin-draw/types.ts +36 -0
- package/_vendor/plugin-eraser/EraserTool.ts +297 -0
- package/_vendor/plugin-eraser/canvas.tsx +616 -0
- package/_vendor/plugin-eraser/core.ts +49 -0
- package/_vendor/plugin-eraser/feature.ts +20 -0
- package/_vendor/plugin-eraser/index.ts +4 -0
- package/_vendor/plugin-frame/FrameShapeUtil.ts +173 -0
- package/_vendor/plugin-frame/FrameTool.ts +225 -0
- package/_vendor/plugin-frame/canvas.tsx +75 -0
- package/_vendor/plugin-frame/core.ts +534 -0
- package/_vendor/plugin-frame/feature.ts +20 -0
- package/_vendor/plugin-frame/index.ts +6 -0
- package/_vendor/plugin-geo/GeoShapeUtil.ts +463 -0
- package/_vendor/plugin-geo/GeoTools.ts +247 -0
- package/_vendor/plugin-geo/canvas.tsx +90 -0
- package/_vendor/plugin-geo/core.ts +495 -0
- package/_vendor/plugin-geo/feature.ts +20 -0
- package/_vendor/plugin-geo/index.ts +7 -0
- package/_vendor/plugin-geo/types.ts +27 -0
- package/_vendor/plugin-group/GroupShapeUtil.ts +59 -0
- package/_vendor/plugin-group/canvas.tsx +59 -0
- package/_vendor/plugin-group/core.ts +40 -0
- package/_vendor/plugin-group/feature.ts +20 -0
- package/_vendor/plugin-group/index.ts +5 -0
- package/_vendor/plugin-image/ImageShapeUtil.ts +95 -0
- package/_vendor/plugin-image/canvas.tsx +212 -0
- package/_vendor/plugin-image/core.ts +542 -0
- package/_vendor/plugin-image/crop.ts +770 -0
- package/_vendor/plugin-image/cropInteractions.ts +350 -0
- package/_vendor/plugin-image/cropSession.ts +38 -0
- package/_vendor/plugin-image/feature.ts +20 -0
- package/_vendor/plugin-image/index.ts +29 -0
- package/_vendor/plugin-image/types.ts +55 -0
- package/_vendor/plugin-image-product-react/ImageImportController.tsx +143 -0
- package/_vendor/plugin-image-product-react/imageAssetService.ts +52 -0
- package/_vendor/plugin-image-product-react/imageBlobStore.ts +315 -0
- package/_vendor/plugin-image-product-react/imageHostActions.ts +438 -0
- package/_vendor/plugin-image-product-react/imageProductApi.ts +88 -0
- package/_vendor/plugin-image-product-react/imageToolbarHostBridge.ts +48 -0
- package/_vendor/plugin-image-product-react/imageToolbarRuntime.ts +21 -0
- package/_vendor/plugin-image-product-react/index.ts +60 -0
- package/_vendor/plugin-image-product-react/snapshotGuards.ts +33 -0
- package/_vendor/plugin-image-product-react/svgImageAssetInliner.ts +54 -0
- package/_vendor/plugin-image-product-react/useImageImport.ts +64 -0
- package/_vendor/plugin-laser/LaserTool.ts +154 -0
- package/_vendor/plugin-laser/canvas.tsx +645 -0
- package/_vendor/plugin-laser/core.ts +49 -0
- package/_vendor/plugin-laser/feature.ts +20 -0
- package/_vendor/plugin-laser/index.ts +4 -0
- package/_vendor/plugin-text/ArrowLabelBindingUtil.ts +336 -0
- package/_vendor/plugin-text/GeoLabelBindingUtil.ts +391 -0
- package/_vendor/plugin-text/TextShapeSvgExporter.ts +101 -0
- package/_vendor/plugin-text/TextShapeUtil.ts +284 -0
- package/_vendor/plugin-text/TextTool.ts +228 -0
- package/_vendor/plugin-text/canvas.tsx +115 -0
- package/_vendor/plugin-text/core.ts +422 -0
- package/_vendor/plugin-text/feature.ts +20 -0
- package/_vendor/plugin-text/host/RichTextEditingBox.tsx +144 -0
- package/_vendor/plugin-text/host/RichTextToolbar.tsx +266 -0
- package/_vendor/plugin-text/host/TiptapTextEditor.tsx +191 -0
- package/_vendor/plugin-text/host/richTextRendering.tsx +49 -0
- package/_vendor/plugin-text/host/textDomSelection.ts +93 -0
- package/_vendor/plugin-text/host/textEditingBoxStyle.ts +36 -0
- package/_vendor/plugin-text/host/textEntryFocus.ts +307 -0
- package/_vendor/plugin-text/host/textFontLoader.ts +149 -0
- package/_vendor/plugin-text/host/textMeasurement.ts +258 -0
- package/_vendor/plugin-text/host/textMeasurementSync.ts +77 -0
- package/_vendor/plugin-text/host/textRangeSelection.ts +134 -0
- package/_vendor/plugin-text/host/textShapeRendererRuntime.tsx +89 -0
- package/_vendor/plugin-text/host/textShapeSync.ts +173 -0
- package/_vendor/plugin-text/host/tiptapTextEditorController.ts +148 -0
- package/_vendor/plugin-text/index.ts +18 -0
- package/_vendor/plugin-text/richTextUtils.ts +259 -0
- package/_vendor/plugin-text/textInteractions.ts +366 -0
- package/_vendor/plugin-text/textLabelHelpers.ts +235 -0
- package/_vendor/plugin-text/textShapeHelpers.ts +123 -0
- package/_vendor/plugin-text/textStyle.ts +96 -0
- package/_vendor/plugin-text/textTypes.ts +48 -0
- package/_vendor/signals/atom.ts +74 -0
- package/_vendor/signals/computed.ts +132 -0
- package/_vendor/signals/core.ts +130 -0
- package/_vendor/signals/effect.ts +117 -0
- package/_vendor/signals/index.ts +9 -0
- package/_vendor/signals/types.ts +17 -0
- package/_vendor/store/Store.ts +171 -0
- package/_vendor/store/diff.ts +229 -0
- package/_vendor/store/history.ts +177 -0
- package/_vendor/store/index.ts +32 -0
- package/_vendor/store/types.ts +37 -0
- package/api/canvasKitApi.d.ts +29 -0
- package/index.css +3 -0
- package/index.d.ts +16 -0
- package/index.mjs +1 -0
- package/internal-modules.d.ts +187 -0
- package/package.json +48 -0
- package/product/Shell.d.ts +19 -0
- package/product/chromeContext.d.ts +70 -0
- package/product/createCanvasKitEditor.d.ts +6 -0
- package/product/index.d.ts +7 -0
- package/product/persistence.d.ts +3 -0
- package/product/product.d.ts +22 -0
- package/product/useCanvasClipboardShortcuts.d.ts +6 -0
- package/product-iyBbEPIs.mjs +4 -0
- package/product.mjs +1 -0
- package/standard/extensions.d.ts +1 -0
- package/standard/index.d.ts +3 -0
- package/standard/standardApi.d.ts +91 -0
- package/standard-BmrxwqpJ.mjs +44 -0
- package/standard.mjs +1 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Vec } from "./Vec";
|
|
2
|
+
|
|
3
|
+
export class Box {
|
|
4
|
+
constructor(
|
|
5
|
+
public x: number,
|
|
6
|
+
public y: number,
|
|
7
|
+
public w: number,
|
|
8
|
+
public h: number,
|
|
9
|
+
) {}
|
|
10
|
+
|
|
11
|
+
get minX(): number {
|
|
12
|
+
return this.x;
|
|
13
|
+
}
|
|
14
|
+
get minY(): number {
|
|
15
|
+
return this.y;
|
|
16
|
+
}
|
|
17
|
+
get maxX(): number {
|
|
18
|
+
return this.x + this.w;
|
|
19
|
+
}
|
|
20
|
+
get maxY(): number {
|
|
21
|
+
return this.y + this.h;
|
|
22
|
+
}
|
|
23
|
+
get center(): Vec {
|
|
24
|
+
return new Vec(this.x + this.w / 2, this.y + this.h / 2);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
containsPoint(p: Vec): boolean {
|
|
28
|
+
return (
|
|
29
|
+
p.x >= this.minX &&
|
|
30
|
+
p.x <= this.maxX &&
|
|
31
|
+
p.y >= this.minY &&
|
|
32
|
+
p.y <= this.maxY
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
containsBox(other: Box): boolean {
|
|
37
|
+
return (
|
|
38
|
+
other.minX >= this.minX &&
|
|
39
|
+
other.maxX <= this.maxX &&
|
|
40
|
+
other.minY >= this.minY &&
|
|
41
|
+
other.maxY <= this.maxY
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
intersects(other: Box): boolean {
|
|
46
|
+
return (
|
|
47
|
+
this.minX < other.maxX &&
|
|
48
|
+
this.maxX > other.minX &&
|
|
49
|
+
this.minY < other.maxY &&
|
|
50
|
+
this.maxY > other.minY
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
expand(amount: number): Box {
|
|
55
|
+
return new Box(
|
|
56
|
+
this.x - amount,
|
|
57
|
+
this.y - amount,
|
|
58
|
+
this.w + amount * 2,
|
|
59
|
+
this.h + amount * 2,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
clone(): Box {
|
|
64
|
+
return new Box(this.x, this.y, this.w, this.h);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static FromPoints(points: Vec[]): Box {
|
|
68
|
+
let minX = Infinity;
|
|
69
|
+
let minY = Infinity;
|
|
70
|
+
let maxX = -Infinity;
|
|
71
|
+
let maxY = -Infinity;
|
|
72
|
+
for (const p of points) {
|
|
73
|
+
minX = Math.min(minX, p.x);
|
|
74
|
+
minY = Math.min(minY, p.y);
|
|
75
|
+
maxX = Math.max(maxX, p.x);
|
|
76
|
+
maxY = Math.max(maxY, p.y);
|
|
77
|
+
}
|
|
78
|
+
return new Box(minX, minY, maxX - minX, maxY - minY);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Geometry2d } from "./Geometry2d";
|
|
2
|
+
import { Vec } from "./Vec";
|
|
3
|
+
import { Box } from "./Box";
|
|
4
|
+
|
|
5
|
+
export class Ellipse2d extends Geometry2d {
|
|
6
|
+
readonly width: number;
|
|
7
|
+
readonly height: number;
|
|
8
|
+
|
|
9
|
+
constructor(opts: { width: number; height: number }) {
|
|
10
|
+
super();
|
|
11
|
+
this.width = opts.width;
|
|
12
|
+
this.height = opts.height;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
get bounds(): Box {
|
|
16
|
+
return new Box(0, 0, this.width, this.height);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get isClosed(): boolean {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get vertices(): Vec[] {
|
|
24
|
+
const cx = this.width / 2;
|
|
25
|
+
const cy = this.height / 2;
|
|
26
|
+
const rx = this.width / 2;
|
|
27
|
+
const ry = this.height / 2;
|
|
28
|
+
const points: Vec[] = [];
|
|
29
|
+
const segments = 32;
|
|
30
|
+
for (let i = 0; i < segments; i++) {
|
|
31
|
+
const angle = (i / segments) * Math.PI * 2;
|
|
32
|
+
points.push(
|
|
33
|
+
new Vec(cx + rx * Math.cos(angle), cy + ry * Math.sin(angle)),
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
return points;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
nearestPoint(point: Vec): Vec {
|
|
40
|
+
const cx = this.width / 2;
|
|
41
|
+
const cy = this.height / 2;
|
|
42
|
+
const rx = this.width / 2;
|
|
43
|
+
const ry = this.height / 2;
|
|
44
|
+
|
|
45
|
+
// Normalize point relative to center
|
|
46
|
+
const dx = point.x - cx;
|
|
47
|
+
const dy = point.y - cy;
|
|
48
|
+
|
|
49
|
+
if (dx === 0 && dy === 0) {
|
|
50
|
+
return new Vec(cx + rx, cy);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Scale to unit circle space
|
|
54
|
+
const angle = Math.atan2(dy / ry, dx / rx);
|
|
55
|
+
return new Vec(cx + rx * Math.cos(angle), cy + ry * Math.sin(angle));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
hitTestPoint(point: Vec, margin = 0): boolean {
|
|
59
|
+
const cx = this.width / 2;
|
|
60
|
+
const cy = this.height / 2;
|
|
61
|
+
const rx = this.width / 2 + margin;
|
|
62
|
+
const ry = this.height / 2 + margin;
|
|
63
|
+
const dx = point.x - cx;
|
|
64
|
+
const dy = point.y - cy;
|
|
65
|
+
return (dx * dx) / (rx * rx) + (dy * dy) / (ry * ry) <= 1;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Vec } from "./Vec";
|
|
2
|
+
import { Box } from "./Box";
|
|
3
|
+
|
|
4
|
+
export abstract class Geometry2d {
|
|
5
|
+
abstract get bounds(): Box;
|
|
6
|
+
abstract get isClosed(): boolean;
|
|
7
|
+
abstract get vertices(): Vec[];
|
|
8
|
+
abstract nearestPoint(point: Vec): Vec;
|
|
9
|
+
abstract hitTestPoint(point: Vec, margin?: number): boolean;
|
|
10
|
+
|
|
11
|
+
distanceToPoint(point: Vec): number {
|
|
12
|
+
return point.dist(this.nearestPoint(point));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Find intersection points between a line segment (a→b) and the shape outline.
|
|
17
|
+
* Default implementation uses the polygon formed by `vertices`.
|
|
18
|
+
*/
|
|
19
|
+
intersectLineSegment(a: Vec, b: Vec): Vec[] {
|
|
20
|
+
const verts = this.vertices;
|
|
21
|
+
const results: Vec[] = [];
|
|
22
|
+
const n = verts.length;
|
|
23
|
+
if (n < 2) return results;
|
|
24
|
+
|
|
25
|
+
for (let i = 0; i < n; i++) {
|
|
26
|
+
const c = verts[i];
|
|
27
|
+
const d = verts[(i + 1) % n];
|
|
28
|
+
const pt = segmentIntersection(a, b, c, d);
|
|
29
|
+
if (pt) results.push(pt);
|
|
30
|
+
}
|
|
31
|
+
return results;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Returns the intersection point of segments AB and CD, or null if they don't intersect. */
|
|
36
|
+
function segmentIntersection(a: Vec, b: Vec, c: Vec, d: Vec): Vec | null {
|
|
37
|
+
const dx1 = b.x - a.x;
|
|
38
|
+
const dy1 = b.y - a.y;
|
|
39
|
+
const dx2 = d.x - c.x;
|
|
40
|
+
const dy2 = d.y - c.y;
|
|
41
|
+
|
|
42
|
+
const denom = dx1 * dy2 - dy1 * dx2;
|
|
43
|
+
if (Math.abs(denom) < 1e-10) return null; // parallel
|
|
44
|
+
|
|
45
|
+
const t = ((c.x - a.x) * dy2 - (c.y - a.y) * dx2) / denom;
|
|
46
|
+
const u = ((c.x - a.x) * dy1 - (c.y - a.y) * dx1) / denom;
|
|
47
|
+
|
|
48
|
+
if (t >= 0 && t <= 1 && u >= 0 && u <= 1) {
|
|
49
|
+
return new Vec(a.x + t * dx1, a.y + t * dy1);
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Vec } from "./Vec";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 2D affine transform matrix:
|
|
5
|
+
* [a c e]
|
|
6
|
+
* [b d f]
|
|
7
|
+
* [0 0 1]
|
|
8
|
+
*/
|
|
9
|
+
export class Mat {
|
|
10
|
+
constructor(
|
|
11
|
+
public a: number,
|
|
12
|
+
public b: number,
|
|
13
|
+
public c: number,
|
|
14
|
+
public d: number,
|
|
15
|
+
public e: number,
|
|
16
|
+
public f: number,
|
|
17
|
+
) {}
|
|
18
|
+
|
|
19
|
+
static Identity(): Mat {
|
|
20
|
+
return new Mat(1, 0, 0, 1, 0, 0);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static Translate(x: number, y: number): Mat {
|
|
24
|
+
return new Mat(1, 0, 0, 1, x, y);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static Rotate(angle: number): Mat {
|
|
28
|
+
const cos = Math.cos(angle);
|
|
29
|
+
const sin = Math.sin(angle);
|
|
30
|
+
return new Mat(cos, sin, -sin, cos, 0, 0);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static Scale(sx: number, sy: number): Mat {
|
|
34
|
+
return new Mat(sx, 0, 0, sy, 0, 0);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Compose: this × other */
|
|
38
|
+
compose(other: Mat): Mat {
|
|
39
|
+
return new Mat(
|
|
40
|
+
this.a * other.a + this.c * other.b,
|
|
41
|
+
this.b * other.a + this.d * other.b,
|
|
42
|
+
this.a * other.c + this.c * other.d,
|
|
43
|
+
this.b * other.c + this.d * other.d,
|
|
44
|
+
this.a * other.e + this.c * other.f + this.e,
|
|
45
|
+
this.b * other.e + this.d * other.f + this.f,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
applyToPoint(p: Vec): Vec {
|
|
50
|
+
return new Vec(
|
|
51
|
+
this.a * p.x + this.c * p.y + this.e,
|
|
52
|
+
this.b * p.x + this.d * p.y + this.f,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
invert(): Mat {
|
|
57
|
+
const det = this.a * this.d - this.b * this.c;
|
|
58
|
+
if (det === 0) return Mat.Identity();
|
|
59
|
+
const invDet = 1 / det;
|
|
60
|
+
return new Mat(
|
|
61
|
+
this.d * invDet,
|
|
62
|
+
-this.b * invDet,
|
|
63
|
+
-this.c * invDet,
|
|
64
|
+
this.a * invDet,
|
|
65
|
+
(this.c * this.f - this.d * this.e) * invDet,
|
|
66
|
+
(this.b * this.e - this.a * this.f) * invDet,
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
toCssString(): string {
|
|
71
|
+
return `matrix(${this.a},${this.b},${this.c},${this.d},${this.e},${this.f})`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
toSvgString(): string {
|
|
75
|
+
return `matrix(${this.a} ${this.b} ${this.c} ${this.d} ${this.e} ${this.f})`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Create a transform for a shape: translate(x,y) * rotate(rotation) * scale(scaleX, scaleY) */
|
|
79
|
+
static ForShape(
|
|
80
|
+
x: number,
|
|
81
|
+
y: number,
|
|
82
|
+
rotation: number,
|
|
83
|
+
scaleX = 1,
|
|
84
|
+
scaleY = 1,
|
|
85
|
+
): Mat {
|
|
86
|
+
const translation = Mat.Translate(x, y);
|
|
87
|
+
const rotationMat = rotation === 0 ? Mat.Identity() : Mat.Rotate(rotation);
|
|
88
|
+
const scaleMat =
|
|
89
|
+
scaleX === 1 && scaleY === 1 ? Mat.Identity() : Mat.Scale(scaleX, scaleY);
|
|
90
|
+
return translation.compose(rotationMat).compose(scaleMat);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Geometry2d } from "./Geometry2d";
|
|
2
|
+
import { Vec } from "./Vec";
|
|
3
|
+
import { Box } from "./Box";
|
|
4
|
+
|
|
5
|
+
export class Polyline2d extends Geometry2d {
|
|
6
|
+
readonly points: Vec[];
|
|
7
|
+
|
|
8
|
+
constructor(opts: { points: Vec[] }) {
|
|
9
|
+
super();
|
|
10
|
+
this.points = opts.points;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get bounds(): Box {
|
|
14
|
+
return Box.FromPoints(this.points);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get isClosed(): boolean {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get vertices(): Vec[] {
|
|
22
|
+
return this.points;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
nearestPoint(point: Vec): Vec {
|
|
26
|
+
let nearest = this.points[0];
|
|
27
|
+
let minDist = Infinity;
|
|
28
|
+
|
|
29
|
+
for (let i = 0; i < this.points.length - 1; i++) {
|
|
30
|
+
const a = this.points[i];
|
|
31
|
+
const b = this.points[i + 1];
|
|
32
|
+
const p = nearestPointOnSegment(a, b, point);
|
|
33
|
+
const d = point.dist(p);
|
|
34
|
+
if (d < minDist) {
|
|
35
|
+
minDist = d;
|
|
36
|
+
nearest = p;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return nearest;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
hitTestPoint(point: Vec, margin = 0): boolean {
|
|
44
|
+
for (let i = 0; i < this.points.length - 1; i++) {
|
|
45
|
+
const a = this.points[i];
|
|
46
|
+
const b = this.points[i + 1];
|
|
47
|
+
const p = nearestPointOnSegment(a, b, point);
|
|
48
|
+
if (point.dist(p) <= margin + 4) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function nearestPointOnSegment(a: Vec, b: Vec, p: Vec): Vec {
|
|
57
|
+
const ab = b.sub(a);
|
|
58
|
+
const ap = p.sub(a);
|
|
59
|
+
const abLenSq = ab.x * ab.x + ab.y * ab.y;
|
|
60
|
+
if (abLenSq === 0) return a;
|
|
61
|
+
const t = Math.max(0, Math.min(1, (ap.x * ab.x + ap.y * ab.y) / abLenSq));
|
|
62
|
+
return new Vec(a.x + t * ab.x, a.y + t * ab.y);
|
|
63
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Geometry2d } from "./Geometry2d";
|
|
2
|
+
import { Vec } from "./Vec";
|
|
3
|
+
import { Box } from "./Box";
|
|
4
|
+
|
|
5
|
+
export class Rectangle2d extends Geometry2d {
|
|
6
|
+
readonly width: number;
|
|
7
|
+
readonly height: number;
|
|
8
|
+
|
|
9
|
+
constructor(opts: { width: number; height: number }) {
|
|
10
|
+
super();
|
|
11
|
+
this.width = opts.width;
|
|
12
|
+
this.height = opts.height;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
get bounds(): Box {
|
|
16
|
+
return new Box(0, 0, this.width, this.height);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get isClosed(): boolean {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get vertices(): Vec[] {
|
|
24
|
+
return [
|
|
25
|
+
new Vec(0, 0),
|
|
26
|
+
new Vec(this.width, 0),
|
|
27
|
+
new Vec(this.width, this.height),
|
|
28
|
+
new Vec(0, this.height),
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
nearestPoint(point: Vec): Vec {
|
|
33
|
+
const x = point.x;
|
|
34
|
+
const y = point.y;
|
|
35
|
+
const w = this.width;
|
|
36
|
+
const h = this.height;
|
|
37
|
+
|
|
38
|
+
// If the point is outside, clamp to the nearest edge
|
|
39
|
+
if (x <= 0 || x >= w || y <= 0 || y >= h) {
|
|
40
|
+
return new Vec(Math.max(0, Math.min(w, x)), Math.max(0, Math.min(h, y)));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Point is inside: find the nearest edge
|
|
44
|
+
const distLeft = x;
|
|
45
|
+
const distRight = w - x;
|
|
46
|
+
const distTop = y;
|
|
47
|
+
const distBottom = h - y;
|
|
48
|
+
const min = Math.min(distLeft, distRight, distTop, distBottom);
|
|
49
|
+
|
|
50
|
+
if (min === distLeft) return new Vec(0, y);
|
|
51
|
+
if (min === distRight) return new Vec(w, y);
|
|
52
|
+
if (min === distTop) return new Vec(x, 0);
|
|
53
|
+
return new Vec(x, h);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
hitTestPoint(point: Vec, margin = 0): boolean {
|
|
57
|
+
return (
|
|
58
|
+
point.x >= -margin &&
|
|
59
|
+
point.x <= this.width + margin &&
|
|
60
|
+
point.y >= -margin &&
|
|
61
|
+
point.y <= this.height + margin
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
export class Vec {
|
|
2
|
+
constructor(
|
|
3
|
+
public x: number,
|
|
4
|
+
public y: number,
|
|
5
|
+
) {}
|
|
6
|
+
|
|
7
|
+
add(v: Vec): Vec {
|
|
8
|
+
return new Vec(this.x + v.x, this.y + v.y);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
sub(v: Vec): Vec {
|
|
12
|
+
return new Vec(this.x - v.x, this.y - v.y);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
mul(s: number): Vec {
|
|
16
|
+
return new Vec(this.x * s, this.y * s);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
div(s: number): Vec {
|
|
20
|
+
return new Vec(this.x / s, this.y / s);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
len2(): number {
|
|
24
|
+
return this.x * this.x + this.y * this.y;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
len(): number {
|
|
28
|
+
return Math.sqrt(this.len2());
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
dist2(v: Vec): number {
|
|
32
|
+
const dx = this.x - v.x;
|
|
33
|
+
const dy = this.y - v.y;
|
|
34
|
+
return dx * dx + dy * dy;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
dist(v: Vec): number {
|
|
38
|
+
return Math.sqrt(this.dist2(v));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
rot(angle: number): Vec {
|
|
42
|
+
const c = Math.cos(angle);
|
|
43
|
+
const s = Math.sin(angle);
|
|
44
|
+
return new Vec(this.x * c - this.y * s, this.x * s + this.y * c);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Perpendicular vector (rotated 90° counter-clockwise). */
|
|
48
|
+
per(): Vec {
|
|
49
|
+
return new Vec(-this.y, this.x);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Unit vector (alias for normalize). */
|
|
53
|
+
uni(): Vec {
|
|
54
|
+
return this.normalize();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
normalize(): Vec {
|
|
58
|
+
const l = this.len();
|
|
59
|
+
if (l === 0) return new Vec(0, 0);
|
|
60
|
+
return this.div(l);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
equals(v: Vec): boolean {
|
|
64
|
+
return this.x === v.x && this.y === v.y;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
clone(): Vec {
|
|
68
|
+
return new Vec(this.x, this.y);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
static From(x: number, y: number): Vec {
|
|
72
|
+
return new Vec(x, y);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static Zero(): Vec {
|
|
76
|
+
return new Vec(0, 0);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Midpoint between two vectors. */
|
|
80
|
+
static Med(a: Vec, b: Vec): Vec {
|
|
81
|
+
return new Vec((a.x + b.x) / 2, (a.y + b.y) / 2);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Linear interpolation between two vectors. */
|
|
85
|
+
static Lrp(a: Vec, b: Vec, t: number): Vec {
|
|
86
|
+
return new Vec(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Distance between two vectors. */
|
|
90
|
+
static Dist(a: Vec, b: Vec): number {
|
|
91
|
+
return a.dist(b);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
static Dist2(a: Vec, b: Vec): number {
|
|
95
|
+
return a.dist2(b);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Angle from center to point (atan2). */
|
|
99
|
+
static Angle(center: Vec, point: Vec): number {
|
|
100
|
+
return Math.atan2(point.y - center.y, point.x - center.x);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Move point toward target by distance. */
|
|
104
|
+
static Nudge(from: Vec, toward: Vec, distance: number): Vec {
|
|
105
|
+
const d = toward.sub(from);
|
|
106
|
+
const l = d.len();
|
|
107
|
+
if (l === 0) return from.clone();
|
|
108
|
+
return from.add(d.mul(distance / l));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Rotate point around a center by angle. */
|
|
112
|
+
static RotWith(point: Vec, center: Vec, angle: number): Vec {
|
|
113
|
+
const dx = point.x - center.x;
|
|
114
|
+
const dy = point.y - center.y;
|
|
115
|
+
const c = Math.cos(angle);
|
|
116
|
+
const s = Math.sin(angle);
|
|
117
|
+
return new Vec(center.x + dx * c - dy * s, center.y + dx * s + dy * c);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
static IsNaN(v: Vec): boolean {
|
|
121
|
+
return isNaN(v.x) || isNaN(v.y);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { Vec } from "./Vec";
|
|
2
|
+
export { Box } from "./Box";
|
|
3
|
+
export { Mat } from "./Mat";
|
|
4
|
+
export { Geometry2d } from "./Geometry2d";
|
|
5
|
+
export { Rectangle2d } from "./Rectangle2d";
|
|
6
|
+
export { Ellipse2d } from "./Ellipse2d";
|
|
7
|
+
export { Polyline2d } from "./Polyline2d";
|
|
8
|
+
export {
|
|
9
|
+
distanceBetweenSegments,
|
|
10
|
+
distanceToSegment,
|
|
11
|
+
nearestPointOnSegment,
|
|
12
|
+
segmentsIntersect,
|
|
13
|
+
} from "./segments";
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Vec } from "./Vec";
|
|
2
|
+
|
|
3
|
+
export function nearestPointOnSegment(start: Vec, end: Vec, point: Vec): Vec {
|
|
4
|
+
const segment = end.sub(start);
|
|
5
|
+
const pointOffset = point.sub(start);
|
|
6
|
+
const lengthSquared = segment.x * segment.x + segment.y * segment.y;
|
|
7
|
+
if (lengthSquared === 0) {
|
|
8
|
+
return start;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const t = Math.max(
|
|
12
|
+
0,
|
|
13
|
+
Math.min(
|
|
14
|
+
1,
|
|
15
|
+
(pointOffset.x * segment.x + pointOffset.y * segment.y) / lengthSquared,
|
|
16
|
+
),
|
|
17
|
+
);
|
|
18
|
+
return new Vec(start.x + segment.x * t, start.y + segment.y * t);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function distanceToSegment(
|
|
22
|
+
point: Vec,
|
|
23
|
+
start: Vec,
|
|
24
|
+
end: Vec,
|
|
25
|
+
): number {
|
|
26
|
+
return point.dist(nearestPointOnSegment(start, end, point));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function segmentsIntersect(
|
|
30
|
+
firstStart: Vec,
|
|
31
|
+
firstEnd: Vec,
|
|
32
|
+
secondStart: Vec,
|
|
33
|
+
secondEnd: Vec,
|
|
34
|
+
): boolean {
|
|
35
|
+
const first = firstEnd.sub(firstStart);
|
|
36
|
+
const second = secondEnd.sub(secondStart);
|
|
37
|
+
const denominator = first.x * second.y - first.y * second.x;
|
|
38
|
+
if (Math.abs(denominator) < 1e-8) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const delta = secondStart.sub(firstStart);
|
|
43
|
+
const t = (delta.x * second.y - delta.y * second.x) / denominator;
|
|
44
|
+
const u = (delta.x * first.y - delta.y * first.x) / denominator;
|
|
45
|
+
|
|
46
|
+
return t >= 0 && t <= 1 && u >= 0 && u <= 1;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function distanceBetweenSegments(
|
|
50
|
+
firstStart: Vec,
|
|
51
|
+
firstEnd: Vec,
|
|
52
|
+
secondStart: Vec,
|
|
53
|
+
secondEnd: Vec,
|
|
54
|
+
): number {
|
|
55
|
+
if (segmentsIntersect(firstStart, firstEnd, secondStart, secondEnd)) {
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return Math.min(
|
|
60
|
+
distanceToSegment(firstStart, secondStart, secondEnd),
|
|
61
|
+
distanceToSegment(firstEnd, secondStart, secondEnd),
|
|
62
|
+
distanceToSegment(secondStart, firstStart, firstEnd),
|
|
63
|
+
distanceToSegment(secondEnd, firstStart, firstEnd),
|
|
64
|
+
);
|
|
65
|
+
}
|