UNPKG

@tldraw/editor

Version:

tldraw infinite canvas SDK (editor).

8 lines (7 loc) 6.81 kB
{ "version": 3, "sources": ["../../../../src/lib/primitives/geometry/Polyline2d.ts"], "sourcesContent": ["import { pointInPolygon } from '../utils'\nimport { Vec, VecLike } from '../Vec'\nimport { Edge2d } from './Edge2d'\nimport { Geometry2d, Geometry2dOptions } from './Geometry2d'\n\n/** @public */\nexport class Polyline2d extends Geometry2d {\n\tprivate _points: Vec[]\n\tprivate _segments?: Edge2d[]\n\n\tconstructor(config: Omit<Geometry2dOptions, 'isFilled' | 'isClosed'> & { points: Vec[] }) {\n\t\tsuper({ isClosed: false, isFilled: false, ...config })\n\t\tconst { points } = config\n\t\tthis._points = points\n\n\t\tif (points.length < 2) {\n\t\t\tthrow new Error('Polyline2d: points must be an array of at least 2 points')\n\t\t}\n\t}\n\n\t// eslint-disable-next-line tldraw/no-setter-getter\n\tprotected get segments() {\n\t\tif (!this._segments) {\n\t\t\tthis._segments = []\n\t\t\tconst { vertices } = this\n\t\t\tfor (let i = 0, n = vertices.length - 1; i < n; i++) {\n\t\t\t\tconst start = vertices[i]\n\t\t\t\tconst end = vertices[i + 1]\n\t\t\t\tthis._segments.push(new Edge2d({ start, end }))\n\t\t\t}\n\n\t\t\tif (this.isClosed) {\n\t\t\t\tthis._segments.push(new Edge2d({ start: vertices[vertices.length - 1], end: vertices[0] }))\n\t\t\t}\n\t\t}\n\n\t\treturn this._segments\n\t}\n\n\toverride getLength() {\n\t\treturn this.segments.reduce((acc, segment) => acc + segment.length, 0)\n\t}\n\n\tgetVertices() {\n\t\treturn this._points\n\t}\n\n\tnearestPoint(A: VecLike): Vec {\n\t\t// Inlined: for each segment, Edge2d.nearestPoint(A) + Vec.Dist2(result, A), pick closest.\n\t\t// Inlines the per-segment nearest-point math to avoid N Edge2d.nearestPoint Vec allocations;\n\t\t// only allocates a single Vec at the end for the best result.\n\t\tconst { vertices } = this\n\t\tlet bestX = vertices[0].x\n\t\tlet bestY = vertices[0].y\n\t\tlet bestDist2 = (A.x - bestX) * (A.x - bestX) + (A.y - bestY) * (A.y - bestY)\n\n\t\tconst limit = this.isClosed ? vertices.length : vertices.length - 1\n\t\tfor (let i = 0; i < limit; i++) {\n\t\t\tconst start = vertices[i]\n\t\t\tconst end = vertices[(i + 1) % vertices.length]\n\t\t\tconst dx = end.x - start.x\n\t\t\tconst dy = end.y - start.y\n\t\t\tconst len2 = dx * dx + dy * dy\n\n\t\t\tlet nx: number, ny: number\n\t\t\tif (len2 === 0) {\n\t\t\t\tnx = start.x\n\t\t\t\tny = start.y\n\t\t\t} else {\n\t\t\t\tconst t = ((A.x - start.x) * dx + (A.y - start.y) * dy) / len2\n\t\t\t\tif (t <= 0) {\n\t\t\t\t\tnx = start.x\n\t\t\t\t\tny = start.y\n\t\t\t\t} else if (t >= 1) {\n\t\t\t\t\tnx = end.x\n\t\t\t\t\tny = end.y\n\t\t\t\t} else {\n\t\t\t\t\tnx = start.x + dx * t\n\t\t\t\t\tny = start.y + dy * t\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst ex = A.x - nx\n\t\t\tconst ey = A.y - ny\n\t\t\tconst d2 = ex * ex + ey * ey\n\t\t\tif (d2 < bestDist2) {\n\t\t\t\tbestX = nx\n\t\t\t\tbestY = ny\n\t\t\t\tbestDist2 = d2\n\t\t\t}\n\t\t}\n\n\t\treturn new Vec(bestX, bestY)\n\t}\n\n\toverride hitTestPoint(point: VecLike, margin = 0, hitInside = false): boolean {\n\t\treturn this.distanceToPoint(point, hitInside) <= margin\n\t}\n\n\toverride distanceToPoint(point: VecLike, hitInside = false): number {\n\t\tconst { segments } = this\n\t\tlet minDist = Infinity\n\t\tfor (let i = 0; i < segments.length; i++) {\n\t\t\tconst d = segments[i].distanceToPoint(point)\n\t\t\tif (d < minDist) minDist = d\n\t\t}\n\t\tif (this.isClosed && (this.isFilled || hitInside) && pointInPolygon(point, this.vertices)) {\n\t\t\treturn -minDist\n\t\t}\n\t\treturn minDist\n\t}\n\n\thitTestLineSegment(A: VecLike, B: VecLike, distance = 0): boolean {\n\t\tconst { segments } = this\n\t\tfor (let i = 0, n = segments.length; i < n; i++) {\n\t\t\tif (segments[i].hitTestLineSegment(A, B, distance)) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t\treturn false\n\t}\n\n\tgetSvgPathData(): string {\n\t\tconst { vertices } = this\n\t\tif (vertices.length < 2) return ''\n\t\treturn vertices.reduce((acc, vertex, i) => {\n\t\t\tif (i === 0) return `M ${vertex.x} ${vertex.y}`\n\t\t\treturn `${acc} L ${vertex.x} ${vertex.y}`\n\t\t}, '')\n\t}\n}\n"], "mappings": "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", "names": [] }