@retikz/core 0.1.0-alpha.5 → 0.1.0-beta.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.
Files changed (189) hide show
  1. package/dist/es/compile/compile.d.ts +17 -0
  2. package/dist/es/compile/compile.d.ts.map +1 -1
  3. package/dist/es/compile/compile.js +40 -15
  4. package/dist/es/compile/index.d.ts +1 -1
  5. package/dist/es/compile/index.d.ts.map +1 -1
  6. package/dist/es/compile/node.d.ts +3 -3
  7. package/dist/es/compile/node.d.ts.map +1 -1
  8. package/dist/es/compile/node.js +1 -1
  9. package/dist/es/compile/path/anchor.d.ts +19 -0
  10. package/dist/es/compile/path/anchor.d.ts.map +1 -0
  11. package/dist/es/compile/path/anchor.js +54 -0
  12. package/dist/es/compile/{path.d.ts → path/index.d.ts} +18 -7
  13. package/dist/es/compile/path/index.d.ts.map +1 -0
  14. package/dist/es/compile/path/index.js +308 -0
  15. package/dist/es/compile/path/label.d.ts +18 -0
  16. package/dist/es/compile/path/label.d.ts.map +1 -0
  17. package/dist/es/compile/path/label.js +102 -0
  18. package/dist/es/compile/path/relative.d.ts +8 -0
  19. package/dist/es/compile/path/relative.d.ts.map +1 -0
  20. package/dist/es/compile/path/relative.js +48 -0
  21. package/dist/es/compile/path/shrink.d.ts +24 -0
  22. package/dist/es/compile/path/shrink.d.ts.map +1 -0
  23. package/dist/es/compile/path/shrink.js +136 -0
  24. package/dist/es/compile/path/split.d.ts +15 -0
  25. package/dist/es/compile/path/split.d.ts.map +1 -0
  26. package/dist/es/compile/path/split.js +46 -0
  27. package/dist/es/compile/text-metrics.d.ts +4 -1
  28. package/dist/es/compile/text-metrics.d.ts.map +1 -1
  29. package/dist/es/compile/text-metrics.js +11 -5
  30. package/dist/es/geometry/_transform.d.ts +21 -0
  31. package/dist/es/geometry/_transform.d.ts.map +1 -0
  32. package/dist/es/geometry/_transform.js +27 -0
  33. package/dist/es/geometry/bend.d.ts +1 -1
  34. package/dist/es/geometry/bend.js +1 -1
  35. package/dist/es/geometry/circle.d.ts +2 -3
  36. package/dist/es/geometry/circle.d.ts.map +1 -1
  37. package/dist/es/geometry/circle.js +1 -16
  38. package/dist/es/geometry/diamond.d.ts +2 -3
  39. package/dist/es/geometry/diamond.d.ts.map +1 -1
  40. package/dist/es/geometry/diamond.js +1 -16
  41. package/dist/es/geometry/ellipse.d.ts +2 -3
  42. package/dist/es/geometry/ellipse.d.ts.map +1 -1
  43. package/dist/es/geometry/ellipse.js +1 -16
  44. package/dist/es/geometry/polar.d.ts +2 -2
  45. package/dist/es/geometry/polar.d.ts.map +1 -1
  46. package/dist/es/geometry/polar.js +2 -6
  47. package/dist/es/geometry/rect.d.ts.map +1 -1
  48. package/dist/es/geometry/rect.js +1 -18
  49. package/dist/es/geometry/segment.d.ts +5 -1
  50. package/dist/es/geometry/segment.d.ts.map +1 -1
  51. package/dist/es/index.d.ts +10 -6
  52. package/dist/es/index.d.ts.map +1 -1
  53. package/dist/es/index.js +4 -2
  54. package/dist/es/ir/font.d.ts +21 -0
  55. package/dist/es/ir/font.d.ts.map +1 -0
  56. package/dist/es/ir/font.js +15 -0
  57. package/dist/es/ir/index.d.ts +2 -0
  58. package/dist/es/ir/index.d.ts.map +1 -1
  59. package/dist/es/ir/node.d.ts +28 -139
  60. package/dist/es/ir/node.d.ts.map +1 -1
  61. package/dist/es/ir/node.js +6 -30
  62. package/dist/es/ir/path/arrow.d.ts +12 -12
  63. package/dist/es/ir/path/path.d.ts +16 -16
  64. package/dist/es/ir/path/path.js +4 -4
  65. package/dist/es/ir/path/step.d.ts +1 -1
  66. package/dist/es/ir/path/step.d.ts.map +1 -1
  67. package/dist/es/ir/path/step.js +8 -8
  68. package/dist/es/ir/position/offset-position.js +1 -1
  69. package/dist/es/ir/position/polar-position.d.ts.map +1 -1
  70. package/dist/es/ir/position/polar-position.js +2 -2
  71. package/dist/es/ir/position/position.d.ts.map +1 -1
  72. package/dist/es/ir/position/position.js +1 -1
  73. package/dist/es/ir/scene.d.ts +112 -112
  74. package/dist/es/ir/text.d.ts +96 -0
  75. package/dist/es/ir/text.d.ts.map +1 -0
  76. package/dist/es/ir/text.js +20 -0
  77. package/dist/es/parsers/parseTargetSugar.d.ts +4 -0
  78. package/dist/es/parsers/parseTargetSugar.d.ts.map +1 -1
  79. package/dist/es/parsers/parseTargetSugar.js +3 -2
  80. package/dist/es/primitive/ellipse.d.ts +2 -2
  81. package/dist/es/primitive/group.d.ts +23 -7
  82. package/dist/es/primitive/group.d.ts.map +1 -1
  83. package/dist/es/primitive/path.d.ts +51 -11
  84. package/dist/es/primitive/path.d.ts.map +1 -1
  85. package/dist/es/primitive/rect.d.ts +2 -2
  86. package/dist/es/primitive/rect.d.ts.map +1 -1
  87. package/dist/es/primitive/text.d.ts +10 -3
  88. package/dist/es/primitive/text.d.ts.map +1 -1
  89. package/dist/es/primitive/view-box.d.ts +1 -1
  90. package/dist/es/primitive/view-box.d.ts.map +1 -1
  91. package/dist/es/types.d.ts +8 -0
  92. package/dist/es/types.d.ts.map +1 -1
  93. package/dist/lib/compile/compile.cjs +40 -15
  94. package/dist/lib/compile/compile.d.ts +17 -0
  95. package/dist/lib/compile/compile.d.ts.map +1 -1
  96. package/dist/lib/compile/index.d.ts +1 -1
  97. package/dist/lib/compile/index.d.ts.map +1 -1
  98. package/dist/lib/compile/node.cjs +1 -1
  99. package/dist/lib/compile/node.d.ts +3 -3
  100. package/dist/lib/compile/node.d.ts.map +1 -1
  101. package/dist/lib/compile/path/anchor.cjs +58 -0
  102. package/dist/lib/compile/path/anchor.d.ts +19 -0
  103. package/dist/lib/compile/path/anchor.d.ts.map +1 -0
  104. package/dist/lib/compile/path/index.cjs +308 -0
  105. package/dist/lib/compile/{path.d.ts → path/index.d.ts} +18 -7
  106. package/dist/lib/compile/path/index.d.ts.map +1 -0
  107. package/dist/lib/compile/path/label.cjs +103 -0
  108. package/dist/lib/compile/path/label.d.ts +18 -0
  109. package/dist/lib/compile/path/label.d.ts.map +1 -0
  110. package/dist/lib/compile/path/relative.cjs +48 -0
  111. package/dist/lib/compile/path/relative.d.ts +8 -0
  112. package/dist/lib/compile/path/relative.d.ts.map +1 -0
  113. package/dist/lib/compile/path/shrink.cjs +138 -0
  114. package/dist/lib/compile/path/shrink.d.ts +24 -0
  115. package/dist/lib/compile/path/shrink.d.ts.map +1 -0
  116. package/dist/lib/compile/path/split.cjs +46 -0
  117. package/dist/lib/compile/path/split.d.ts +15 -0
  118. package/dist/lib/compile/path/split.d.ts.map +1 -0
  119. package/dist/lib/compile/text-metrics.cjs +11 -5
  120. package/dist/lib/compile/text-metrics.d.ts +4 -1
  121. package/dist/lib/compile/text-metrics.d.ts.map +1 -1
  122. package/dist/lib/geometry/_transform.cjs +28 -0
  123. package/dist/lib/geometry/_transform.d.ts +21 -0
  124. package/dist/lib/geometry/_transform.d.ts.map +1 -0
  125. package/dist/lib/geometry/bend.cjs +1 -1
  126. package/dist/lib/geometry/bend.d.ts +1 -1
  127. package/dist/lib/geometry/circle.cjs +5 -20
  128. package/dist/lib/geometry/circle.d.ts +2 -3
  129. package/dist/lib/geometry/circle.d.ts.map +1 -1
  130. package/dist/lib/geometry/diamond.cjs +5 -20
  131. package/dist/lib/geometry/diamond.d.ts +2 -3
  132. package/dist/lib/geometry/diamond.d.ts.map +1 -1
  133. package/dist/lib/geometry/ellipse.cjs +5 -20
  134. package/dist/lib/geometry/ellipse.d.ts +2 -3
  135. package/dist/lib/geometry/ellipse.d.ts.map +1 -1
  136. package/dist/lib/geometry/polar.cjs +2 -6
  137. package/dist/lib/geometry/polar.d.ts +2 -2
  138. package/dist/lib/geometry/polar.d.ts.map +1 -1
  139. package/dist/lib/geometry/rect.cjs +5 -22
  140. package/dist/lib/geometry/rect.d.ts.map +1 -1
  141. package/dist/lib/geometry/segment.d.ts +5 -1
  142. package/dist/lib/geometry/segment.d.ts.map +1 -1
  143. package/dist/lib/index.cjs +5 -3
  144. package/dist/lib/index.d.ts +10 -6
  145. package/dist/lib/index.d.ts.map +1 -1
  146. package/dist/lib/ir/font.cjs +15 -0
  147. package/dist/lib/ir/font.d.ts +21 -0
  148. package/dist/lib/ir/font.d.ts.map +1 -0
  149. package/dist/lib/ir/index.d.ts +2 -0
  150. package/dist/lib/ir/index.d.ts.map +1 -1
  151. package/dist/lib/ir/node.cjs +7 -34
  152. package/dist/lib/ir/node.d.ts +28 -139
  153. package/dist/lib/ir/node.d.ts.map +1 -1
  154. package/dist/lib/ir/path/arrow.d.ts +12 -12
  155. package/dist/lib/ir/path/path.cjs +4 -4
  156. package/dist/lib/ir/path/path.d.ts +16 -16
  157. package/dist/lib/ir/path/step.cjs +8 -8
  158. package/dist/lib/ir/path/step.d.ts +1 -1
  159. package/dist/lib/ir/path/step.d.ts.map +1 -1
  160. package/dist/lib/ir/position/offset-position.cjs +1 -1
  161. package/dist/lib/ir/position/polar-position.cjs +2 -2
  162. package/dist/lib/ir/position/polar-position.d.ts.map +1 -1
  163. package/dist/lib/ir/position/position.cjs +1 -1
  164. package/dist/lib/ir/position/position.d.ts.map +1 -1
  165. package/dist/lib/ir/scene.d.ts +112 -112
  166. package/dist/lib/ir/text.cjs +21 -0
  167. package/dist/lib/ir/text.d.ts +96 -0
  168. package/dist/lib/ir/text.d.ts.map +1 -0
  169. package/dist/lib/parsers/parseTargetSugar.cjs +3 -2
  170. package/dist/lib/parsers/parseTargetSugar.d.ts +4 -0
  171. package/dist/lib/parsers/parseTargetSugar.d.ts.map +1 -1
  172. package/dist/lib/primitive/ellipse.d.ts +2 -2
  173. package/dist/lib/primitive/group.d.ts +23 -7
  174. package/dist/lib/primitive/group.d.ts.map +1 -1
  175. package/dist/lib/primitive/path.d.ts +51 -11
  176. package/dist/lib/primitive/path.d.ts.map +1 -1
  177. package/dist/lib/primitive/rect.d.ts +2 -2
  178. package/dist/lib/primitive/rect.d.ts.map +1 -1
  179. package/dist/lib/primitive/text.d.ts +10 -3
  180. package/dist/lib/primitive/text.d.ts.map +1 -1
  181. package/dist/lib/primitive/view-box.d.ts +1 -1
  182. package/dist/lib/primitive/view-box.d.ts.map +1 -1
  183. package/dist/lib/types.d.ts +8 -0
  184. package/dist/lib/types.d.ts.map +1 -1
  185. package/package.json +13 -4
  186. package/dist/es/compile/path.d.ts.map +0 -1
  187. package/dist/es/compile/path.js +0 -636
  188. package/dist/lib/compile/path.cjs +0 -636
  189. package/dist/lib/compile/path.d.ts.map +0 -1
