@tldraw/editor 3.14.0-canary.36a37ef097fb → 3.14.0-canary.403af9c5d8f2
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 +46 -46
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/primitives/Vec.js +13 -8
- package/dist-cjs/lib/primitives/Vec.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Arc2d.js +41 -21
- package/dist-cjs/lib/primitives/geometry/Arc2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Circle2d.js +11 -11
- package/dist-cjs/lib/primitives/geometry/Circle2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js +13 -16
- package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/CubicSpline2d.js +4 -4
- package/dist-cjs/lib/primitives/geometry/CubicSpline2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Edge2d.js +14 -17
- package/dist-cjs/lib/primitives/geometry/Edge2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Ellipse2d.js +10 -10
- package/dist-cjs/lib/primitives/geometry/Ellipse2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Point2d.js +6 -6
- package/dist-cjs/lib/primitives/geometry/Point2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Polygon2d.js +3 -0
- package/dist-cjs/lib/primitives/geometry/Polygon2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Polyline2d.js +8 -5
- package/dist-cjs/lib/primitives/geometry/Polyline2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Rectangle2d.js +22 -11
- package/dist-cjs/lib/primitives/geometry/Rectangle2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Stadium2d.js +22 -22
- package/dist-cjs/lib/primitives/geometry/Stadium2d.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 +46 -46
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/primitives/Vec.mjs +13 -8
- package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Arc2d.mjs +41 -21
- package/dist-esm/lib/primitives/geometry/Arc2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Circle2d.mjs +11 -11
- package/dist-esm/lib/primitives/geometry/Circle2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs +13 -16
- package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/CubicSpline2d.mjs +4 -4
- package/dist-esm/lib/primitives/geometry/CubicSpline2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Edge2d.mjs +14 -17
- package/dist-esm/lib/primitives/geometry/Edge2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs +11 -11
- package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Point2d.mjs +6 -6
- package/dist-esm/lib/primitives/geometry/Point2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Polygon2d.mjs +3 -0
- package/dist-esm/lib/primitives/geometry/Polygon2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Polyline2d.mjs +8 -5
- package/dist-esm/lib/primitives/geometry/Polyline2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Rectangle2d.mjs +22 -11
- package/dist-esm/lib/primitives/geometry/Rectangle2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Stadium2d.mjs +22 -22
- package/dist-esm/lib/primitives/geometry/Stadium2d.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +7 -7
- package/src/lib/primitives/Vec.test.ts +2 -2
- package/src/lib/primitives/Vec.ts +13 -8
- package/src/lib/primitives/geometry/Arc2d.ts +42 -23
- package/src/lib/primitives/geometry/Circle2d.ts +12 -12
- package/src/lib/primitives/geometry/CubicBezier2d.test.ts +5 -0
- package/src/lib/primitives/geometry/CubicBezier2d.ts +13 -17
- package/src/lib/primitives/geometry/CubicSpline2d.ts +5 -5
- package/src/lib/primitives/geometry/Edge2d.ts +14 -18
- package/src/lib/primitives/geometry/Ellipse2d.ts +12 -13
- package/src/lib/primitives/geometry/Point2d.ts +6 -6
- package/src/lib/primitives/geometry/Polygon2d.ts +4 -0
- package/src/lib/primitives/geometry/Polyline2d.ts +10 -7
- package/src/lib/primitives/geometry/Rectangle2d.ts +24 -11
- package/src/lib/primitives/geometry/Stadium2d.ts +22 -23
- package/src/version.ts +3 -3
|
@@ -2,13 +2,16 @@ import { Vec } from "../Vec.mjs";
|
|
|
2
2
|
import { Edge2d } from "./Edge2d.mjs";
|
|
3
3
|
import { Geometry2d } from "./Geometry2d.mjs";
|
|
4
4
|
class Polyline2d extends Geometry2d {
|
|
5
|
-
|
|
5
|
+
_points;
|
|
6
|
+
_segments;
|
|
6
7
|
constructor(config) {
|
|
7
8
|
super({ isClosed: false, isFilled: false, ...config });
|
|
8
9
|
const { points } = config;
|
|
9
|
-
this.
|
|
10
|
+
this._points = points;
|
|
11
|
+
if (points.length < 2) {
|
|
12
|
+
throw new Error("Polyline2d: points must be an array of at least 2 points");
|
|
13
|
+
}
|
|
10
14
|
}
|
|
11
|
-
_segments;
|
|
12
15
|
// eslint-disable-next-line no-restricted-syntax
|
|
13
16
|
get segments() {
|
|
14
17
|
if (!this._segments) {
|
|
@@ -29,11 +32,11 @@ class Polyline2d extends Geometry2d {
|
|
|
29
32
|
return this.segments.reduce((acc, segment) => acc + segment.length, 0);
|
|
30
33
|
}
|
|
31
34
|
getVertices() {
|
|
32
|
-
return this.
|
|
35
|
+
return this._points;
|
|
33
36
|
}
|
|
34
37
|
nearestPoint(A) {
|
|
35
38
|
const { segments } = this;
|
|
36
|
-
let nearest = this.
|
|
39
|
+
let nearest = this._points[0];
|
|
37
40
|
let dist = Infinity;
|
|
38
41
|
let p;
|
|
39
42
|
let d;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/primitives/geometry/Polyline2d.ts"],
|
|
4
|
-
"sourcesContent": ["import { Vec, VecLike } from '../Vec'\nimport { Edge2d } from './Edge2d'\nimport { Geometry2d, Geometry2dOptions } from './Geometry2d'\n\n/** @public */\nexport class Polyline2d extends Geometry2d {\n\
|
|
5
|
-
"mappings": "AAAA,SAAS,WAAoB;AAC7B,SAAS,cAAc;AACvB,SAAS,kBAAqC;AAGvC,MAAM,mBAAmB,WAAW;AAAA,
|
|
4
|
+
"sourcesContent": ["import { 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 no-restricted-syntax\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\tconst { segments } = this\n\t\tlet nearest = this._points[0]\n\t\tlet dist = Infinity\n\t\tlet p: Vec // current point on segment\n\t\tlet d: number // distance from A to p\n\t\tfor (let i = 0; i < segments.length; i++) {\n\t\t\tp = segments[i].nearestPoint(A)\n\t\t\td = Vec.Dist2(p, A)\n\t\t\tif (d < dist) {\n\t\t\t\tnearest = p\n\t\t\t\tdist = d\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\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"],
|
|
5
|
+
"mappings": "AAAA,SAAS,WAAoB;AAC7B,SAAS,cAAc;AACvB,SAAS,kBAAqC;AAGvC,MAAM,mBAAmB,WAAW;AAAA,EAClC;AAAA,EACA;AAAA,EAER,YAAY,QAA8E;AACzF,UAAM,EAAE,UAAU,OAAO,UAAU,OAAO,GAAG,OAAO,CAAC;AACrD,UAAM,EAAE,OAAO,IAAI;AACnB,SAAK,UAAU;AAEf,QAAI,OAAO,SAAS,GAAG;AACtB,YAAM,IAAI,MAAM,0DAA0D;AAAA,IAC3E;AAAA,EACD;AAAA;AAAA,EAGA,IAAc,WAAW;AACxB,QAAI,CAAC,KAAK,WAAW;AACpB,WAAK,YAAY,CAAC;AAClB,YAAM,EAAE,SAAS,IAAI;AACrB,eAAS,IAAI,GAAG,IAAI,SAAS,SAAS,GAAG,IAAI,GAAG,KAAK;AACpD,cAAM,QAAQ,SAAS,CAAC;AACxB,cAAM,MAAM,SAAS,IAAI,CAAC;AAC1B,aAAK,UAAU,KAAK,IAAI,OAAO,EAAE,OAAO,IAAI,CAAC,CAAC;AAAA,MAC/C;AAEA,UAAI,KAAK,UAAU;AAClB,aAAK,UAAU,KAAK,IAAI,OAAO,EAAE,OAAO,SAAS,SAAS,SAAS,CAAC,GAAG,KAAK,SAAS,CAAC,EAAE,CAAC,CAAC;AAAA,MAC3F;AAAA,IACD;AAEA,WAAO,KAAK;AAAA,EACb;AAAA,EAES,YAAY;AACpB,WAAO,KAAK,SAAS,OAAO,CAAC,KAAK,YAAY,MAAM,QAAQ,QAAQ,CAAC;AAAA,EACtE;AAAA,EAEA,cAAc;AACb,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,aAAa,GAAiB;AAC7B,UAAM,EAAE,SAAS,IAAI;AACrB,QAAI,UAAU,KAAK,QAAQ,CAAC;AAC5B,QAAI,OAAO;AACX,QAAI;AACJ,QAAI;AACJ,aAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACzC,UAAI,SAAS,CAAC,EAAE,aAAa,CAAC;AAC9B,UAAI,IAAI,MAAM,GAAG,CAAC;AAClB,UAAI,IAAI,MAAM;AACb,kBAAU;AACV,eAAO;AAAA,MACR;AAAA,IACD;AACA,QAAI,CAAC,QAAS,OAAM,MAAM,yBAAyB;AACnD,WAAO;AAAA,EACR;AAAA,EAEA,mBAAmB,GAAY,GAAY,WAAW,GAAY;AACjE,UAAM,EAAE,SAAS,IAAI;AACrB,aAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,IAAI,GAAG,KAAK;AAChD,UAAI,SAAS,CAAC,EAAE,mBAAmB,GAAG,GAAG,QAAQ,GAAG;AACnD,eAAO;AAAA,MACR;AAAA,IACD;AACA,WAAO;AAAA,EACR;AAAA,EAEA,iBAAyB;AACxB,UAAM,EAAE,SAAS,IAAI;AACrB,QAAI,SAAS,SAAS,EAAG,QAAO;AAChC,WAAO,SAAS,OAAO,CAAC,KAAK,QAAQ,MAAM;AAC1C,UAAI,MAAM,EAAG,QAAO,KAAK,OAAO,CAAC,IAAI,OAAO,CAAC;AAC7C,aAAO,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,OAAO,CAAC;AAAA,IACxC,GAAG,EAAE;AAAA,EACN;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,10 +2,10 @@ import { Box } from "../Box.mjs";
|
|
|
2
2
|
import { Vec } from "../Vec.mjs";
|
|
3
3
|
import { Polygon2d } from "./Polygon2d.mjs";
|
|
4
4
|
class Rectangle2d extends Polygon2d {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
_x;
|
|
6
|
+
_y;
|
|
7
|
+
_w;
|
|
8
|
+
_h;
|
|
9
9
|
constructor(config) {
|
|
10
10
|
const { x = 0, y = 0, width, height } = config;
|
|
11
11
|
super({
|
|
@@ -17,18 +17,29 @@ class Rectangle2d extends Polygon2d {
|
|
|
17
17
|
new Vec(x, y + height)
|
|
18
18
|
]
|
|
19
19
|
});
|
|
20
|
-
this.
|
|
21
|
-
this.
|
|
22
|
-
this.
|
|
23
|
-
this.
|
|
20
|
+
this._x = x;
|
|
21
|
+
this._y = y;
|
|
22
|
+
this._w = width;
|
|
23
|
+
this._h = height;
|
|
24
24
|
}
|
|
25
25
|
getBounds() {
|
|
26
|
-
return new Box(this.
|
|
26
|
+
return new Box(this._x, this._y, this._w, this._h);
|
|
27
27
|
}
|
|
28
28
|
getSvgPathData() {
|
|
29
|
-
const { x, y, w, h } = this;
|
|
30
|
-
|
|
29
|
+
const { _x: x, _y: y, _w: w, _h: h } = this;
|
|
30
|
+
this.negativeZeroFix();
|
|
31
|
+
return `M${x},${y} h${w} v${h} h${-w}z`;
|
|
31
32
|
}
|
|
33
|
+
negativeZeroFix() {
|
|
34
|
+
this._x = zeroFix(this._x);
|
|
35
|
+
this._y = zeroFix(this._y);
|
|
36
|
+
this._w = zeroFix(this._w);
|
|
37
|
+
this._h = zeroFix(this._h);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function zeroFix(value) {
|
|
41
|
+
if (Object.is(value, -0)) return 0;
|
|
42
|
+
return value;
|
|
32
43
|
}
|
|
33
44
|
export {
|
|
34
45
|
Rectangle2d
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/primitives/geometry/Rectangle2d.ts"],
|
|
4
|
-
"sourcesContent": ["import { Box } from '../Box'\nimport { Vec } from '../Vec'\nimport { Geometry2dOptions } from './Geometry2d'\nimport { Polygon2d } from './Polygon2d'\n\n/** @public */\nexport class Rectangle2d extends Polygon2d {\n\
|
|
5
|
-
"mappings": "AAAA,SAAS,WAAW;AACpB,SAAS,WAAW;AAEpB,SAAS,iBAAiB;AAGnB,MAAM,oBAAoB,UAAU;AAAA,
|
|
4
|
+
"sourcesContent": ["import { Box } from '../Box'\nimport { Vec } from '../Vec'\nimport { Geometry2dOptions } from './Geometry2d'\nimport { Polygon2d } from './Polygon2d'\n\n/** @public */\nexport class Rectangle2d extends Polygon2d {\n\tprivate _x: number\n\tprivate _y: number\n\tprivate _w: number\n\tprivate _h: number\n\n\tconstructor(\n\t\tconfig: Omit<Geometry2dOptions, 'isClosed'> & {\n\t\t\tx?: number\n\t\t\ty?: number\n\t\t\twidth: number\n\t\t\theight: number\n\t\t}\n\t) {\n\t\tconst { x = 0, y = 0, width, height } = config\n\t\tsuper({\n\t\t\t...config,\n\t\t\tpoints: [\n\t\t\t\tnew Vec(x, y),\n\t\t\t\tnew Vec(x + width, y),\n\t\t\t\tnew Vec(x + width, y + height),\n\t\t\t\tnew Vec(x, y + height),\n\t\t\t],\n\t\t})\n\t\tthis._x = x\n\t\tthis._y = y\n\t\tthis._w = width\n\t\tthis._h = height\n\t}\n\n\tgetBounds() {\n\t\treturn new Box(this._x, this._y, this._w, this._h)\n\t}\n\n\tgetSvgPathData(): string {\n\t\tconst { _x: x, _y: y, _w: w, _h: h } = this\n\t\tthis.negativeZeroFix()\n\t\treturn `M${x},${y} h${w} v${h} h${-w}z`\n\t}\n\n\tprivate negativeZeroFix() {\n\t\tthis._x = zeroFix(this._x)\n\t\tthis._y = zeroFix(this._y)\n\t\tthis._w = zeroFix(this._w)\n\t\tthis._h = zeroFix(this._h)\n\t}\n}\n\nfunction zeroFix(value: number) {\n\tif (Object.is(value, -0)) return 0\n\treturn value\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,WAAW;AACpB,SAAS,WAAW;AAEpB,SAAS,iBAAiB;AAGnB,MAAM,oBAAoB,UAAU;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YACC,QAMC;AACD,UAAM,EAAE,IAAI,GAAG,IAAI,GAAG,OAAO,OAAO,IAAI;AACxC,UAAM;AAAA,MACL,GAAG;AAAA,MACH,QAAQ;AAAA,QACP,IAAI,IAAI,GAAG,CAAC;AAAA,QACZ,IAAI,IAAI,IAAI,OAAO,CAAC;AAAA,QACpB,IAAI,IAAI,IAAI,OAAO,IAAI,MAAM;AAAA,QAC7B,IAAI,IAAI,GAAG,IAAI,MAAM;AAAA,MACtB;AAAA,IACD,CAAC;AACD,SAAK,KAAK;AACV,SAAK,KAAK;AACV,SAAK,KAAK;AACV,SAAK,KAAK;AAAA,EACX;AAAA,EAEA,YAAY;AACX,WAAO,IAAI,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,EAAE;AAAA,EAClD;AAAA,EAEA,iBAAyB;AACxB,UAAM,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,EAAE,IAAI;AACvC,SAAK,gBAAgB;AACrB,WAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAAA,EACrC;AAAA,EAEQ,kBAAkB;AACzB,SAAK,KAAK,QAAQ,KAAK,EAAE;AACzB,SAAK,KAAK,QAAQ,KAAK,EAAE;AACzB,SAAK,KAAK,QAAQ,KAAK,EAAE;AACzB,SAAK,KAAK,QAAQ,KAAK,EAAE;AAAA,EAC1B;AACD;AAEA,SAAS,QAAQ,OAAe;AAC/B,MAAI,OAAO,GAAG,OAAO,EAAE,EAAG,QAAO;AACjC,SAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -9,58 +9,58 @@ class Stadium2d extends Geometry2d {
|
|
|
9
9
|
super({ ...config, isClosed: true });
|
|
10
10
|
this.config = config;
|
|
11
11
|
const { width: w, height: h } = config;
|
|
12
|
-
this.
|
|
13
|
-
this.
|
|
12
|
+
this._w = w;
|
|
13
|
+
this._h = h;
|
|
14
14
|
if (h > w) {
|
|
15
15
|
const r = w / 2;
|
|
16
|
-
this.
|
|
16
|
+
this._a = new Arc2d({
|
|
17
17
|
start: new Vec(0, r),
|
|
18
18
|
end: new Vec(w, r),
|
|
19
19
|
center: new Vec(w / 2, r),
|
|
20
20
|
sweepFlag: 1,
|
|
21
21
|
largeArcFlag: 1
|
|
22
22
|
});
|
|
23
|
-
this.
|
|
24
|
-
this.
|
|
23
|
+
this._b = new Edge2d({ start: new Vec(w, r), end: new Vec(w, h - r) });
|
|
24
|
+
this._c = new Arc2d({
|
|
25
25
|
start: new Vec(w, h - r),
|
|
26
26
|
end: new Vec(0, h - r),
|
|
27
27
|
center: new Vec(w / 2, h - r),
|
|
28
28
|
sweepFlag: 1,
|
|
29
29
|
largeArcFlag: 1
|
|
30
30
|
});
|
|
31
|
-
this.
|
|
31
|
+
this._d = new Edge2d({ start: new Vec(0, h - r), end: new Vec(0, r) });
|
|
32
32
|
} else {
|
|
33
33
|
const r = h / 2;
|
|
34
|
-
this.
|
|
34
|
+
this._a = new Arc2d({
|
|
35
35
|
start: new Vec(r, h),
|
|
36
36
|
end: new Vec(r, 0),
|
|
37
37
|
center: new Vec(r, r),
|
|
38
38
|
sweepFlag: 1,
|
|
39
39
|
largeArcFlag: 1
|
|
40
40
|
});
|
|
41
|
-
this.
|
|
42
|
-
this.
|
|
41
|
+
this._b = new Edge2d({ start: new Vec(r, 0), end: new Vec(w - r, 0) });
|
|
42
|
+
this._c = new Arc2d({
|
|
43
43
|
start: new Vec(w - r, 0),
|
|
44
44
|
end: new Vec(w - r, h),
|
|
45
45
|
center: new Vec(w - r, r),
|
|
46
46
|
sweepFlag: 1,
|
|
47
47
|
largeArcFlag: 1
|
|
48
48
|
});
|
|
49
|
-
this.
|
|
49
|
+
this._d = new Edge2d({ start: new Vec(w - r, h), end: new Vec(r, h) });
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
_w;
|
|
53
|
+
_h;
|
|
54
|
+
_a;
|
|
55
|
+
_b;
|
|
56
|
+
_c;
|
|
57
|
+
_d;
|
|
58
58
|
nearestPoint(A) {
|
|
59
59
|
let nearest;
|
|
60
60
|
let dist = Infinity;
|
|
61
61
|
let _d;
|
|
62
62
|
let p;
|
|
63
|
-
const { a, b, c, d } = this;
|
|
63
|
+
const { _a: a, _b: b, _c: c, _d: d } = this;
|
|
64
64
|
for (const part of [a, b, c, d]) {
|
|
65
65
|
p = part.nearestPoint(A);
|
|
66
66
|
_d = Vec.Dist2(p, A);
|
|
@@ -73,26 +73,26 @@ class Stadium2d extends Geometry2d {
|
|
|
73
73
|
return nearest;
|
|
74
74
|
}
|
|
75
75
|
hitTestLineSegment(A, B) {
|
|
76
|
-
const { a, b, c, d } = this;
|
|
76
|
+
const { _a: a, _b: b, _c: c, _d: d } = this;
|
|
77
77
|
return [a, b, c, d].some((edge) => edge.hitTestLineSegment(A, B));
|
|
78
78
|
}
|
|
79
79
|
getVertices() {
|
|
80
|
-
const { a, b, c, d } = this;
|
|
80
|
+
const { _a: a, _b: b, _c: c, _d: d } = this;
|
|
81
81
|
return [a, b, c, d].reduce((a2, p) => {
|
|
82
82
|
a2.push(...p.vertices);
|
|
83
83
|
return a2;
|
|
84
84
|
}, []);
|
|
85
85
|
}
|
|
86
86
|
getBounds() {
|
|
87
|
-
return new Box(0, 0, this.
|
|
87
|
+
return new Box(0, 0, this._w, this._h);
|
|
88
88
|
}
|
|
89
89
|
getLength() {
|
|
90
|
-
const { h, w } = this;
|
|
90
|
+
const { _h: h, _w: w } = this;
|
|
91
91
|
if (h > w) return (PI * (w / 2) + (h - w)) * 2;
|
|
92
92
|
else return (PI * (h / 2) + (w - h)) * 2;
|
|
93
93
|
}
|
|
94
94
|
getSvgPathData() {
|
|
95
|
-
const { a, b, c, d } = this;
|
|
95
|
+
const { _a: a, _b: b, _c: c, _d: d } = this;
|
|
96
96
|
return [a, b, c, d].map((p, i) => p.getSvgPathData(i === 0)).join(" ") + " Z";
|
|
97
97
|
}
|
|
98
98
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/primitives/geometry/Stadium2d.ts"],
|
|
4
|
-
"sourcesContent": ["import { Box } from '../Box'\nimport { Vec, VecLike } from '../Vec'\nimport { PI } from '../utils'\nimport { Arc2d } from './Arc2d'\nimport { Edge2d } from './Edge2d'\nimport { Geometry2d, Geometry2dOptions } from './Geometry2d'\n\n/** @public */\nexport class Stadium2d extends Geometry2d {\n\
|
|
5
|
-
"mappings": "AAAA,SAAS,WAAW;AACpB,SAAS,WAAoB;AAC7B,SAAS,UAAU;AACnB,SAAS,aAAa;AACtB,SAAS,cAAc;AACvB,SAAS,kBAAqC;AAGvC,MAAM,kBAAkB,WAAW;AAAA,
|
|
4
|
+
"sourcesContent": ["import { Box } from '../Box'\nimport { Vec, VecLike } from '../Vec'\nimport { PI } from '../utils'\nimport { Arc2d } from './Arc2d'\nimport { Edge2d } from './Edge2d'\nimport { Geometry2d, Geometry2dOptions } from './Geometry2d'\n\n/** @public */\nexport class Stadium2d extends Geometry2d {\n\tprivate _w: number\n\tprivate _h: number\n\tprivate _a: Arc2d\n\tprivate _b: Edge2d\n\tprivate _c: Arc2d\n\tprivate _d: Edge2d\n\n\tconstructor(\n\t\tpublic config: Omit<Geometry2dOptions, 'isClosed'> & {\n\t\t\twidth: number\n\t\t\theight: number\n\t\t}\n\t) {\n\t\tsuper({ ...config, isClosed: true })\n\t\tconst { width: w, height: h } = config\n\t\tthis._w = w\n\t\tthis._h = h\n\n\t\tif (h > w) {\n\t\t\tconst r = w / 2\n\t\t\tthis._a = new Arc2d({\n\t\t\t\tstart: new Vec(0, r),\n\t\t\t\tend: new Vec(w, r),\n\t\t\t\tcenter: new Vec(w / 2, r),\n\t\t\t\tsweepFlag: 1,\n\t\t\t\tlargeArcFlag: 1,\n\t\t\t})\n\t\t\tthis._b = new Edge2d({ start: new Vec(w, r), end: new Vec(w, h - r) })\n\t\t\tthis._c = new Arc2d({\n\t\t\t\tstart: new Vec(w, h - r),\n\t\t\t\tend: new Vec(0, h - r),\n\t\t\t\tcenter: new Vec(w / 2, h - r),\n\t\t\t\tsweepFlag: 1,\n\t\t\t\tlargeArcFlag: 1,\n\t\t\t})\n\t\t\tthis._d = new Edge2d({ start: new Vec(0, h - r), end: new Vec(0, r) })\n\t\t} else {\n\t\t\tconst r = h / 2\n\t\t\tthis._a = new Arc2d({\n\t\t\t\tstart: new Vec(r, h),\n\t\t\t\tend: new Vec(r, 0),\n\t\t\t\tcenter: new Vec(r, r),\n\t\t\t\tsweepFlag: 1,\n\t\t\t\tlargeArcFlag: 1,\n\t\t\t})\n\t\t\tthis._b = new Edge2d({ start: new Vec(r, 0), end: new Vec(w - r, 0) })\n\t\t\tthis._c = new Arc2d({\n\t\t\t\tstart: new Vec(w - r, 0),\n\t\t\t\tend: new Vec(w - r, h),\n\t\t\t\tcenter: new Vec(w - r, r),\n\t\t\t\tsweepFlag: 1,\n\t\t\t\tlargeArcFlag: 1,\n\t\t\t})\n\t\t\tthis._d = new Edge2d({ start: new Vec(w - r, h), end: new Vec(r, h) })\n\t\t}\n\t}\n\n\tnearestPoint(A: VecLike): Vec {\n\t\tlet nearest: Vec | undefined\n\t\tlet dist = Infinity\n\t\tlet _d: number\n\t\tlet p: Vec\n\n\t\tconst { _a: a, _b: b, _c: c, _d: d } = this\n\t\tfor (const part of [a, b, c, d]) {\n\t\t\tp = part.nearestPoint(A)\n\t\t\t_d = Vec.Dist2(p, A)\n\t\t\tif (_d < dist) {\n\t\t\t\tnearest = p\n\t\t\t\tdist = _d\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\thitTestLineSegment(A: VecLike, B: VecLike): boolean {\n\t\tconst { _a: a, _b: b, _c: c, _d: d } = this\n\t\treturn [a, b, c, d].some((edge) => edge.hitTestLineSegment(A, B))\n\t}\n\n\tgetVertices() {\n\t\tconst { _a: a, _b: b, _c: c, _d: d } = this\n\t\treturn [a, b, c, d].reduce<Vec[]>((a, p) => {\n\t\t\ta.push(...p.vertices)\n\t\t\treturn a\n\t\t}, [])\n\t}\n\n\tgetBounds() {\n\t\treturn new Box(0, 0, this._w, this._h)\n\t}\n\n\tgetLength() {\n\t\tconst { _h: h, _w: w } = this\n\t\tif (h > w) return (PI * (w / 2) + (h - w)) * 2\n\t\telse return (PI * (h / 2) + (w - h)) * 2\n\t}\n\n\tgetSvgPathData() {\n\t\tconst { _a: a, _b: b, _c: c, _d: d } = this\n\t\treturn [a, b, c, d].map((p, i) => p.getSvgPathData(i === 0)).join(' ') + ' Z'\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["a"]
|
|
7
7
|
}
|
package/dist-esm/version.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const version = "3.14.0-canary.
|
|
1
|
+
const version = "3.14.0-canary.403af9c5d8f2";
|
|
2
2
|
const publishDates = {
|
|
3
3
|
major: "2024-09-13T14:36:29.063Z",
|
|
4
|
-
minor: "2025-
|
|
5
|
-
patch: "2025-
|
|
4
|
+
minor: "2025-06-01T07:14:58.245Z",
|
|
5
|
+
patch: "2025-06-01T07:14:58.245Z"
|
|
6
6
|
};
|
|
7
7
|
export {
|
|
8
8
|
publishDates,
|
package/dist-esm/version.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/version.ts"],
|
|
4
|
-
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.14.0-canary.
|
|
4
|
+
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.14.0-canary.403af9c5d8f2'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-06-01T07:14:58.245Z',\n\tpatch: '2025-06-01T07:14:58.245Z',\n}\n"],
|
|
5
5
|
"mappings": "AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tldraw/editor",
|
|
3
3
|
"description": "A tiny little drawing app (editor).",
|
|
4
|
-
"version": "3.14.0-canary.
|
|
4
|
+
"version": "3.14.0-canary.403af9c5d8f2",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "tldraw Inc.",
|
|
7
7
|
"email": "hello@tldraw.com"
|
|
@@ -48,12 +48,12 @@
|
|
|
48
48
|
"@tiptap/core": "^2.9.1",
|
|
49
49
|
"@tiptap/pm": "^2.9.1",
|
|
50
50
|
"@tiptap/react": "^2.9.1",
|
|
51
|
-
"@tldraw/state": "3.14.0-canary.
|
|
52
|
-
"@tldraw/state-react": "3.14.0-canary.
|
|
53
|
-
"@tldraw/store": "3.14.0-canary.
|
|
54
|
-
"@tldraw/tlschema": "3.14.0-canary.
|
|
55
|
-
"@tldraw/utils": "3.14.0-canary.
|
|
56
|
-
"@tldraw/validate": "3.14.0-canary.
|
|
51
|
+
"@tldraw/state": "3.14.0-canary.403af9c5d8f2",
|
|
52
|
+
"@tldraw/state-react": "3.14.0-canary.403af9c5d8f2",
|
|
53
|
+
"@tldraw/store": "3.14.0-canary.403af9c5d8f2",
|
|
54
|
+
"@tldraw/tlschema": "3.14.0-canary.403af9c5d8f2",
|
|
55
|
+
"@tldraw/utils": "3.14.0-canary.403af9c5d8f2",
|
|
56
|
+
"@tldraw/validate": "3.14.0-canary.403af9c5d8f2",
|
|
57
57
|
"@types/core-js": "^2.5.8",
|
|
58
58
|
"@use-gesture/react": "^10.3.1",
|
|
59
59
|
"classnames": "^2.5.1",
|
|
@@ -144,8 +144,8 @@ describe('Vec.Uni', () => {
|
|
|
144
144
|
expect(Vec.Uni(new Vec(10, 10))).toMatchObject(new Vec(0.7071067811865475, 0.7071067811865475))
|
|
145
145
|
})
|
|
146
146
|
|
|
147
|
-
it('Divide-by-zero spits out
|
|
148
|
-
expect(Vec.Uni(new Vec(0, 0))).toMatchObject(new Vec(
|
|
147
|
+
it('Divide-by-zero spits out 0', () => {
|
|
148
|
+
expect(Vec.Uni(new Vec(0, 0))).toMatchObject(new Vec(0, 0))
|
|
149
149
|
})
|
|
150
150
|
})
|
|
151
151
|
|
|
@@ -189,11 +189,15 @@ export class Vec {
|
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
uni() {
|
|
192
|
-
|
|
192
|
+
const l = this.len()
|
|
193
|
+
if (l === 0) return this
|
|
194
|
+
this.x /= l
|
|
195
|
+
this.y /= l
|
|
196
|
+
return this
|
|
193
197
|
}
|
|
194
198
|
|
|
195
199
|
tan(V: VecLike): Vec {
|
|
196
|
-
return
|
|
200
|
+
return this.sub(V).uni()
|
|
197
201
|
}
|
|
198
202
|
|
|
199
203
|
dist(V: VecLike): number {
|
|
@@ -236,15 +240,15 @@ export class Vec {
|
|
|
236
240
|
return Vec.EqualsXY(this, x, y)
|
|
237
241
|
}
|
|
238
242
|
|
|
243
|
+
/** @deprecated use `uni` instead */
|
|
239
244
|
norm() {
|
|
240
|
-
|
|
241
|
-
this.x = l === 0 ? 0 : this.x / l
|
|
242
|
-
this.y = l === 0 ? 0 : this.y / l
|
|
243
|
-
return this
|
|
245
|
+
return this.uni()
|
|
244
246
|
}
|
|
245
247
|
|
|
246
248
|
toFixed() {
|
|
247
|
-
|
|
249
|
+
this.x = toFixed(this.x)
|
|
250
|
+
this.y = toFixed(this.y)
|
|
251
|
+
return this
|
|
248
252
|
}
|
|
249
253
|
|
|
250
254
|
toString() {
|
|
@@ -375,7 +379,8 @@ export class Vec {
|
|
|
375
379
|
* Get the unit vector of A.
|
|
376
380
|
*/
|
|
377
381
|
static Uni(A: VecLike) {
|
|
378
|
-
|
|
382
|
+
const l = Vec.Len(A)
|
|
383
|
+
return new Vec(l === 0 ? 0 : A.x / l, l === 0 ? 0 : A.y / l)
|
|
379
384
|
}
|
|
380
385
|
|
|
381
386
|
static Tan(A: VecLike, B: VecLike): Vec {
|
|
@@ -6,16 +6,15 @@ import { getVerticesCountForLength } from './geometry-constants'
|
|
|
6
6
|
|
|
7
7
|
/** @public */
|
|
8
8
|
export class Arc2d extends Geometry2d {
|
|
9
|
-
_center: Vec
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
angleEnd: number
|
|
9
|
+
private _center: Vec
|
|
10
|
+
private _radius: number
|
|
11
|
+
private _start: Vec
|
|
12
|
+
private _end: Vec
|
|
13
|
+
private _largeArcFlag: number
|
|
14
|
+
private _sweepFlag: number
|
|
15
|
+
private _measure: number
|
|
16
|
+
private _angleStart: number
|
|
17
|
+
private _angleEnd: number
|
|
19
18
|
|
|
20
19
|
constructor(
|
|
21
20
|
config: Omit<Geometry2dOptions, 'isFilled' | 'isClosed'> & {
|
|
@@ -31,21 +30,29 @@ export class Arc2d extends Geometry2d {
|
|
|
31
30
|
if (start.equals(end)) throw Error(`Arc must have different start and end points.`)
|
|
32
31
|
|
|
33
32
|
// ensure that the start and end are clockwise
|
|
34
|
-
this.
|
|
35
|
-
this.
|
|
36
|
-
this.
|
|
37
|
-
this.
|
|
33
|
+
this._angleStart = Vec.Angle(center, start)
|
|
34
|
+
this._angleEnd = Vec.Angle(center, end)
|
|
35
|
+
this._radius = Vec.Dist(center, start)
|
|
36
|
+
this._measure = getArcMeasure(this._angleStart, this._angleEnd, sweepFlag, largeArcFlag)
|
|
38
37
|
|
|
39
|
-
this.
|
|
40
|
-
this.
|
|
38
|
+
this._start = start
|
|
39
|
+
this._end = end
|
|
41
40
|
|
|
42
|
-
this.
|
|
43
|
-
this.
|
|
41
|
+
this._sweepFlag = sweepFlag
|
|
42
|
+
this._largeArcFlag = largeArcFlag
|
|
44
43
|
this._center = center
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
nearestPoint(point: VecLike): Vec {
|
|
48
|
-
const {
|
|
47
|
+
const {
|
|
48
|
+
_center,
|
|
49
|
+
_measure: measure,
|
|
50
|
+
_radius: radius,
|
|
51
|
+
_angleEnd: angleEnd,
|
|
52
|
+
_angleStart: angleStart,
|
|
53
|
+
_start: A,
|
|
54
|
+
_end: B,
|
|
55
|
+
} = this
|
|
49
56
|
const t = getPointInArcT(measure, angleStart, angleEnd, _center.angle(point))
|
|
50
57
|
if (t <= 0) return A
|
|
51
58
|
if (t >= 1) return B
|
|
@@ -68,7 +75,13 @@ export class Arc2d extends Geometry2d {
|
|
|
68
75
|
}
|
|
69
76
|
|
|
70
77
|
hitTestLineSegment(A: VecLike, B: VecLike): boolean {
|
|
71
|
-
const {
|
|
78
|
+
const {
|
|
79
|
+
_center,
|
|
80
|
+
_radius: radius,
|
|
81
|
+
_measure: measure,
|
|
82
|
+
_angleStart: angleStart,
|
|
83
|
+
_angleEnd: angleEnd,
|
|
84
|
+
} = this
|
|
72
85
|
const intersection = intersectLineSegmentCircle(A, B, _center, radius)
|
|
73
86
|
if (intersection === null) return false
|
|
74
87
|
|
|
@@ -79,7 +92,7 @@ export class Arc2d extends Geometry2d {
|
|
|
79
92
|
}
|
|
80
93
|
|
|
81
94
|
getVertices(): Vec[] {
|
|
82
|
-
const { _center, measure, length, radius, angleStart } = this
|
|
95
|
+
const { _center, _measure: measure, length, _radius: radius, _angleStart: angleStart } = this
|
|
83
96
|
const vertices: Vec[] = []
|
|
84
97
|
for (let i = 0, n = getVerticesCountForLength(Math.abs(length)); i < n + 1; i++) {
|
|
85
98
|
const t = (i / n) * measure
|
|
@@ -90,11 +103,17 @@ export class Arc2d extends Geometry2d {
|
|
|
90
103
|
}
|
|
91
104
|
|
|
92
105
|
getSvgPathData(first = true) {
|
|
93
|
-
const {
|
|
106
|
+
const {
|
|
107
|
+
_start: start,
|
|
108
|
+
_end: end,
|
|
109
|
+
_radius: radius,
|
|
110
|
+
_largeArcFlag: largeArcFlag,
|
|
111
|
+
_sweepFlag: sweepFlag,
|
|
112
|
+
} = this
|
|
94
113
|
return `${first ? `M${start.toFixed()}` : ``} A${radius} ${radius} 0 ${largeArcFlag} ${sweepFlag} ${end.toFixed()}`
|
|
95
114
|
}
|
|
96
115
|
|
|
97
116
|
override getLength() {
|
|
98
|
-
return Math.abs(this.
|
|
117
|
+
return Math.abs(this._measure * this._radius)
|
|
99
118
|
}
|
|
100
119
|
}
|
|
@@ -7,10 +7,10 @@ import { getVerticesCountForLength } from './geometry-constants'
|
|
|
7
7
|
|
|
8
8
|
/** @public */
|
|
9
9
|
export class Circle2d extends Geometry2d {
|
|
10
|
-
_center: Vec
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
private _center: Vec
|
|
11
|
+
private _radius: number
|
|
12
|
+
private _x: number
|
|
13
|
+
private _y: number
|
|
14
14
|
|
|
15
15
|
constructor(
|
|
16
16
|
public config: Omit<Geometry2dOptions, 'isClosed'> & {
|
|
@@ -22,18 +22,18 @@ export class Circle2d extends Geometry2d {
|
|
|
22
22
|
) {
|
|
23
23
|
super({ isClosed: true, ...config })
|
|
24
24
|
const { x = 0, y = 0, radius } = config
|
|
25
|
-
this.
|
|
26
|
-
this.
|
|
25
|
+
this._x = x
|
|
26
|
+
this._y = y
|
|
27
27
|
this._center = new Vec(radius + x, radius + y)
|
|
28
|
-
this.
|
|
28
|
+
this._radius = radius
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
getBounds() {
|
|
32
|
-
return new Box(this.
|
|
32
|
+
return new Box(this._x, this._y, this._radius * 2, this._radius * 2)
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
getVertices(): Vec[] {
|
|
36
|
-
const { _center, radius } = this
|
|
36
|
+
const { _center, _radius: radius } = this
|
|
37
37
|
const perimeter = PI2 * radius
|
|
38
38
|
const vertices: Vec[] = []
|
|
39
39
|
for (let i = 0, n = getVerticesCountForLength(perimeter); i < n; i++) {
|
|
@@ -44,18 +44,18 @@ export class Circle2d extends Geometry2d {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
nearestPoint(point: VecLike): Vec {
|
|
47
|
-
const { _center, radius } = this
|
|
47
|
+
const { _center, _radius: radius } = this
|
|
48
48
|
if (_center.equals(point)) return Vec.AddXY(_center, radius, 0)
|
|
49
49
|
return Vec.Sub(point, _center).uni().mul(radius).add(_center)
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
hitTestLineSegment(A: VecLike, B: VecLike, distance = 0): boolean {
|
|
53
|
-
const { _center, radius } = this
|
|
53
|
+
const { _center, _radius: radius } = this
|
|
54
54
|
return intersectLineSegmentCircle(A, B, _center, radius + distance) !== null
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
getSvgPathData(): string {
|
|
58
|
-
const { _center, radius } = this
|
|
58
|
+
const { _center, _radius: radius } = this
|
|
59
59
|
return `M${_center.x + radius},${_center.y} a${radius},${radius} 0 1,0 ${radius * 2},0a${radius},${radius} 0 1,0 -${radius * 2},0`
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -4,10 +4,10 @@ import { Polyline2d } from './Polyline2d'
|
|
|
4
4
|
|
|
5
5
|
/** @public */
|
|
6
6
|
export class CubicBezier2d extends Polyline2d {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
private _a: Vec
|
|
8
|
+
private _b: Vec
|
|
9
|
+
private _c: Vec
|
|
10
|
+
private _d: Vec
|
|
11
11
|
|
|
12
12
|
constructor(
|
|
13
13
|
config: Omit<Geometry2dOptions, 'isFilled' | 'isClosed'> & {
|
|
@@ -20,15 +20,15 @@ export class CubicBezier2d extends Polyline2d {
|
|
|
20
20
|
const { start: a, cp1: b, cp2: c, end: d } = config
|
|
21
21
|
super({ ...config, points: [a, d] })
|
|
22
22
|
|
|
23
|
-
this.
|
|
24
|
-
this.
|
|
25
|
-
this.
|
|
26
|
-
this.
|
|
23
|
+
this._a = a
|
|
24
|
+
this._b = b
|
|
25
|
+
this._c = c
|
|
26
|
+
this._d = d
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
override getVertices() {
|
|
30
30
|
const vertices = [] as Vec[]
|
|
31
|
-
const { a, b, c, d } = this
|
|
31
|
+
const { _a: a, _b: b, _c: c, _d: d } = this
|
|
32
32
|
// we'll always use ten vertices for each bezier curve
|
|
33
33
|
for (let i = 0, n = 10; i <= n; i++) {
|
|
34
34
|
const t = i / n
|
|
@@ -48,10 +48,6 @@ export class CubicBezier2d extends Polyline2d {
|
|
|
48
48
|
return vertices
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
midPoint() {
|
|
52
|
-
return CubicBezier2d.GetAtT(this, 0.5)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
51
|
nearestPoint(A: VecLike): Vec {
|
|
56
52
|
let nearest: Vec | undefined
|
|
57
53
|
let dist = Infinity
|
|
@@ -71,12 +67,12 @@ export class CubicBezier2d extends Polyline2d {
|
|
|
71
67
|
}
|
|
72
68
|
|
|
73
69
|
getSvgPathData(first = true) {
|
|
74
|
-
const { a, b, c, d } = this
|
|
70
|
+
const { _a: a, _b: b, _c: c, _d: d } = this
|
|
75
71
|
return `${first ? `M ${a.toFixed()} ` : ``} C${b.toFixed()} ${c.toFixed()} ${d.toFixed()}`
|
|
76
72
|
}
|
|
77
73
|
|
|
78
74
|
static GetAtT(segment: CubicBezier2d, t: number) {
|
|
79
|
-
const { a, b, c, d } = segment
|
|
75
|
+
const { _a: a, _b: b, _c: c, _d: d } = segment
|
|
80
76
|
return new Vec(
|
|
81
77
|
(1 - t) * (1 - t) * (1 - t) * a.x +
|
|
82
78
|
3 * ((1 - t) * (1 - t)) * t * b.x +
|
|
@@ -89,9 +85,9 @@ export class CubicBezier2d extends Polyline2d {
|
|
|
89
85
|
)
|
|
90
86
|
}
|
|
91
87
|
|
|
92
|
-
override getLength(
|
|
88
|
+
override getLength(_filters?: Geometry2dFilters, precision = 32) {
|
|
93
89
|
let n1: Vec,
|
|
94
|
-
p1 = this.
|
|
90
|
+
p1 = this._a,
|
|
95
91
|
length = 0
|
|
96
92
|
for (let i = 1; i <= precision; i++) {
|
|
97
93
|
n1 = CubicBezier2d.GetAtT(this, i / precision)
|