@@ -0,0 +1,102 @@
1
+ //#region src/compile/path/label.ts
2
+ /** 边标注默认字号 / 偏移量 */
3
+ var LABEL_FONT_SIZE = 14;
4
+ var LABEL_LINE_HEIGHT_FACTOR = 1.2;
5
+ var LABEL_SIDE_OFFSET = 4;
6
+ var RAD_TO_DEG = 180 / Math.PI;
7
+ /** keyword → t 数值映射;含旧 3 keyword(midway/near-start/near-end)+ 新 4 keyword */
8
+ var KEYWORD_TO_T = {
9
+ "at-start": 0,
10
+ "very-near-start": .125,
11
+ "near-start": .25,
12
+ midway: .5,
13
+ "near-end": .75,
14
+ "very-near-end": .875,
15
+ "at-end": 1
16
+ };
17
+ /**
18
+ * label.position → 段参数 t∈[0,1]
19
+ * @description 数值原样返回(schema 已 clamp 0..1);keyword 走 KEYWORD_TO_T 映射;undefined 退默认 midway (0.5)
20
+ */
21
+ var tForLabelPosition = (pos) => {
22
+ if (typeof pos === "number") return pos;
23
+ if (typeof pos === "string" && pos in KEYWORD_TO_T) return KEYWORD_TO_T[pos];
24
+ return .5;
25
+ };
26
+ /**
27
+ * step.label + 段采样 → TextPrim(sloped 时裹一层 group 旋转)
28
+ * @description 默认 side='above'/position='midway':above/below 锚点 y±offset、align=middle、baseline=bottom/top;left/right x±offset、align=end/start、baseline=middle;sloped 不偏移裹 group rotate(angle, cx, cy) 由切线 atan2 算(SVG y-down CW 正)。返回 primitive + viewBox 外接点
29
+ */
30
+ var emitLabelPrimitive = (label, sample, measureText, round) => {
31
+ const fontSize = LABEL_FONT_SIZE;
32
+ const lineHeight = fontSize * LABEL_LINE_HEIGHT_FACTOR;
33
+ const m = measureText(label.text, { size: fontSize });
34
+ const measuredWidth = m.width;
35
+ const measuredHeight = m.height || lineHeight;
36
+ const side = label.side ?? "above";
37
+ let x = sample.point[0];
38
+ let y = sample.point[1];
39
+ let align = "middle";
40
+ let baseline = "middle";
41
+ if (side === "above") {
42
+ y -= LABEL_SIDE_OFFSET;
43
+ baseline = "bottom";
44
+ } else if (side === "below") {
45
+ y += LABEL_SIDE_OFFSET;
46
+ baseline = "top";
47
+ } else if (side === "left") {
48
+ x -= LABEL_SIDE_OFFSET;
49
+ align = "end";
50
+ } else if (side === "right") {
51
+ x += LABEL_SIDE_OFFSET;
52
+ align = "start";
53
+ } else baseline = "bottom";
54
+ const text = {
55
+ type: "text",
56
+ x: round(x),
57
+ y: round(y),
58
+ lines: [{ text: label.text }],
59
+ fontSize,
60
+ align,
61
+ baseline,
62
+ lineHeight: round(lineHeight),
63
+ measuredWidth: round(measuredWidth),
64
+ measuredHeight: round(measuredHeight),
65
+ fill: "currentColor"
66
+ };
67
+ if (side === "sloped") {
68
+ const groupPrim = {
69
+ type: "group",
70
+ transforms: [{
71
+ kind: "rotate",
72
+ degrees: round(Math.atan2(sample.tangent[1], sample.tangent[0]) * RAD_TO_DEG),
73
+ cx: round(x),
74
+ cy: round(y)
75
+ }],
76
+ children: [text]
77
+ };
78
+ const r = Math.max(measuredWidth / 2, measuredHeight / 2);
79
+ return {
80
+ primitive: groupPrim,
81
+ points: [
82
+ [x - r, y - r],
83
+ [x + r, y - r],
84
+ [x - r, y + r],
85
+ [x + r, y + r]
86
+ ]
87
+ };
88
+ }
89
+ const halfW = measuredWidth / 2;
90
+ const halfH = measuredHeight / 2;
91
+ return {
92
+ primitive: text,
93
+ points: [
94
+ [x - halfW, y - halfH],
95
+ [x + halfW, y - halfH],
96
+ [x - halfW, y + halfH],
97
+ [x + halfW, y + halfH]
98
+ ]
99
+ };
100
+ };
101
+ //#endregion
102
+ export { emitLabelPrimitive, tForLabelPosition };
@@ -0,0 +1,8 @@
1
+ import { IRStep } from '../../ir';
2
+ import { NodeLayout } from '../node';
3
+ /**
4
+ * relative/relativeAccumulate 目标解析为绝对 Position(step kind 不变,to 全为绝对坐标)
5
+ * @description relative 不更新 prevEnd(TikZ `+`),relativeAccumulate 更新(TikZ `++`)。prevEnd 推进:有 to 的 kind 用 refPointOfTarget(to);arc 用 arcEndPoint;circlePath/ellipsePath/cycle 不变。首步 relative 时 prevEnd 回退 [0,0];解析失败保持原 step
6
+ */
7
+ export declare const normalizeRelativeTargets: (steps: ReadonlyArray<IRStep>, nodeIndex: Map<string, NodeLayout>) => Array<IRStep>;
8
+ //# sourceMappingURL=relative.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relative.d.ts","sourceRoot":"","sources":["../../../../src/compile/path/relative.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAc,MAAM,EAAY,MAAM,UAAU,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAG1C;;;GAGG;AACH,eAAO,MAAM,wBAAwB,GACnC,OAAO,aAAa,CAAC,MAAM,CAAC,EAC5B,WAAW,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,KACjC,KAAK,CAAC,MAAM,CA0Dd,CAAC"}
@@ -0,0 +1,48 @@
1
+ import { arcEndPoint } from "../../geometry/arc.js";
2
+ import { refPointOfTarget } from "./anchor.js";
3
+ //#region src/compile/path/relative.ts
4
+ /**
5
+ * relative/relativeAccumulate 目标解析为绝对 Position(step kind 不变,to 全为绝对坐标)
6
+ * @description relative 不更新 prevEnd(TikZ `+`),relativeAccumulate 更新(TikZ `++`)。prevEnd 推进:有 to 的 kind 用 refPointOfTarget(to);arc 用 arcEndPoint;circlePath/ellipsePath/cycle 不变。首步 relative 时 prevEnd 回退 [0,0];解析失败保持原 step
7
+ */
8
+ var normalizeRelativeTargets = (steps, nodeIndex) => {
9
+ let prevEnd = null;
10
+ const out = [];
11
+ for (const step of steps) {
12
+ if (step.kind === "cycle") {
13
+ out.push(step);
14
+ continue;
15
+ }
16
+ if (step.kind === "circlePath" || step.kind === "ellipsePath") {
17
+ out.push(step);
18
+ continue;
19
+ }
20
+ if (step.kind === "arc") {
21
+ out.push(step);
22
+ if (prevEnd) prevEnd = arcEndPoint(prevEnd, step.radius, step.endAngle);
23
+ continue;
24
+ }
25
+ const original = step.to;
26
+ let resolvedTo = original;
27
+ let updatePrevEnd = true;
28
+ if (typeof original === "object" && !Array.isArray(original) && "relative" in original) {
29
+ const ref = prevEnd ?? [0, 0];
30
+ resolvedTo = [ref[0] + original.relative[0], ref[1] + original.relative[1]];
31
+ updatePrevEnd = false;
32
+ } else if (typeof original === "object" && !Array.isArray(original) && "relativeAccumulate" in original) {
33
+ const ref = prevEnd ?? [0, 0];
34
+ resolvedTo = [ref[0] + original.relativeAccumulate[0], ref[1] + original.relativeAccumulate[1]];
35
+ }
36
+ out.push({
37
+ ...step,
38
+ to: resolvedTo
39
+ });
40
+ if (updatePrevEnd) {
41
+ const pos = refPointOfTarget(resolvedTo, nodeIndex);
42
+ if (pos) prevEnd = pos;
43
+ }
44
+ }
45
+ return out;
46
+ };
47
+ //#endregion
48
+ export { normalizeRelativeTargets };
@@ -0,0 +1,24 @@
1
+ import { IRArrowDetail } from '../../ir';
2
+ import { ArrowEndSpec, PathCommand } from '../../primitive';
3
+ /** IR path-level `arrow` + `arrowDetail` → PathPrim 起末视觉规格 */
4
+ export declare const arrowMarkers: (arrow: "none" | "->" | "<-" | "<->" | undefined, detail: IRArrowDetail | undefined) => {
5
+ arrowStart?: ArrowEndSpec;
6
+ arrowEnd?: ArrowEndSpec;
7
+ };
8
+ /**
9
+ * 端点级 shrink(strokeWidth 倍):line 末端朝起点缩这么多,让 marker apex 落回原 target
10
+ * @description 不分实心/空心:所有 shape 都让 line 端点接在箭头尾部、apex 顶端仍贴原 target。低 opacity 下不会再透出 line。viewBox=10,shrink = (apex.x - refX) × length × scale / 10(strokeWidth 倍)。
11
+ *
12
+ * 几何对齐(必须与 react/render/arrowMarkers.tsx 中 renderInner 的 refX 一致):
13
+ * - `normal` / `diamond` / `circle`:apex 在 viewBox x=10、back 外缘 x=0 → refX=0,shrink = length × scale
14
+ * - `stealth`:apex x=10、V tip x=3(line 嵌进 V 凹口)→ refX=3,shrink = 0.7 × length × scale
15
+ * - `open` / `openDiamond`:apex x=9、back stroke 外缘 x = 1 - lineWidth/2 → refX = 1 - lineWidth/2,shrink = (8 + lineWidth/2) × length × scale / 10
16
+ * - `openCircle`:apex 外缘右 x ≈ 10、back 外缘左 x = 0.75 - lineWidth/2 → refX = 0.75 - lineWidth/2,shrink ≈ length × scale
17
+ */
18
+ export declare const computeShrink: (spec: ArrowEndSpec) => number;
19
+ /**
20
+ * 按 shape + spec(length / scale / lineWidth)把首/末段端点向内缩短
21
+ * @description 让 line 端点接在 hollow arrow 尾部外缘、不贯穿 back outline;shrink=0 的实心 shape 跳过。in-place 改写 commands 数组
22
+ */
23
+ export declare const applyArrowShrinks: (commands: Array<PathCommand>, shrinkStart: number, shrinkEnd: number, strokeWidth: number, round: (n: number) => number) => void;
24
+ //# sourceMappingURL=shrink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shrink.d.ts","sourceRoot":"","sources":["../../../../src/compile/path/shrink.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAgC,MAAM,UAAU,CAAC;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAkCjE,8DAA8D;AAC9D,eAAO,MAAM,YAAY,GACvB,OAAO,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,SAAS,EAC/C,QAAQ,aAAa,GAAG,SAAS,KAChC;IAAE,UAAU,CAAC,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,EAAE,YAAY,CAAA;CAatD,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,YAAY,KAAG,MAWlD,CAAC;AAiDF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAC5B,UAAU,KAAK,CAAC,WAAW,CAAC,EAC5B,aAAa,MAAM,EACnB,WAAW,MAAM,EACjB,aAAa,MAAM,EACnB,OAAO,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,KAC3B,IA4CF,CAAC"}
@@ -0,0 +1,136 @@
1
+ import { HOLLOW_ARROW_SHAPES } from "../../ir/path/arrow.js";
2
+ import { shiftToward } from "./anchor.js";
3
+ //#region src/compile/path/shrink.ts
4
+ /**
5
+ * 端点级 spec:顶层默认 ⊕ end-side override(逐字段 merge)
6
+ * @description 缺省字段继承顶层(不是"完全替换");空心 shape 上 fill 字段被丢(silent no-op)
7
+ */
8
+ var resolveArrowEndSpec = (topLevel, endSide) => {
9
+ const baseShape = endSide?.shape ?? topLevel.shape ?? "normal";
10
+ const out = { shape: baseShape };
11
+ const scale = endSide?.scale ?? topLevel.scale;
12
+ if (scale !== void 0) out.scale = scale;
13
+ const length = endSide?.length ?? topLevel.length;
14
+ if (length !== void 0) out.length = length;
15
+ const width = endSide?.width ?? topLevel.width;
16
+ if (width !== void 0) out.width = width;
17
+ const color = endSide?.color ?? topLevel.color;
18
+ if (color !== void 0) out.color = color;
19
+ const opacity = endSide?.opacity ?? topLevel.opacity;
20
+ if (opacity !== void 0) out.opacity = opacity;
21
+ const lineWidth = endSide?.lineWidth ?? topLevel.lineWidth;
22
+ if (lineWidth !== void 0) out.lineWidth = lineWidth;
23
+ if (!HOLLOW_ARROW_SHAPES.has(baseShape)) {
24
+ const fill = endSide?.fill ?? topLevel.fill;
25
+ if (fill !== void 0) out.fill = fill;
26
+ }
27
+ return out;
28
+ };
29
+ /** IR path-level `arrow` + `arrowDetail` → PathPrim 起末视觉规格 */
30
+ var arrowMarkers = (arrow, detail) => {
31
+ if (!arrow || arrow === "none") return {};
32
+ const top = detail ?? {};
33
+ const startSpec = resolveArrowEndSpec(top, top.start);
34
+ const endSpec = resolveArrowEndSpec(top, top.end);
35
+ switch (arrow) {
36
+ case "->": return { arrowEnd: endSpec };
37
+ case "<-": return { arrowStart: startSpec };
38
+ case "<->": return {
39
+ arrowStart: startSpec,
40
+ arrowEnd: endSpec
41
+ };
42
+ }
43
+ };
44
+ /**
45
+ * 端点级 shrink(strokeWidth 倍):line 末端朝起点缩这么多,让 marker apex 落回原 target
46
+ * @description 不分实心/空心:所有 shape 都让 line 端点接在箭头尾部、apex 顶端仍贴原 target。低 opacity 下不会再透出 line。viewBox=10,shrink = (apex.x - refX) × length × scale / 10(strokeWidth 倍)。
47
+ *
48
+ * 几何对齐(必须与 react/render/arrowMarkers.tsx 中 renderInner 的 refX 一致):
49
+ * - `normal` / `diamond` / `circle`:apex 在 viewBox x=10、back 外缘 x=0 → refX=0,shrink = length × scale
50
+ * - `stealth`:apex x=10、V tip x=3(line 嵌进 V 凹口)→ refX=3,shrink = 0.7 × length × scale
51
+ * - `open` / `openDiamond`:apex x=9、back stroke 外缘 x = 1 - lineWidth/2 → refX = 1 - lineWidth/2,shrink = (8 + lineWidth/2) × length × scale / 10
52
+ * - `openCircle`:apex 外缘右 x ≈ 10、back 外缘左 x = 0.75 - lineWidth/2 → refX = 0.75 - lineWidth/2,shrink ≈ length × scale
53
+ */
54
+ var computeShrink = (spec) => {
55
+ const length = (spec.length ?? 6) * (spec.scale ?? 1);
56
+ if (HOLLOW_ARROW_SHAPES.has(spec.shape)) {
57
+ if (spec.shape === "openCircle") return length;
58
+ return (8 + (spec.lineWidth ?? 1.5) / 2) * length / 10;
59
+ }
60
+ if (spec.shape === "stealth") return 7 * length / 10;
61
+ return length;
62
+ };
63
+ /** 取一个 PathCommand 末端 endpoint(move/line/quad/cubic → to;arc/ellipseArc → polar(end);close 无端点) */
64
+ var endpointOf = (cmd) => {
65
+ switch (cmd.kind) {
66
+ case "move":
67
+ case "line":
68
+ case "quad":
69
+ case "cubic": return [cmd.to[0], cmd.to[1]];
70
+ case "arc": {
71
+ const rad = cmd.endAngle * Math.PI / 180;
72
+ return [cmd.center[0] + Math.cos(rad) * cmd.radius, cmd.center[1] + Math.sin(rad) * cmd.radius];
73
+ }
74
+ case "ellipseArc": {
75
+ const rad = cmd.endAngle * Math.PI / 180;
76
+ return [cmd.center[0] + Math.cos(rad) * cmd.radiusX, cmd.center[1] + Math.sin(rad) * cmd.radiusY];
77
+ }
78
+ case "close": return null;
79
+ }
80
+ };
81
+ /** 改写一个 PathCommand 的 endpoint(用于 shrink) */
82
+ var setEndpoint = (commands, idx, newPt, round) => {
83
+ const cmd = commands[idx];
84
+ if (cmd.kind === "close") return;
85
+ const rp = [round(newPt[0]), round(newPt[1])];
86
+ if (cmd.kind === "move" || cmd.kind === "line") commands[idx] = {
87
+ ...cmd,
88
+ to: rp
89
+ };
90
+ else if (cmd.kind === "quad") commands[idx] = {
91
+ ...cmd,
92
+ to: rp
93
+ };
94
+ else if (cmd.kind === "cubic") commands[idx] = {
95
+ ...cmd,
96
+ to: rp
97
+ };
98
+ };
99
+ /**
100
+ * 按 shape + spec(length / scale / lineWidth)把首/末段端点向内缩短
101
+ * @description 让 line 端点接在 hollow arrow 尾部外缘、不贯穿 back outline;shrink=0 的实心 shape 跳过。in-place 改写 commands 数组
102
+ */
103
+ var applyArrowShrinks = (commands, shrinkStart, shrinkEnd, strokeWidth, round) => {
104
+ if (shrinkStart > 0) {
105
+ const firstIdx = commands.findIndex((o) => o.kind === "move");
106
+ if (firstIdx >= 0) {
107
+ const cur = commands[firstIdx];
108
+ const nextIdx = commands.findIndex((o, idx) => idx > firstIdx && o.kind !== "close");
109
+ if (cur.kind === "move" && nextIdx >= 0) {
110
+ const nextPt = endpointOf(commands[nextIdx]);
111
+ if (nextPt) setEndpoint(commands, firstIdx, shiftToward([cur.to[0], cur.to[1]], nextPt, shrinkStart * strokeWidth), round);
112
+ }
113
+ }
114
+ }
115
+ if (shrinkEnd > 0) {
116
+ let lastIdx = -1;
117
+ for (let i = commands.length - 1; i >= 0; i--) if (commands[i].kind !== "close") {
118
+ lastIdx = i;
119
+ break;
120
+ }
121
+ if (lastIdx > 0) {
122
+ let prevIdx = lastIdx - 1;
123
+ while (prevIdx >= 0 && commands[prevIdx].kind === "close") prevIdx--;
124
+ if (prevIdx >= 0) {
125
+ const curPt = endpointOf(commands[lastIdx]);
126
+ const prevPt = endpointOf(commands[prevIdx]);
127
+ if (curPt && prevPt) {
128
+ const shifted = shiftToward(curPt, prevPt, shrinkEnd * strokeWidth);
129
+ setEndpoint(commands, lastIdx, shifted, round);
130
+ }
131
+ }
132
+ }
133
+ }
134
+ };
135
+ //#endregion
136
+ export { applyArrowShrinks, arrowMarkers, computeShrink };
@@ -0,0 +1,15 @@
1
+ import { ArrowEndSpec, PathCommand, PathPrim, ScenePrimitive } from '../../primitive';
2
+ /** baseProps:除 commands/markers 外 PathPrim 公共属性集合(多 sub-path 复用) */
3
+ export type PathBaseProps = Omit<PathPrim, 'type' | 'commands' | 'arrowStart' | 'arrowEnd'>;
4
+ /**
5
+ * 多 sub-path + 有箭头:按 sub-path split 成多个 PathPrim,仅首段挂 arrowStart / 末段挂 arrowEnd,包进 GroupPrim
6
+ * @description SVG marker 按每个 sub-path 单独贴会在中间节点视觉错乱,故仅首末段挂;单 sub-path 或无箭头直接产一个 PathPrim
7
+ */
8
+ export declare const splitSubPathsForMarkers: (commands: Array<PathCommand>, baseProps: PathBaseProps, markers: {
9
+ arrowStart?: ArrowEndSpec;
10
+ arrowEnd?: ArrowEndSpec;
11
+ }) => {
12
+ primitive: ScenePrimitive;
13
+ isGrouped: boolean;
14
+ };
15
+ //# sourceMappingURL=split.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"split.d.ts","sourceRoot":"","sources":["../../../../src/compile/path/split.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAE3F,oEAAoE;AACpE,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,YAAY,GAAG,UAAU,CAAC,CAAC;AAE5F;;;GAGG;AACH,eAAO,MAAM,uBAAuB,GAClC,UAAU,KAAK,CAAC,WAAW,CAAC,EAC5B,WAAW,aAAa,EACxB,SAAS;IAAE,UAAU,CAAC,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,EAAE,YAAY,CAAA;CAAE,KAC9D;IAAE,SAAS,EAAE,cAAc,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CA4CjD,CAAC"}
@@ -0,0 +1,46 @@
1
+ //#region src/compile/path/split.ts
2
+ /**
3
+ * 多 sub-path + 有箭头:按 sub-path split 成多个 PathPrim,仅首段挂 arrowStart / 末段挂 arrowEnd,包进 GroupPrim
4
+ * @description SVG marker 按每个 sub-path 单独贴会在中间节点视觉错乱,故仅首末段挂;单 sub-path 或无箭头直接产一个 PathPrim
5
+ */
6
+ var splitSubPathsForMarkers = (commands, baseProps, markers) => {
7
+ const hasArrows = !!markers.arrowStart || !!markers.arrowEnd;
8
+ const subPathStarts = [];
9
+ commands.forEach((cmd, idx) => {
10
+ if (cmd.kind === "move") subPathStarts.push(idx);
11
+ });
12
+ if (!hasArrows || subPathStarts.length <= 1) return {
13
+ primitive: {
14
+ type: "path",
15
+ commands,
16
+ ...baseProps,
17
+ ...markers
18
+ },
19
+ isGrouped: false
20
+ };
21
+ const subPathSlices = [];
22
+ for (let s = 0; s < subPathStarts.length; s++) {
23
+ const start = subPathStarts[s];
24
+ const end = s + 1 < subPathStarts.length ? subPathStarts[s + 1] : commands.length;
25
+ subPathSlices.push(commands.slice(start, end));
26
+ }
27
+ return {
28
+ primitive: {
29
+ type: "group",
30
+ children: subPathSlices.map((sub, i) => {
31
+ const isFirst = i === 0;
32
+ const isLast = i === subPathSlices.length - 1;
33
+ return {
34
+ type: "path",
35
+ commands: sub,
36
+ ...baseProps,
37
+ ...isFirst && markers.arrowStart ? { arrowStart: markers.arrowStart } : {},
38
+ ...isLast && markers.arrowEnd ? { arrowEnd: markers.arrowEnd } : {}
39
+ };
40
+ })
41
+ },
42
+ isGrouped: true
43
+ };
44
+ };
45
+ //#endregion
46
+ export { splitSubPathsForMarkers };
@@ -25,6 +25,9 @@ export type TextMetrics = {
25
25
  * @description @retikz/react: canvas measureText;@retikz/ssr: opentype.js/fontkit;@retikz/canvas: ctx.measureText
26
26
  */
27
27
  export type TextMeasurer = (text: string, font: FontSpec) => TextMetrics;
28
- /** 默认 fallback 度量:基于平均字宽估算,不准但保证可运行 */
28
+ /**
29
+ * 默认 fallback 度量:基于平均字宽估算,不准但保证可运行
30
+ * @description size=0 → 退化返回 (0, 0)(与 text='' 一致);负 size 或 NaN size → throw(非法输入早 fail,避免 NaN 噪音传播到 Scene)
31
+ */
29
32
  export declare const fallbackMeasurer: TextMeasurer;
30
33
  //# sourceMappingURL=text-metrics.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"text-metrics.d.ts","sourceRoot":"","sources":["../../../src/compile/text-metrics.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,MAAM,MAAM,QAAQ,GAAG;IACrB,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,mCAAmC;IACnC,KAAK,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;CACzC,CAAC;AAEF,uCAAuC;AACvC,MAAM,MAAM,WAAW,GAAG;IACxB,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,KAAK,WAAW,CAAC;AAEzE,uCAAuC;AACvC,eAAO,MAAM,gBAAgB,EAAE,YAG7B,CAAC"}
1
+ {"version":3,"file":"text-metrics.d.ts","sourceRoot":"","sources":["../../../src/compile/text-metrics.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,MAAM,MAAM,QAAQ,GAAG;IACrB,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,mCAAmC;IACnC,KAAK,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;CACzC,CAAC;AAEF,uCAAuC;AACvC,MAAM,MAAM,WAAW,GAAG;IACxB,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,KAAK,WAAW,CAAC;AAEzE;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,YAU9B,CAAC"}
@@ -1,8 +1,14 @@
1
1
  //#region src/compile/text-metrics.ts
2
- /** 默认 fallback 度量:基于平均字宽估算,不准但保证可运行 */
3
- var fallbackMeasurer = (text, font) => ({
4
- width: text.length * font.size * .55,
5
- height: font.size * 1.2
6
- });
2
+ /**
3
+ * 默认 fallback 度量:基于平均字宽估算,不准但保证可运行
4
+ * @description size=0 → 退化返回 (0, 0)(与 text='' 一致);负 size NaN size → throw(非法输入早 fail,避免 NaN 噪音传播到 Scene)
5
+ */
6
+ var fallbackMeasurer = (text, font) => {
7
+ if (Number.isNaN(font.size) || font.size < 0) throw new Error(`fallbackMeasurer: invalid font.size '${font.size}'; must be a non-negative finite number`);
8
+ return {
9
+ width: text.length * font.size * .55,
10
+ height: font.size * 1.2
11
+ };
12
+ };
7
13
  //#endregion
8
14
  export { fallbackMeasurer };
@@ -0,0 +1,21 @@
1
+ import { Position } from './point';
2
+ /** 任何"中心 + 可选旋转"形状的几何契约(rect / circle / ellipse / diamond 共用) */
3
+ export type CenteredShape = {
4
+ /** 中心横坐标 */
5
+ x: number;
6
+ /** 中心纵坐标 */
7
+ y: number;
8
+ /** 绕中心旋转弧度(可选,0 / 缺省 = 不旋转) */
9
+ rotate?: number;
10
+ };
11
+ /**
12
+ * 本地坐标(以中心为原点)→ 世界坐标
13
+ * @description rotate=0 / 缺省时退化为平移;非零时按右手系绕中心旋转后再平移
14
+ */
15
+ export declare const localToWorld: (s: CenteredShape, local: Position) => Position;
16
+ /**
17
+ * 世界坐标 → 本地坐标(`localToWorld` 逆变换)
18
+ * @description 先反平移到中心、再反旋转回本地基;旋转矩阵转置即逆
19
+ */
20
+ export declare const worldToLocal: (s: CenteredShape, world: Position) => Position;
21
+ //# sourceMappingURL=_transform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_transform.d.ts","sourceRoot":"","sources":["../../../src/geometry/_transform.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,iEAAiE;AACjE,MAAM,MAAM,aAAa,GAAG;IAC1B,YAAY;IACZ,CAAC,EAAE,MAAM,CAAC;IACV,YAAY;IACZ,CAAC,EAAE,MAAM,CAAC;IACV,+BAA+B;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,GAAG,aAAa,EAAE,OAAO,QAAQ,KAAG,QAShE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,GAAG,aAAa,EAAE,OAAO,QAAQ,KAAG,QAQhE,CAAC"}
@@ -0,0 +1,27 @@
1
+ //#region src/geometry/_transform.ts
2
+ /**
3
+ * 本地坐标(以中心为原点)→ 世界坐标
4
+ * @description rotate=0 / 缺省时退化为平移;非零时按右手系绕中心旋转后再平移
5
+ */
6
+ var localToWorld = (s, local) => {
7
+ const angle = s.rotate ?? 0;
8
+ if (angle === 0) return [s.x + local[0], s.y + local[1]];
9
+ const cos = Math.cos(angle);
10
+ const sin = Math.sin(angle);
11
+ return [s.x + local[0] * cos - local[1] * sin, s.y + local[0] * sin + local[1] * cos];
12
+ };
13
+ /**
14
+ * 世界坐标 → 本地坐标(`localToWorld` 逆变换)
15
+ * @description 先反平移到中心、再反旋转回本地基;旋转矩阵转置即逆
16
+ */
17
+ var worldToLocal = (s, world) => {
18
+ const tx = world[0] - s.x;
19
+ const ty = world[1] - s.y;
20
+ const angle = s.rotate ?? 0;
21
+ if (angle === 0) return [tx, ty];
22
+ const cos = Math.cos(angle);
23
+ const sin = Math.sin(angle);
24
+ return [tx * cos + ty * sin, -tx * sin + ty * cos];
25
+ };
26
+ //#endregion
27
+ export { localToWorld, worldToLocal };
@@ -1,7 +1,7 @@
1
1
  import { Position } from './point';
2
2
  /**
3
3
  * cubic Bezier 拟合 from→to 的弧形 bend
4
- * @description apex offset = chord × tan(bendAngle/2);控制点取 chord 1/3 与 2/3 处沿法向偏移,让 cubic 在 t=0.5 穿过 apex 故 ctlOffset = 4/3 × apexOffset。法向 SVG y-downvisual-left=(dy,-dx)/|chord|,visual-right=(-dy,dx)/|chord|。chord=0 时两控制点都返回 from
4
+ * @description apex offset = chord × tan(bendAngle/2);控制点取 chord 1/3 与 2/3 处沿法向偏移,让 cubic 在 t=0.5 穿过 apex 故 ctlOffset = 4/3 × apexOffset。法向(screen y-down):visual-left=(dy,-dx)/|chord|,visual-right=(-dy,dx)/|chord|。chord=0 时两控制点都返回 from
5
5
  */
6
6
  export declare const bendControlPoints: (from: Position, to: Position, direction: "left" | "right", bendAngle: number) => [Position, Position];
7
7
  //# sourceMappingURL=bend.d.ts.map
@@ -1,7 +1,7 @@
1
1
  //#region src/geometry/bend.ts
2
2
  /**
3
3
  * cubic Bezier 拟合 from→to 的弧形 bend
4
- * @description apex offset = chord × tan(bendAngle/2);控制点取 chord 1/3 与 2/3 处沿法向偏移,让 cubic 在 t=0.5 穿过 apex 故 ctlOffset = 4/3 × apexOffset。法向 SVG y-downvisual-left=(dy,-dx)/|chord|,visual-right=(-dy,dx)/|chord|。chord=0 时两控制点都返回 from
4
+ * @description apex offset = chord × tan(bendAngle/2);控制点取 chord 1/3 与 2/3 处沿法向偏移,让 cubic 在 t=0.5 穿过 apex 故 ctlOffset = 4/3 × apexOffset。法向(screen y-down):visual-left=(dy,-dx)/|chord|,visual-right=(-dy,dx)/|chord|。chord=0 时两控制点都返回 from
5
5
  */
6
6
  var bendControlPoints = (from, to, direction, bendAngle) => {
7
7
  const dx = to[0] - from[0];
@@ -1,4 +1,5 @@
1
1
  import { Position } from './point';
2
+ import { RectAnchor } from './rect';
2
3
  /** 圆形:几何中心 + 半径,预留旋转字段保持与 Rect 同形 API */
3
4
  export type Circle = {
4
5
  x: number;
@@ -8,8 +9,6 @@ export type Circle = {
8
9
  /** 绕中心旋转弧度(圆视觉不变,与 Rect 同形保留) */
9
10
  rotate?: number;
10
11
  };
11
- /** 圆形 9 个标准 anchor(与 RECT_ANCHORS 同名同义,圆周每 45° 等距分布) */
12
- export type CircleAnchor = 'center' | 'north' | 'south' | 'east' | 'west' | 'north-east' | 'north-west' | 'south-east' | 'south-west';
13
12
  /** 圆形相关基础工具 */
14
13
  export declare const circle: {
15
14
  /** 圆心 */
@@ -17,7 +16,7 @@ export declare const circle: {
17
16
  /** 判断点是否在圆内(含边界) */
18
17
  contains: (c: Circle, p: Position) => boolean;
19
18
  /** 9 个标准 anchor 之一的世界坐标 */
20
- anchor: (c: Circle, name: CircleAnchor) => Position;
19
+ anchor: (c: Circle, name: RectAnchor) => Position;
21
20
  /** 从圆心向 toward 方向射线与圆周交点(Path 端点贴 Node 边界用) */
22
21
  boundaryPoint: (c: Circle, toward: Position) => Position;
23
22
  };
@@ -1 +1 @@
1
- {"version":3,"file":"circle.d.ts","sourceRoot":"","sources":["../../../src/geometry/circle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,yCAAyC;AACzC,MAAM,MAAM,MAAM,GAAG;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,SAAS;IACT,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAIF,wDAAwD;AACxD,MAAM,MAAM,YAAY,GACpB,QAAQ,GACR,OAAO,GACP,OAAO,GACP,MAAM,GACN,MAAM,GACN,YAAY,GACZ,YAAY,GACZ,YAAY,GACZ,YAAY,CAAC;AAoBjB,eAAe;AACf,eAAO,MAAM,MAAM;IACjB,SAAS;gBACG,MAAM,KAAG,QAAQ;IAC7B,oBAAoB;kBACN,MAAM,KAAK,QAAQ,KAAG,OAAO;IAI3C,2BAA2B;gBACf,MAAM,QAAQ,YAAY,KAAG,QAAQ;IAsCjD,+CAA+C;uBAC5B,MAAM,UAAU,QAAQ,KAAG,QAAQ;CAOvD,CAAC"}
1
+ {"version":3,"file":"circle.d.ts","sourceRoot":"","sources":["../../../src/geometry/circle.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEzC,yCAAyC;AACzC,MAAM,MAAM,MAAM,GAAG;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,SAAS;IACT,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAIF,eAAe;AACf,eAAO,MAAM,MAAM;IACjB,SAAS;gBACG,MAAM,KAAG,QAAQ;IAC7B,oBAAoB;kBACN,MAAM,KAAK,QAAQ,KAAG,OAAO;IAI3C,2BAA2B;gBACf,MAAM,QAAQ,UAAU,KAAG,QAAQ;IAsC/C,+CAA+C;uBAC5B,MAAM,UAAU,QAAQ,KAAG,QAAQ;CAOvD,CAAC"}
@@ -1,21 +1,6 @@
1
+ import { localToWorld, worldToLocal } from "./_transform.js";
1
2
  //#region src/geometry/circle.ts
2
3
  var SQRT_HALF = Math.SQRT1_2;
3
- var localToWorld = (c, local) => {
4
- const angle = c.rotate ?? 0;
5
- if (angle === 0) return [c.x + local[0], c.y + local[1]];
6
- const cos = Math.cos(angle);
7
- const sin = Math.sin(angle);
8
- return [c.x + local[0] * cos - local[1] * sin, c.y + local[0] * sin + local[1] * cos];
9
- };
10
- var worldToLocal = (c, world) => {
11
- const tx = world[0] - c.x;
12
- const ty = world[1] - c.y;
13
- const angle = c.rotate ?? 0;
14
- if (angle === 0) return [tx, ty];
15
- const cos = Math.cos(angle);
16
- const sin = Math.sin(angle);
17
- return [tx * cos + ty * sin, -tx * sin + ty * cos];
18
- };
19
4
  /** 圆形相关基础工具 */
20
5
  var circle = {
21
6
  /** 圆心 */
@@ -1,4 +1,5 @@
1
1
  import { Position } from './point';
2
+ import { RectAnchor } from './rect';
2
3
  /** 菱形:中心 + halfA/halfB 半轴长 + 可选旋转;顶点在 (±halfA,0) 与 (0,±halfB) */
3
4
  export type Diamond = {
4
5
  x: number;
@@ -10,8 +11,6 @@ export type Diamond = {
10
11
  /** 绕中心旋转弧度 */
11
12
  rotate?: number;
12
13
  };
13
- /** 菱形 9 个标准 anchor(4 顶点 + 4 边中点 + 中心) */
14
- export type DiamondAnchor = 'center' | 'north' | 'south' | 'east' | 'west' | 'north-east' | 'north-west' | 'south-east' | 'south-west';
15
14
  /** 菱形相关基础工具 */
16
15
  export declare const diamond: {
17
16
  /** 中心 */
@@ -19,7 +18,7 @@ export declare const diamond: {
19
18
  /** 点是否在菱形内(含边界,含旋转);方程 |x|/halfA + |y|/halfB ≤ 1 */
20
19
  contains: (d: Diamond, p: Position) => boolean;
21
20
  /** 9 个 anchor:N/S/E/W=顶点,NE/NW/SE/SW=边中点,center=中心 */
22
- anchor: (d: Diamond, name: DiamondAnchor) => Position;
21
+ anchor: (d: Diamond, name: RectAnchor) => Position;
23
22
  /**
24
23
  * 从中心向 toward 方向射线与菱形 4 边的交点
25
24
  * @description 菱形方程 |x|/halfA + |y|/halfB = 1;沿方向 (lx,ly) 缩放 t 倍命中:t = 1 / (|lx|/halfA + |ly|/halfB)
@@ -1 +1 @@
1
- {"version":3,"file":"diamond.d.ts","sourceRoot":"","sources":["../../../src/geometry/diamond.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,iEAAiE;AACjE,MAAM,MAAM,OAAO,GAAG;IACpB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,yBAAyB;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,cAAc;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,yCAAyC;AACzC,MAAM,MAAM,aAAa,GACrB,QAAQ,GACR,OAAO,GACP,OAAO,GACP,MAAM,GACN,MAAM,GACN,YAAY,GACZ,YAAY,GACZ,YAAY,GACZ,YAAY,CAAC;AAoBjB,eAAe;AACf,eAAO,MAAM,OAAO;IAClB,SAAS;gBACG,OAAO,KAAG,QAAQ;IAC9B,oDAAoD;kBACtC,OAAO,KAAK,QAAQ,KAAG,OAAO;IAI5C,sDAAsD;gBAC1C,OAAO,QAAQ,aAAa,KAAG,QAAQ;IAqCrD;;;OAGG;uBACkB,OAAO,UAAU,QAAQ,KAAG,QAAQ;CAOxD,CAAC"}
1
+ {"version":3,"file":"diamond.d.ts","sourceRoot":"","sources":["../../../src/geometry/diamond.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEzC,iEAAiE;AACjE,MAAM,MAAM,OAAO,GAAG;IACpB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,yBAAyB;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,cAAc;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,eAAe;AACf,eAAO,MAAM,OAAO;IAClB,SAAS;gBACG,OAAO,KAAG,QAAQ;IAC9B,oDAAoD;kBACtC,OAAO,KAAK,QAAQ,KAAG,OAAO;IAI5C,sDAAsD;gBAC1C,OAAO,QAAQ,UAAU,KAAG,QAAQ;IAqClD;;;OAGG;uBACkB,OAAO,UAAU,QAAQ,KAAG,QAAQ;CAOxD,CAAC"}
@@ -1,20 +1,5 @@
1
+ import { localToWorld, worldToLocal } from "./_transform.js";
1
2
  //#region src/geometry/diamond.ts
2
- var localToWorld = (d, local) => {
3
- const angle = d.rotate ?? 0;
4
- if (angle === 0) return [d.x + local[0], d.y + local[1]];
5
- const cos = Math.cos(angle);
6
- const sin = Math.sin(angle);
7
- return [d.x + local[0] * cos - local[1] * sin, d.y + local[0] * sin + local[1] * cos];
8
- };
9
- var worldToLocal = (d, world) => {
10
- const tx = world[0] - d.x;
11
- const ty = world[1] - d.y;
12
- const angle = d.rotate ?? 0;
13
- if (angle === 0) return [tx, ty];
14
- const cos = Math.cos(angle);
15
- const sin = Math.sin(angle);
16
- return [tx * cos + ty * sin, -tx * sin + ty * cos];
17
- };
18
3
  /** 菱形相关基础工具 */
19
4
  var diamond = {
20
5
  /** 中心 */
@@ -1,4 +1,5 @@
1
1
  import { Position } from './point';
2
+ import { RectAnchor } from './rect';
2
3
  /** 椭圆:中心 + 半长轴 rx / 半短轴 ry + 可选旋转 */
3
4
  export type Ellipse = {
4
5
  x: number;
@@ -10,8 +11,6 @@ export type Ellipse = {
10
11
  /** 绕中心旋转弧度 */
11
12
  rotate?: number;
12
13
  };
13
- /** 椭圆 9 个标准 anchor(与 RECT_ANCHORS 同名同义) */
14
- export type EllipseAnchor = 'center' | 'north' | 'south' | 'east' | 'west' | 'north-east' | 'north-west' | 'south-east' | 'south-west';
15
14
  /** 椭圆相关基础工具 */
16
15
  export declare const ellipse: {
17
16
  /** 中心 */
@@ -22,7 +21,7 @@ export declare const ellipse: {
22
21
  * 9 个 anchor 的世界坐标
23
22
  * @description 对角(NE/NW/SE/SW)取参数曲线 t=π/4 处 (rx/√2, ry/√2),与 TikZ 椭圆 anchor 参数等分约定一致
24
23
  */
25
- anchor: (e: Ellipse, name: EllipseAnchor) => Position;
24
+ anchor: (e: Ellipse, name: RectAnchor) => Position;
26
25
  /**
27
26
  * 从中心向 toward 方向射线与椭圆交点
28
27
  * @description 椭圆方程 (x/rx)² + (y/ry)² = 1;沿 (lx,ly) 缩放 t 倍命中 t = 1 / √((lx/rx)² + (ly/ry)²)