@retikz/core 0.3.0-alpha.3 → 0.3.0-alpha.4
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 +41 -41
- package/dist/es/compile/anchor-cache.d.ts +5 -3
- package/dist/es/compile/anchor-cache.d.ts.map +1 -1
- package/dist/es/compile/anchor-cache.js +14 -10
- package/dist/es/compile/boundary.d.ts +19 -0
- package/dist/es/compile/boundary.d.ts.map +1 -0
- package/dist/es/compile/boundary.js +64 -0
- package/dist/es/compile/compile.d.ts.map +1 -1
- package/dist/es/compile/compile.js +14 -2
- package/dist/es/compile/node.d.ts +24 -8
- package/dist/es/compile/node.d.ts.map +1 -1
- package/dist/es/compile/node.js +100 -16
- package/dist/es/compile/path/anchor.d.ts.map +1 -1
- package/dist/es/compile/path/anchor.js +7 -6
- package/dist/es/compile/path/index.d.ts.map +1 -1
- package/dist/es/compile/path/index.js +5 -3
- package/dist/es/compile/path/relative.js +1 -1
- package/dist/es/compile/scope.d.ts.map +1 -1
- package/dist/es/compile/scope.js +2 -1
- package/dist/es/geometry/arc.d.ts +14 -0
- package/dist/es/geometry/arc.d.ts.map +1 -1
- package/dist/es/geometry/arc.js +65 -9
- package/dist/es/geometry/index.d.ts +1 -0
- package/dist/es/geometry/index.d.ts.map +1 -1
- package/dist/es/geometry/rect.d.ts +2 -2
- package/dist/es/geometry/rect.d.ts.map +1 -1
- package/dist/es/geometry/rect.js +3 -3
- package/dist/es/geometry/roundedContour.d.ts +88 -0
- package/dist/es/geometry/roundedContour.d.ts.map +1 -0
- package/dist/es/geometry/roundedContour.js +417 -0
- package/dist/es/index.d.ts +6 -5
- package/dist/es/index.d.ts.map +1 -1
- package/dist/es/index.js +9 -6
- package/dist/es/ir/boundary.d.ts +25 -0
- package/dist/es/ir/boundary.d.ts.map +1 -0
- package/dist/es/ir/boundary.js +14 -0
- package/dist/es/ir/index.d.ts +2 -0
- package/dist/es/ir/index.d.ts.map +1 -1
- package/dist/es/ir/node.d.ts +43 -7
- package/dist/es/ir/node.d.ts.map +1 -1
- package/dist/es/ir/node.js +8 -3
- package/dist/es/ir/path/arrow.d.ts +12 -12
- package/dist/es/ir/path/path.d.ts +490 -147
- package/dist/es/ir/path/path.d.ts.map +1 -1
- package/dist/es/ir/path/path.js +2 -0
- package/dist/es/ir/path/step.d.ts +674 -154
- package/dist/es/ir/path/step.d.ts.map +1 -1
- package/dist/es/ir/path/step.js +2 -2
- package/dist/es/ir/path/target.d.ts +43 -8
- package/dist/es/ir/path/target.d.ts.map +1 -1
- package/dist/es/ir/path/target.js +4 -5
- package/dist/es/ir/scope.d.ts +843 -234
- package/dist/es/ir/scope.d.ts.map +1 -1
- package/dist/es/ir/scope.js +6 -2
- package/dist/es/ir/shape.d.ts +14 -0
- package/dist/es/ir/shape.d.ts.map +1 -0
- package/dist/es/ir/shape.js +9 -0
- package/dist/es/parsers/parseNodeTarget.d.ts.map +1 -1
- package/dist/es/parsers/parseNodeTarget.js +4 -2
- package/dist/es/primitive/ellipse.d.ts +3 -0
- package/dist/es/primitive/ellipse.d.ts.map +1 -1
- package/dist/es/primitive/group.d.ts +3 -0
- package/dist/es/primitive/group.d.ts.map +1 -1
- package/dist/es/primitive/path.d.ts +3 -0
- package/dist/es/primitive/path.d.ts.map +1 -1
- package/dist/es/primitive/rect.d.ts +3 -0
- package/dist/es/primitive/rect.d.ts.map +1 -1
- package/dist/es/primitive/text.d.ts +3 -0
- package/dist/es/primitive/text.d.ts.map +1 -1
- package/dist/es/shapes/_contour.d.ts +19 -0
- package/dist/es/shapes/_contour.d.ts.map +1 -0
- package/dist/es/shapes/_contour.js +60 -0
- package/dist/es/shapes/_shared.d.ts +54 -0
- package/dist/es/shapes/_shared.d.ts.map +1 -1
- package/dist/es/shapes/_shared.js +68 -1
- package/dist/es/shapes/arc.d.ts +8 -0
- package/dist/es/shapes/arc.d.ts.map +1 -0
- package/dist/es/shapes/arc.js +104 -0
- package/dist/es/shapes/define.d.ts +13 -0
- package/dist/es/shapes/define.d.ts.map +1 -0
- package/dist/es/shapes/define.js +13 -0
- package/dist/es/shapes/ellipse.d.ts +5 -4
- package/dist/es/shapes/ellipse.d.ts.map +1 -1
- package/dist/es/shapes/ellipse.js +15 -7
- package/dist/es/shapes/index.d.ts +9 -6
- package/dist/es/shapes/index.d.ts.map +1 -1
- package/dist/es/shapes/index.js +10 -5
- package/dist/es/shapes/polygon.d.ts +13 -0
- package/dist/es/shapes/polygon.d.ts.map +1 -0
- package/dist/es/shapes/polygon.js +104 -0
- package/dist/es/shapes/rectangle.d.ts +7 -5
- package/dist/es/shapes/rectangle.d.ts.map +1 -1
- package/dist/es/shapes/rectangle.js +37 -8
- package/dist/es/shapes/sector.d.ts +9 -0
- package/dist/es/shapes/sector.d.ts.map +1 -0
- package/dist/es/shapes/sector.js +143 -0
- package/dist/es/shapes/star.d.ts +15 -0
- package/dist/es/shapes/star.d.ts.map +1 -0
- package/dist/es/shapes/star.js +113 -0
- package/dist/es/shapes/types.d.ts +47 -14
- package/dist/es/shapes/types.d.ts.map +1 -1
- package/dist/lib/compile/anchor-cache.cjs +14 -10
- package/dist/lib/compile/anchor-cache.d.ts +5 -3
- package/dist/lib/compile/anchor-cache.d.ts.map +1 -1
- package/dist/lib/compile/boundary.cjs +65 -0
- package/dist/lib/compile/boundary.d.ts +19 -0
- package/dist/lib/compile/boundary.d.ts.map +1 -0
- package/dist/lib/compile/compile.cjs +14 -2
- package/dist/lib/compile/compile.d.ts.map +1 -1
- package/dist/lib/compile/node.cjs +100 -16
- package/dist/lib/compile/node.d.ts +24 -8
- package/dist/lib/compile/node.d.ts.map +1 -1
- package/dist/lib/compile/path/anchor.cjs +7 -6
- package/dist/lib/compile/path/anchor.d.ts.map +1 -1
- package/dist/lib/compile/path/index.cjs +5 -3
- package/dist/lib/compile/path/index.d.ts.map +1 -1
- package/dist/lib/compile/path/relative.cjs +1 -1
- package/dist/lib/compile/scope.cjs +2 -1
- package/dist/lib/compile/scope.d.ts.map +1 -1
- package/dist/lib/geometry/arc.cjs +66 -8
- package/dist/lib/geometry/arc.d.ts +14 -0
- package/dist/lib/geometry/arc.d.ts.map +1 -1
- package/dist/lib/geometry/index.d.ts +1 -0
- package/dist/lib/geometry/index.d.ts.map +1 -1
- package/dist/lib/geometry/rect.cjs +3 -3
- package/dist/lib/geometry/rect.d.ts +2 -2
- package/dist/lib/geometry/rect.d.ts.map +1 -1
- package/dist/lib/geometry/roundedContour.cjs +418 -0
- package/dist/lib/geometry/roundedContour.d.ts +88 -0
- package/dist/lib/geometry/roundedContour.d.ts.map +1 -0
- package/dist/lib/index.cjs +14 -7
- package/dist/lib/index.d.ts +6 -5
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/ir/boundary.cjs +15 -0
- package/dist/lib/ir/boundary.d.ts +25 -0
- package/dist/lib/ir/boundary.d.ts.map +1 -0
- package/dist/lib/ir/index.d.ts +2 -0
- package/dist/lib/ir/index.d.ts.map +1 -1
- package/dist/lib/ir/node.cjs +8 -3
- package/dist/lib/ir/node.d.ts +43 -7
- package/dist/lib/ir/node.d.ts.map +1 -1
- package/dist/lib/ir/path/arrow.d.ts +12 -12
- package/dist/lib/ir/path/path.cjs +2 -0
- package/dist/lib/ir/path/path.d.ts +490 -147
- package/dist/lib/ir/path/path.d.ts.map +1 -1
- package/dist/lib/ir/path/step.cjs +2 -2
- package/dist/lib/ir/path/step.d.ts +674 -154
- package/dist/lib/ir/path/step.d.ts.map +1 -1
- package/dist/lib/ir/path/target.cjs +4 -5
- package/dist/lib/ir/path/target.d.ts +43 -8
- package/dist/lib/ir/path/target.d.ts.map +1 -1
- package/dist/lib/ir/scope.cjs +6 -2
- package/dist/lib/ir/scope.d.ts +843 -234
- package/dist/lib/ir/scope.d.ts.map +1 -1
- package/dist/lib/ir/shape.cjs +9 -0
- package/dist/lib/ir/shape.d.ts +14 -0
- package/dist/lib/ir/shape.d.ts.map +1 -0
- package/dist/lib/parsers/parseNodeTarget.cjs +4 -2
- package/dist/lib/parsers/parseNodeTarget.d.ts.map +1 -1
- package/dist/lib/primitive/ellipse.d.ts +3 -0
- package/dist/lib/primitive/ellipse.d.ts.map +1 -1
- package/dist/lib/primitive/group.d.ts +3 -0
- package/dist/lib/primitive/group.d.ts.map +1 -1
- package/dist/lib/primitive/path.d.ts +3 -0
- package/dist/lib/primitive/path.d.ts.map +1 -1
- package/dist/lib/primitive/rect.d.ts +3 -0
- package/dist/lib/primitive/rect.d.ts.map +1 -1
- package/dist/lib/primitive/text.d.ts +3 -0
- package/dist/lib/primitive/text.d.ts.map +1 -1
- package/dist/lib/shapes/_contour.cjs +61 -0
- package/dist/lib/shapes/_contour.d.ts +19 -0
- package/dist/lib/shapes/_contour.d.ts.map +1 -0
- package/dist/lib/shapes/_shared.cjs +70 -0
- package/dist/lib/shapes/_shared.d.ts +54 -0
- package/dist/lib/shapes/_shared.d.ts.map +1 -1
- package/dist/lib/shapes/arc.cjs +104 -0
- package/dist/lib/shapes/arc.d.ts +8 -0
- package/dist/lib/shapes/arc.d.ts.map +1 -0
- package/dist/lib/shapes/define.cjs +13 -0
- package/dist/lib/shapes/define.d.ts +13 -0
- package/dist/lib/shapes/define.d.ts.map +1 -0
- package/dist/lib/shapes/ellipse.cjs +15 -7
- package/dist/lib/shapes/ellipse.d.ts +5 -4
- package/dist/lib/shapes/ellipse.d.ts.map +1 -1
- package/dist/lib/shapes/index.cjs +12 -6
- package/dist/lib/shapes/index.d.ts +9 -6
- package/dist/lib/shapes/index.d.ts.map +1 -1
- package/dist/lib/shapes/polygon.cjs +104 -0
- package/dist/lib/shapes/polygon.d.ts +13 -0
- package/dist/lib/shapes/polygon.d.ts.map +1 -0
- package/dist/lib/shapes/rectangle.cjs +37 -8
- package/dist/lib/shapes/rectangle.d.ts +7 -5
- package/dist/lib/shapes/rectangle.d.ts.map +1 -1
- package/dist/lib/shapes/sector.cjs +143 -0
- package/dist/lib/shapes/sector.d.ts +9 -0
- package/dist/lib/shapes/sector.d.ts.map +1 -0
- package/dist/lib/shapes/star.cjs +113 -0
- package/dist/lib/shapes/star.d.ts +15 -0
- package/dist/lib/shapes/star.d.ts.map +1 -0
- package/dist/lib/shapes/types.d.ts +47 -14
- package/dist/lib/shapes/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/es/shapes/circle.d.ts +0 -8
- package/dist/es/shapes/circle.d.ts.map +0 -1
- package/dist/es/shapes/circle.js +0 -34
- package/dist/es/shapes/diamond.d.ts +0 -8
- package/dist/es/shapes/diamond.d.ts.map +0 -1
- package/dist/es/shapes/diamond.js +0 -66
- package/dist/lib/shapes/circle.cjs +0 -34
- package/dist/lib/shapes/circle.d.ts +0 -8
- package/dist/lib/shapes/circle.d.ts.map +0 -1
- package/dist/lib/shapes/diamond.cjs +0 -66
- package/dist/lib/shapes/diamond.d.ts +0 -8
- package/dist/lib/shapes/diamond.d.ts.map +0 -1
|
@@ -1,9 +1,62 @@
|
|
|
1
|
+
const require_json = require("../ir/json.cjs");
|
|
2
|
+
const require__shared = require("../shapes/_shared.cjs");
|
|
1
3
|
const require_index = require("../shapes/index.cjs");
|
|
2
4
|
const require_position = require("./position.cjs");
|
|
3
5
|
const require_text_baseline = require("./text-baseline.cjs");
|
|
6
|
+
const require_boundary = require("./boundary.cjs");
|
|
4
7
|
//#region src/compile/node.ts
|
|
5
8
|
var DEFAULT_FONT_SIZE = 14;
|
|
6
9
|
var DEFAULT_PADDING = 8;
|
|
10
|
+
/** 无参 / 合成 layout 的 shape params 兜底(避免每次调用重建空对象) */
|
|
11
|
+
var EMPTY_SHAPE_PARAMS = {};
|
|
12
|
+
/**
|
|
13
|
+
* 规范化 `Node.shape` 为 `{ type, params }`
|
|
14
|
+
* @description 裸 string → `{ type, params: {} }`;`{ type, params? }` → params 缺省补 `{}`;
|
|
15
|
+
* 缺省(undefined)→ `{ type: 'rectangle', params: {} }`。`'circle'`(裸 string)消解为
|
|
16
|
+
* `{ type: 'ellipse', params: { circumscribe: 'equal' } }`——circle 无独立几何,是 ellipse 等轴 preset 别名。
|
|
17
|
+
* `'diamond'`(裸 string)消解为 `{ type: 'polygon', params: { sides: 4, rotate: 45 } }`——diamond 无独立几何,
|
|
18
|
+
* 是 polygon 4 边形(自旋 45°)preset 别名。仅做形态归一,不查表 / 不校验。
|
|
19
|
+
*/
|
|
20
|
+
var normalizeShape = (shape) => {
|
|
21
|
+
if (shape === void 0) return {
|
|
22
|
+
type: "rectangle",
|
|
23
|
+
params: {}
|
|
24
|
+
};
|
|
25
|
+
if (shape === "circle") return {
|
|
26
|
+
type: "ellipse",
|
|
27
|
+
params: { circumscribe: "equal" }
|
|
28
|
+
};
|
|
29
|
+
if (shape === "diamond") return {
|
|
30
|
+
type: "polygon",
|
|
31
|
+
params: {
|
|
32
|
+
sides: 4,
|
|
33
|
+
rotate: 45
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
if (typeof shape === "string") return {
|
|
37
|
+
type: shape,
|
|
38
|
+
params: {}
|
|
39
|
+
};
|
|
40
|
+
const ref = shape;
|
|
41
|
+
return {
|
|
42
|
+
type: ref.type,
|
|
43
|
+
params: ref.params ?? {}
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* 递归把 JSON 值里所有数值叶子乘以 factor(数组 / 对象深入,string / boolean / null 原样)
|
|
48
|
+
* @description 用于 shape params 随 node scale 协同缩放;输入已是 JSON-safe(双护栏过),输出仍 JSON-safe。
|
|
49
|
+
*/
|
|
50
|
+
var scaleJsonNumbers = (value, factor) => {
|
|
51
|
+
if (typeof value === "number") return value * factor;
|
|
52
|
+
if (Array.isArray(value)) return value.map((v) => scaleJsonNumbers(v, factor));
|
|
53
|
+
if (value !== null && typeof value === "object") {
|
|
54
|
+
const out = {};
|
|
55
|
+
for (const [k, v] of Object.entries(value)) out[k] = scaleJsonNumbers(v, factor);
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
return value;
|
|
59
|
+
};
|
|
7
60
|
var DEFAULT_LINE_HEIGHT_FACTOR = 1.2;
|
|
8
61
|
var DEG_TO_RAD = Math.PI / 180;
|
|
9
62
|
/** CJK / fullwidth ranges: break per-character (no whitespace needed) */
|
|
@@ -73,16 +126,28 @@ var inflateRect = (r, m) => m === 0 ? r : {
|
|
|
73
126
|
};
|
|
74
127
|
/**
|
|
75
128
|
* 取节点 shape 在 toward 方向的附着点(path 端点贴边用)
|
|
76
|
-
* @description
|
|
129
|
+
* @description 走连接面(boundary)对应的 def.boundaryPoint;margin > 0 时先膨胀外接 Rect,让 path 在 border 外停 margin。
|
|
130
|
+
* boundary 缺省 = 'shape'(视觉形状自身),与改前行为一致。
|
|
77
131
|
*/
|
|
78
|
-
var boundaryPointOf = (layout, toward
|
|
132
|
+
var boundaryPointOf = (layout, toward, boundary = "shape") => {
|
|
133
|
+
const { def, rect, params } = require_boundary.resolveBoundary(boundary, layout.shapeDef, layout.rect, layout.shapeParams ?? EMPTY_SHAPE_PARAMS, layout.shapes);
|
|
134
|
+
return def.boundaryPoint(inflateRect(rect, layout.margin), toward, params);
|
|
135
|
+
};
|
|
79
136
|
/**
|
|
80
137
|
* 取节点 shape 命名 anchor(center / north / east / north-east 等)
|
|
81
138
|
* @description 不应用 margin——TikZ 语义中 explicit anchor 取视觉边界点不涉及 outer sep;用于 `'A.north'` 落点。
|
|
82
|
-
*
|
|
139
|
+
* compass(9 个 rect 方位名)走连接面 AABB:'shape' 时归一为 'rectangle'(矩形 AABB),其余按 boundary 解析。
|
|
140
|
+
* 形状专属命名 anchor(tip-N / apex 等非 compass 名)恒走视觉形状自身,boundary 不影响。
|
|
141
|
+
* boundary 缺省 = 'shape',与改前 compass 走 AABB 行为一致(原 shapeDef.anchor 内部也走 rect AABB)。
|
|
83
142
|
*/
|
|
84
|
-
var anchorOf = (layout, name) => {
|
|
85
|
-
|
|
143
|
+
var anchorOf = (layout, name, boundary = "shape") => {
|
|
144
|
+
if (require__shared.asRectAnchor(name) !== void 0) {
|
|
145
|
+
const { def, rect, params } = require_boundary.resolveBoundary(boundary === "shape" ? "rectangle" : boundary, layout.shapeDef, layout.rect, layout.shapeParams ?? EMPTY_SHAPE_PARAMS, layout.shapes);
|
|
146
|
+
const p = def.anchor(rect, name, params);
|
|
147
|
+
if (p === void 0) throw new Error(`Unknown anchor '${name}' for shape '${layout.shapeName}'`);
|
|
148
|
+
return p;
|
|
149
|
+
}
|
|
150
|
+
const p = layout.shapeDef.anchor(layout.rect, name, layout.shapeParams ?? EMPTY_SHAPE_PARAMS);
|
|
86
151
|
if (p === void 0) throw new Error(`Unknown anchor '${name}' for shape '${layout.shapeName}'`);
|
|
87
152
|
return p;
|
|
88
153
|
};
|
|
@@ -187,9 +252,10 @@ var resolveLabelRotateDeg = (label, lx, ly, cx, cy) => {
|
|
|
187
252
|
};
|
|
188
253
|
/**
|
|
189
254
|
* 取节点 shape 在指定角度方向的边界点
|
|
190
|
-
* @description 角度是节点**局部坐标系**下的极角(度数:0°=局部 +x,90°=局部 +y)。layout.rect.rotate 把局部基绕中心旋转,得到世界系下的视觉方向;shape boundaryPoint 内部用 rotate-aware 投影,所以这里把局部 (cos, sin) 经 rect.rotate 旋转后加到中心当作世界系 toward 传入。不应用 margin(同 anchorOf);用于 `'A.30'`
|
|
255
|
+
* @description 角度是节点**局部坐标系**下的极角(度数:0°=局部 +x,90°=局部 +y)。layout.rect.rotate 把局部基绕中心旋转,得到世界系下的视觉方向;shape boundaryPoint 内部用 rotate-aware 投影,所以这里把局部 (cos, sin) 经 rect.rotate 旋转后加到中心当作世界系 toward 传入。不应用 margin(同 anchorOf);用于 `'A.30'` 落点。
|
|
256
|
+
* boundary 缺省 = 'shape'(视觉形状自身),与改前行为一致。
|
|
191
257
|
*/
|
|
192
|
-
var angleBoundaryOf = (layout, angleDeg) => {
|
|
258
|
+
var angleBoundaryOf = (layout, angleDeg, boundary = "shape") => {
|
|
193
259
|
const rad = angleDeg * Math.PI / 180;
|
|
194
260
|
const lx = Math.cos(rad);
|
|
195
261
|
const ly = Math.sin(rad);
|
|
@@ -197,7 +263,8 @@ var angleBoundaryOf = (layout, angleDeg) => {
|
|
|
197
263
|
const cosR = Math.cos(rot);
|
|
198
264
|
const sinR = Math.sin(rot);
|
|
199
265
|
const toward = [layout.rect.x + lx * cosR - ly * sinR, layout.rect.y + lx * sinR + ly * cosR];
|
|
200
|
-
|
|
266
|
+
const { def, rect, params } = require_boundary.resolveBoundary(boundary, layout.shapeDef, layout.rect, layout.shapeParams ?? EMPTY_SHAPE_PARAMS, layout.shapes);
|
|
267
|
+
return def.boundaryPoint(rect, toward, params);
|
|
201
268
|
};
|
|
202
269
|
/**
|
|
203
270
|
* IR Node → 内部 NodeLayout
|
|
@@ -207,12 +274,20 @@ var angleBoundaryOf = (layout, angleDeg) => {
|
|
|
207
274
|
* 笛卡尔字面量 `Position` 已在 scope 局部度量,行为延续 v0.1。
|
|
208
275
|
*/
|
|
209
276
|
var layoutNode = (node, measureText, nameStack, nodeDistance, scopeChain = [], labelDefault, shapes = require_index.BUILTIN_SHAPES, resolveBetweenGlobal) => {
|
|
210
|
-
const shapeName = node.shape
|
|
277
|
+
const { type: shapeName, params: rawShapeParams } = normalizeShape(node.shape);
|
|
211
278
|
const shapeDef = Object.prototype.hasOwnProperty.call(shapes, shapeName) ? shapes[shapeName] : void 0;
|
|
212
279
|
if (!shapeDef) throw new Error(`Unknown shape '${shapeName}'; registered shapes: ${Object.keys(shapes).sort().join(", ")}`);
|
|
280
|
+
require_json.JsonObjectSchema.parse(rawShapeParams);
|
|
281
|
+
const parsedShapeParams = shapeDef.paramsSchema.parse(rawShapeParams);
|
|
282
|
+
const mergedShapeParams = shapeName === "rectangle" && node.cornerRadius !== void 0 && !("cornerRadius" in parsedShapeParams) ? {
|
|
283
|
+
...parsedShapeParams,
|
|
284
|
+
cornerRadius: node.cornerRadius
|
|
285
|
+
} : parsedShapeParams;
|
|
213
286
|
const sx = node.xScale ?? node.scale ?? 1;
|
|
214
287
|
const sy = node.yScale ?? node.scale ?? 1;
|
|
215
288
|
const fontScale = Math.min(sx, sy);
|
|
289
|
+
const shapeScale = Math.sqrt(sx * sy);
|
|
290
|
+
const shapeParams = sx === 1 && sy === 1 ? mergedShapeParams : shapeDef.scaleParams ? shapeDef.scaleParams(mergedShapeParams, sx, sy) : scaleJsonNumbers(mergedShapeParams, shapeScale);
|
|
216
291
|
const baseFontSize = node.font?.size ?? DEFAULT_FONT_SIZE;
|
|
217
292
|
const fontSize = baseFontSize * fontScale;
|
|
218
293
|
const fontFamily = node.font?.family;
|
|
@@ -262,10 +337,13 @@ var layoutNode = (node, measureText, nameStack, nodeDistance, scopeChain = [], l
|
|
|
262
337
|
const minH = node.minimumHeight ?? node.minimumSize ?? 0;
|
|
263
338
|
const innerHalfW = Math.max(textWidth / 2 + xSep, xSep, minW / 2);
|
|
264
339
|
const innerHalfH = Math.max(textHeight / 2 + ySep, ySep, minH / 2);
|
|
265
|
-
const { halfWidth: boundsHalfW, halfHeight: boundsHalfH } = shapeDef.circumscribe(innerHalfW, innerHalfH);
|
|
340
|
+
const { halfWidth: boundsHalfW, halfHeight: boundsHalfH } = shapeDef.circumscribe(innerHalfW, innerHalfH, shapeParams);
|
|
266
341
|
const rotateDeg = node.rotate ?? 0;
|
|
267
342
|
const center = require_position.resolvePosition(node.position, nameStack, nodeDistance, scopeChain, resolveBetweenGlobal);
|
|
268
343
|
if (!center) throw new Error(`Cannot resolve position for node ${node.id ?? "(unnamed)"}; polar.origin / at.of / between endpoint may reference an undefined node`);
|
|
344
|
+
const aabbOffset = shapeDef.circumscribeOffset?.(shapeParams);
|
|
345
|
+
const rectCenterX = center[0] + (aabbOffset?.[0] ?? 0);
|
|
346
|
+
const rectCenterY = center[1] + (aabbOffset?.[1] ?? 0);
|
|
269
347
|
const labels = (node.label === void 0 ? void 0 : Array.isArray(node.label) ? node.label : [node.label])?.map((lab) => {
|
|
270
348
|
const labFont = lab.font;
|
|
271
349
|
const labFontSize = (labFont?.size ?? labelDefault?.font?.size ?? baseFontSize) * fontScale;
|
|
@@ -297,9 +375,10 @@ var layoutNode = (node, measureText, nameStack, nodeDistance, scopeChain = [], l
|
|
|
297
375
|
id: node.id,
|
|
298
376
|
shapeName,
|
|
299
377
|
shapeDef,
|
|
378
|
+
shapeParams,
|
|
300
379
|
rect: {
|
|
301
|
-
x:
|
|
302
|
-
y:
|
|
380
|
+
x: rectCenterX,
|
|
381
|
+
y: rectCenterY,
|
|
303
382
|
width: 2 * boundsHalfW,
|
|
304
383
|
height: 2 * boundsHalfH,
|
|
305
384
|
rotate: rotateDeg * DEG_TO_RAD
|
|
@@ -321,10 +400,13 @@ var layoutNode = (node, measureText, nameStack, nodeDistance, scopeChain = [], l
|
|
|
321
400
|
strokeOpacity: node.drawOpacity,
|
|
322
401
|
strokeWidth: node.strokeWidth,
|
|
323
402
|
dashPattern: resolveDashArray(node.dashArray, node.dashed, node.dotted),
|
|
324
|
-
|
|
403
|
+
cornerRadius: node.cornerRadius,
|
|
325
404
|
textColor: node.textColor,
|
|
326
405
|
opacity: node.opacity,
|
|
327
|
-
labels
|
|
406
|
+
labels,
|
|
407
|
+
boundary: node.boundary,
|
|
408
|
+
meta: node.meta,
|
|
409
|
+
shapes
|
|
328
410
|
};
|
|
329
411
|
};
|
|
330
412
|
/** 从 NodeLayout 收敛 emit 所需的视觉样式子集(ShapeStyle,不含几何 / 文本);fill 经 resolveFill 转 PaintValue */
|
|
@@ -335,7 +417,7 @@ var toShapeStyle = (layout, resolveFill) => ({
|
|
|
335
417
|
strokeOpacity: layout.strokeOpacity,
|
|
336
418
|
strokeWidth: layout.strokeWidth,
|
|
337
419
|
dashPattern: layout.dashPattern,
|
|
338
|
-
|
|
420
|
+
cornerRadius: layout.cornerRadius,
|
|
339
421
|
opacity: layout.opacity
|
|
340
422
|
});
|
|
341
423
|
/**
|
|
@@ -380,7 +462,7 @@ var emitNodePrimitives = (layout, round, resolveFill) => {
|
|
|
380
462
|
...layout.rect,
|
|
381
463
|
rotate: 0
|
|
382
464
|
};
|
|
383
|
-
const shapePrims = [...layout.shapeDef.emit(axisAlignedRect, toShapeStyle(layout, resolveFill), round)];
|
|
465
|
+
const shapePrims = [...layout.shapeDef.emit(axisAlignedRect, toShapeStyle(layout, resolveFill), round, layout.shapeParams ?? EMPTY_SHAPE_PARAMS)];
|
|
384
466
|
const inner = [...shapePrims];
|
|
385
467
|
if (layout.lines) {
|
|
386
468
|
const halfBlockW = layout.textWidth / 2;
|
|
@@ -463,6 +545,7 @@ var emitNodePrimitives = (layout, round, resolveFill) => {
|
|
|
463
545
|
}
|
|
464
546
|
if (!(layout.rotateDeg !== 0 || layout.lines !== void 0)) {
|
|
465
547
|
if (layout.id !== void 0) for (const prim of shapePrims) prim.id = layout.id;
|
|
548
|
+
if (layout.meta !== void 0) for (const prim of shapePrims) prim.meta = layout.meta;
|
|
466
549
|
return inner;
|
|
467
550
|
}
|
|
468
551
|
const group = {
|
|
@@ -470,6 +553,7 @@ var emitNodePrimitives = (layout, round, resolveFill) => {
|
|
|
470
553
|
children: inner
|
|
471
554
|
};
|
|
472
555
|
if (layout.id !== void 0) group.id = layout.id;
|
|
556
|
+
if (layout.meta !== void 0) group.meta = layout.meta;
|
|
473
557
|
if (layout.rotateDeg !== 0) group.transforms = [{
|
|
474
558
|
kind: "rotate",
|
|
475
559
|
degrees: round(layout.rotateDeg),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Position } from '../geometry/point';
|
|
2
2
|
import { Rect } from '../geometry/rect';
|
|
3
|
-
import { AtDirection, IRLabelDefault, IRNode, IRPaintSpec } from '../ir';
|
|
3
|
+
import { AtDirection, IRBoundary, IRJsonObject, IRLabelDefault, IRNode, IRPaintSpec } from '../ir';
|
|
4
4
|
import { PaintResolver } from './paint';
|
|
5
5
|
import { ScenePrimitive, TextLine, Transform } from '../primitive';
|
|
6
6
|
import { ShapeDefinition } from '../shapes';
|
|
@@ -14,6 +14,12 @@ export type NodeLayout = {
|
|
|
14
14
|
shapeName: string;
|
|
15
15
|
/** 已解析的 shape 定义;circumscribe / boundaryPoint / anchor / emit 多点复用,取代旧 switch */
|
|
16
16
|
shapeDef: ShapeDefinition;
|
|
17
|
+
/**
|
|
18
|
+
* 已校验的 per-instance shape 参数(经 `paramsSchema.parse` + `JsonObjectSchema.parse` 双护栏)
|
|
19
|
+
* @description 透传给 `shapeDef` 的 circumscribe / boundaryPoint / anchor / edgePoint / emit;
|
|
20
|
+
* 无参形状(内置 4 个)解析为 `{}`。省略时各调用点以空对象兜底(合成 layout 如 coordinate / scope.id)。
|
|
21
|
+
*/
|
|
22
|
+
shapeParams?: IRJsonObject;
|
|
17
23
|
/**
|
|
18
24
|
* 节点视觉边界框(所有 shape 共享语义)
|
|
19
25
|
* @description rectangle: rect 本身;circle: width=height=2×radius;ellipse: 2×rx,2×ry;diamond: 2×halfA,2×halfB。x,y 是几何中心,rotate 弧度
|
|
@@ -57,7 +63,7 @@ export type NodeLayout = {
|
|
|
57
63
|
/** 描边 dash pattern,已把 dashed/dotted 预设解析为具体 pattern */
|
|
58
64
|
dashPattern?: Array<number>;
|
|
59
65
|
/** rectangle 圆角半径(非 rect shape 无效) */
|
|
60
|
-
|
|
66
|
+
cornerRadius?: number;
|
|
61
67
|
/** 文字颜色,emit 时 'currentColor' 兜底 */
|
|
62
68
|
textColor?: string;
|
|
63
69
|
/** 整节点透明度 0~1(同时挂 shape 与 text primitive) */
|
|
@@ -67,6 +73,12 @@ export type NodeLayout = {
|
|
|
67
73
|
* @description IR 层 `Node.label` 标准化:position 默认 'above'、distance 默认 DEFAULT_LABEL_DISTANCE、font 从 Node 继承
|
|
68
74
|
*/
|
|
69
75
|
labels?: Array<NodeLabelLayout>;
|
|
76
|
+
/** 节点默认连接面(来自 IR `node.boundary`;undefined = 'shape');path 端点 boundary 可覆盖 */
|
|
77
|
+
boundary?: IRBoundary;
|
|
78
|
+
/** provenance 元数据(来自 IR `node.meta`);emit 时原样 stamp 到 node 的 top-level 图元,renderer 忽略 */
|
|
79
|
+
meta?: IRJsonObject;
|
|
80
|
+
/** 构建本 layout 的 shape 注册表引用——借用连接面(borrowed boundary)查表用 */
|
|
81
|
+
shapes: Record<string, ShapeDefinition>;
|
|
70
82
|
};
|
|
71
83
|
/** 节点附属标签 layout(layoutNode 已合并默认值与样式继承) */
|
|
72
84
|
export type NodeLabelLayout = {
|
|
@@ -96,20 +108,24 @@ export type NodeLabelLayout = {
|
|
|
96
108
|
};
|
|
97
109
|
/**
|
|
98
110
|
* 取节点 shape 在 toward 方向的附着点(path 端点贴边用)
|
|
99
|
-
* @description
|
|
111
|
+
* @description 走连接面(boundary)对应的 def.boundaryPoint;margin > 0 时先膨胀外接 Rect,让 path 在 border 外停 margin。
|
|
112
|
+
* boundary 缺省 = 'shape'(视觉形状自身),与改前行为一致。
|
|
100
113
|
*/
|
|
101
|
-
export declare const boundaryPointOf: (layout: NodeLayout, toward: Position) => Position;
|
|
114
|
+
export declare const boundaryPointOf: (layout: NodeLayout, toward: Position, boundary?: IRBoundary | undefined) => Position;
|
|
102
115
|
/**
|
|
103
116
|
* 取节点 shape 命名 anchor(center / north / east / north-east 等)
|
|
104
117
|
* @description 不应用 margin——TikZ 语义中 explicit anchor 取视觉边界点不涉及 outer sep;用于 `'A.north'` 落点。
|
|
105
|
-
*
|
|
118
|
+
* compass(9 个 rect 方位名)走连接面 AABB:'shape' 时归一为 'rectangle'(矩形 AABB),其余按 boundary 解析。
|
|
119
|
+
* 形状专属命名 anchor(tip-N / apex 等非 compass 名)恒走视觉形状自身,boundary 不影响。
|
|
120
|
+
* boundary 缺省 = 'shape',与改前 compass 走 AABB 行为一致(原 shapeDef.anchor 内部也走 rect AABB)。
|
|
106
121
|
*/
|
|
107
|
-
export declare const anchorOf: (layout: NodeLayout, name: string) => Position;
|
|
122
|
+
export declare const anchorOf: (layout: NodeLayout, name: string, boundary?: IRBoundary | undefined) => Position;
|
|
108
123
|
/**
|
|
109
124
|
* 取节点 shape 在指定角度方向的边界点
|
|
110
|
-
* @description 角度是节点**局部坐标系**下的极角(度数:0°=局部 +x,90°=局部 +y)。layout.rect.rotate 把局部基绕中心旋转,得到世界系下的视觉方向;shape boundaryPoint 内部用 rotate-aware 投影,所以这里把局部 (cos, sin) 经 rect.rotate 旋转后加到中心当作世界系 toward 传入。不应用 margin(同 anchorOf);用于 `'A.30'`
|
|
125
|
+
* @description 角度是节点**局部坐标系**下的极角(度数:0°=局部 +x,90°=局部 +y)。layout.rect.rotate 把局部基绕中心旋转,得到世界系下的视觉方向;shape boundaryPoint 内部用 rotate-aware 投影,所以这里把局部 (cos, sin) 经 rect.rotate 旋转后加到中心当作世界系 toward 传入。不应用 margin(同 anchorOf);用于 `'A.30'` 落点。
|
|
126
|
+
* boundary 缺省 = 'shape'(视觉形状自身),与改前行为一致。
|
|
111
127
|
*/
|
|
112
|
-
export declare const angleBoundaryOf: (layout: NodeLayout, angleDeg: number) => Position;
|
|
128
|
+
export declare const angleBoundaryOf: (layout: NodeLayout, angleDeg: number, boundary?: IRBoundary | undefined) => Position;
|
|
113
129
|
/**
|
|
114
130
|
* IR Node → 内部 NodeLayout
|
|
115
131
|
* @description 文本度量 + padding 推内框半轴;按 shape 算外接边界(circle 取半对角线、ellipse ×√2、diamond ×2);解析 position 为几何中心;rotate 度数转弧度。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/compile/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAc,MAAM,EAAe,WAAW,
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/compile/node.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,10 +8,10 @@ const require_anchor_cache = require("../anchor-cache.cjs");
|
|
|
8
8
|
var isNodeTarget = (t) => typeof t === "object" && !Array.isArray(t) && "id" in t;
|
|
9
9
|
/** target 是否 between 比例点(`{ between, t }`);独有 `between` 字段 */
|
|
10
10
|
var isBetween = (t) => typeof t === "object" && !Array.isArray(t) && "between" in t;
|
|
11
|
-
/** 解析 NodeTarget 的 anchor(非 undefined)到世界坐标:命名 / 角度走 resolveAnchor
|
|
12
|
-
var resolveAnchorRef = (node, anchor) => {
|
|
13
|
-
if (typeof anchor === "number") return require_anchor_cache.resolveAnchor(node, String(anchor));
|
|
14
|
-
if (typeof anchor === "string") return require_anchor_cache.resolveAnchor(node, anchor);
|
|
11
|
+
/** 解析 NodeTarget 的 anchor(非 undefined)到世界坐标:命名 / 角度走 resolveAnchor(可选连接面),`{ side, t }` 恒走视觉形状(不传 boundary) */
|
|
12
|
+
var resolveAnchorRef = (node, anchor, boundary) => {
|
|
13
|
+
if (typeof anchor === "number") return require_anchor_cache.resolveAnchor(node, String(anchor), boundary);
|
|
14
|
+
if (typeof anchor === "string") return require_anchor_cache.resolveAnchor(node, anchor, boundary);
|
|
15
15
|
return require_anchor_cache.resolveEdgePoint(node, anchor.side, anchor.t);
|
|
16
16
|
};
|
|
17
17
|
/** anchor/边点解析后叠加世界系 offset(不随节点 rotate 旋转) */
|
|
@@ -27,7 +27,7 @@ var refPointOfTarget = (target, nameStack, scopeChain = []) => {
|
|
|
27
27
|
if (isNodeTarget(target)) {
|
|
28
28
|
const node = nameStack.lookup(target.id);
|
|
29
29
|
if (!node) return null;
|
|
30
|
-
return addOffset(target.anchor === void 0 ? [node.rect.x, node.rect.y] : resolveAnchorRef(node, target.anchor), target.offset);
|
|
30
|
+
return addOffset(target.anchor === void 0 ? [node.rect.x, node.rect.y] : resolveAnchorRef(node, target.anchor, target.boundary ?? node.boundary), target.offset);
|
|
31
31
|
}
|
|
32
32
|
if (isBetween(target)) {
|
|
33
33
|
const a = refPointOfTarget(target.between[0], nameStack, scopeChain);
|
|
@@ -54,7 +54,8 @@ var clipForTarget = (target, toward, nameStack, scopeChain = []) => {
|
|
|
54
54
|
if (isNodeTarget(target)) {
|
|
55
55
|
const node = nameStack.lookup(target.id);
|
|
56
56
|
if (!node) return null;
|
|
57
|
-
|
|
57
|
+
const boundary = target.boundary ?? node.boundary;
|
|
58
|
+
return addOffset(target.anchor === void 0 ? require_node.boundaryPointOf(node, toward, boundary) : resolveAnchorRef(node, target.anchor, boundary), target.offset);
|
|
58
59
|
}
|
|
59
60
|
if (isBetween(target)) return refPointOfTarget(target, nameStack, scopeChain);
|
|
60
61
|
if (typeof target === "object" && !Array.isArray(target) && ("relative" in target || "relativeAccumulate" in target)) return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anchor.d.ts","sourceRoot":"","sources":["../../../../src/compile/path/anchor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmC,UAAU,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"anchor.d.ts","sourceRoot":"","sources":["../../../../src/compile/path/anchor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmC,UAAU,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEtF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AA6B/C;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAC3B,QAAQ,QAAQ,EAChB,WAAW,SAAS,EACpB,aAAY,aAAa,CAAC,SAAS,CAAM,KACxC,UAAU,GAAG,IA8Bf,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,QAAQ,GACnB,MAAM,UAAU,EAChB,MAAM,UAAU,EAChB,KAAK,IAAI,GAAG,IAAI,KACf,UACqD,CAAC;AAEzD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GACxB,QAAQ,QAAQ,EAChB,QAAQ,UAAU,EAClB,WAAW,SAAS,EACpB,aAAY,aAAa,CAAC,SAAS,CAAM,KACxC,UAAU,GAAG,IAuBf,CAAC;AAEF,qCAAqC;AACrC,eAAO,MAAM,SAAS,GAAI,GAAG,UAAU,GAAG,IAAI,EAAE,GAAG,UAAU,GAAG,IAAI,KAAG,OACzB,CAAC;AAE/C,6BAA6B;AAC7B,eAAO,MAAM,WAAW,GAAI,GAAG,UAAU,EAAE,QAAQ,UAAU,EAAE,MAAM,MAAM,KAAG,UAM7E,CAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const require_rect = require("../../geometry/rect.cjs");
|
|
2
1
|
const require_json = require("../../ir/json.cjs");
|
|
2
|
+
const require_rect = require("../../geometry/rect.cjs");
|
|
3
|
+
const require_arc = require("../../geometry/arc.cjs");
|
|
3
4
|
const require_index = require("../../arrows/index.cjs");
|
|
4
5
|
const require_scope = require("../scope.cjs");
|
|
5
|
-
const require_arc = require("../../geometry/arc.cjs");
|
|
6
6
|
const require_bend = require("../../geometry/bend.cjs");
|
|
7
7
|
const require_segment = require("../../geometry/segment.cjs");
|
|
8
8
|
const require_text_metrics = require("../text-metrics.cjs");
|
|
@@ -434,7 +434,7 @@ var emitPathPrimitive = (path, nameStack, round, measureText = require_text_metr
|
|
|
434
434
|
return null;
|
|
435
435
|
}
|
|
436
436
|
let rectStart = null;
|
|
437
|
-
for (const op of require_rect.rectOutline(fromPt, toPt, step.
|
|
437
|
+
for (const op of require_rect.rectOutline(fromPt, toPt, step.cornerRadius)) if (op.kind === "move") {
|
|
438
438
|
emitMove(op.to);
|
|
439
439
|
rectStart = op.to;
|
|
440
440
|
} else if (op.kind === "line") emitLine(op.to);
|
|
@@ -647,6 +647,7 @@ var emitPathPrimitive = (path, nameStack, round, measureText = require_text_metr
|
|
|
647
647
|
children: bodyPrims
|
|
648
648
|
};
|
|
649
649
|
if (path.id !== void 0) group.id = path.id;
|
|
650
|
+
if (path.meta !== void 0) group.meta = path.meta;
|
|
650
651
|
const transformedPoints = points.map((p) => require_scope.applyTransformChain(p, transforms));
|
|
651
652
|
if (!transformedPoints.every(isFinitePoint)) throw new Error("Path rotate / scale produced a non-finite coordinate (scale too large); use a smaller scale.");
|
|
652
653
|
return {
|
|
@@ -656,6 +657,7 @@ var emitPathPrimitive = (path, nameStack, round, measureText = require_text_metr
|
|
|
656
657
|
}
|
|
657
658
|
}
|
|
658
659
|
if (path.id !== void 0) primitive.id = path.id;
|
|
660
|
+
if (path.meta !== void 0) primitive.meta = path.meta;
|
|
659
661
|
return {
|
|
660
662
|
primitives: bodyPrims,
|
|
661
663
|
points
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/compile/path/index.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAY9C,OAAO,KAAK,EACV,MAAM,EAEN,UAAU,EAGX,MAAM,UAAU,CAAC;AAElB,OAAO,KAAK,EAIV,cAAc,EACd,SAAS,EACV,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,KAAK,YAAY,EAAoB,MAAM,iBAAiB,CAAC;AAKtE,OAAO,EAAE,KAAK,eAAe,EAA2D,MAAM,UAAU,CAAC;AA8FzG,mCAAmC;AACnC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,iCAAiC;IACjC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;KACd,KAAK,IAAI,CAAC;IACX,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,UAAU,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IACtC,wEAAwE;IACxE,WAAW,CAAC,EAAE,aAAa,CAAC;IAC5B;;;;OAIG;IACH,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;CACnE,CAAC;AA0EF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM,MAAM,EACZ,WAAW,SAAS,EACpB,OAAO,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EAC5B,cAAa,YAA+B,EAC5C,WAAU,gBAAqB,KAC9B;IAAE,UAAU,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;IAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAA;CAAE,GAAG,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/compile/path/index.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAY9C,OAAO,KAAK,EACV,MAAM,EAEN,UAAU,EAGX,MAAM,UAAU,CAAC;AAElB,OAAO,KAAK,EAIV,cAAc,EACd,SAAS,EACV,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,KAAK,YAAY,EAAoB,MAAM,iBAAiB,CAAC;AAKtE,OAAO,EAAE,KAAK,eAAe,EAA2D,MAAM,UAAU,CAAC;AA8FzG,mCAAmC;AACnC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,iCAAiC;IACjC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;KACd,KAAK,IAAI,CAAC;IACX,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,UAAU,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IACtC,wEAAwE;IACxE,WAAW,CAAC,EAAE,aAAa,CAAC;IAC5B;;;;OAIG;IACH,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;CACnE,CAAC;AA0EF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM,MAAM,EACZ,WAAW,SAAS,EACpB,OAAO,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EAC5B,cAAa,YAA+B,EAC5C,WAAU,gBAAqB,KAC9B;IAAE,UAAU,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;IAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAA;CAAE,GAAG,IAkvBrE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../../src/compile/scope.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,UAAU,EACV,WAAW,EAEZ,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAGzC;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAC/B,YAAY,aAAa,CAAC,WAAW,CAAC,EACtC,WAAW,SAAS,EACpB,eAAe,MAAM,KACpB,KAAK,CAAC,SAAS,CAAC,GAAG,IAiDrB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAC9B,OAAO,UAAU,EACjB,OAAO,aAAa,CAAC,SAAS,CAAC,KAC9B,UAyBF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,UAAU,EAClB,OAAO,aAAa,CAAC,SAAS,CAAC,KAC9B,UAgCF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,UAAU,EAClB,OAAO,aAAa,CAAC,SAAS,CAAC,KAC9B,UAuBF,CAAC;AAEF,8EAA8E;AAC9E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,wBAAwB;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,wBAAwB;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,GAClC,SAAS,aAAa,CAAC,UAAU,CAAC,KACjC,gBAAgB,GAAG,IA2BrB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAChC,IAAI,MAAM,EACV,MAAM,gBAAgB,GAAG,IAAI,EAC7B,gBAAgB,UAAU,KACzB,
|
|
1
|
+
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../../src/compile/scope.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,UAAU,EACV,WAAW,EAEZ,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAGzC;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAC/B,YAAY,aAAa,CAAC,WAAW,CAAC,EACtC,WAAW,SAAS,EACpB,eAAe,MAAM,KACpB,KAAK,CAAC,SAAS,CAAC,GAAG,IAiDrB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAC9B,OAAO,UAAU,EACjB,OAAO,aAAa,CAAC,SAAS,CAAC,KAC9B,UAyBF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,UAAU,EAClB,OAAO,aAAa,CAAC,SAAS,CAAC,KAC9B,UAgCF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,UAAU,EAClB,OAAO,aAAa,CAAC,SAAS,CAAC,KAC9B,UAuBF,CAAC;AAEF,8EAA8E;AAC9E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,wBAAwB;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,wBAAwB;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,GAClC,SAAS,aAAa,CAAC,UAAU,CAAC,KACjC,gBAAgB,GAAG,IA2BrB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAChC,IAAI,MAAM,EACV,MAAM,gBAAgB,GAAG,IAAI,EAC7B,gBAAgB,UAAU,KACzB,UAiBF,CAAC"}
|
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
//#region src/geometry/arc.ts
|
|
2
2
|
var DEG_TO_RAD = Math.PI / 180;
|
|
3
|
+
/**
|
|
4
|
+
* 在 [lo, hi] 内枚举所有 90°·k 方向角(弧轴向极值候选)
|
|
5
|
+
* @description 一圈最多 4 个轴向,合法弧 sweep ≤ 360° → 至多 5 个 90°·k;正常区间直接 for 扫。
|
|
6
|
+
* 但 lo/hi 为巨型角度(如 1e308)时 k=ceil(lo/90) 落在浮点无整数分辨率区,`k++` 满足 k+1===k →
|
|
7
|
+
* for 循环永不前进而挂死(DoS)。此时端点投影已覆盖全部 x/y 极值(巨角下弧实际是退化点 / 单端),
|
|
8
|
+
* 轴向点无新增信息 → 直接跳过枚举。守卫:仅当 kEnd−kStart 是 finite 且 ≤ 安全上界(远大于
|
|
9
|
+
* 任何合法弧的轴向点数)时才枚举,否则返回空(端点已足够定界)。
|
|
10
|
+
*/
|
|
11
|
+
var axisAngles = (lo, hi) => {
|
|
12
|
+
const kStart = Math.ceil(lo / 90);
|
|
13
|
+
const kEnd = Math.floor(hi / 90);
|
|
14
|
+
const span = kEnd - kStart;
|
|
15
|
+
if (!Number.isFinite(span) || span < 0 || span > 1e6) return [];
|
|
16
|
+
const angles = [];
|
|
17
|
+
for (let k = kStart; k <= kEnd; k++) angles.push(k * 90);
|
|
18
|
+
return angles;
|
|
19
|
+
};
|
|
3
20
|
/** 圆心、半径、角度(度,与 polar.toPosition 同约定)→ 圆周上对应点 */
|
|
4
21
|
var arcEndPoint = (center, radius, angleDeg) => {
|
|
5
22
|
const rad = angleDeg * DEG_TO_RAD;
|
|
@@ -13,15 +30,57 @@ var arcBoundingPoints = (center, radius, startAngleDeg, endAngleDeg) => {
|
|
|
13
30
|
const points = [arcEndPoint(center, radius, startAngleDeg), arcEndPoint(center, radius, endAngleDeg)];
|
|
14
31
|
const lo = Math.min(startAngleDeg, endAngleDeg);
|
|
15
32
|
const hi = Math.max(startAngleDeg, endAngleDeg);
|
|
16
|
-
const
|
|
17
|
-
const kEnd = Math.floor(hi / 90);
|
|
18
|
-
for (let k = kStart; k <= kEnd; k++) {
|
|
19
|
-
const angle = k * 90;
|
|
33
|
+
for (const angle of axisAngles(lo, hi)) {
|
|
20
34
|
if (angle === startAngleDeg || angle === endAngleDeg) continue;
|
|
21
35
|
points.push(arcEndPoint(center, radius, angle));
|
|
22
36
|
}
|
|
23
37
|
return points;
|
|
24
38
|
};
|
|
39
|
+
/** 角度(度)→ 规范化到 [0, 360) */
|
|
40
|
+
var normalizeDeg = (deg) => {
|
|
41
|
+
const m = deg % 360;
|
|
42
|
+
return m < 0 ? m + 360 : m;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* 角度 a(度)是否落在弧的角度区间 [startAngle, endAngle] 内(含端点,带容差)
|
|
46
|
+
* @description 与 ir/path arc 同约定:弧从 startAngle 扫到 endAngle,counterClockwise=false(缺省)
|
|
47
|
+
* 时角度递增(屏幕顺时针)、true 时角度递减(逆时针)。统一把扫描量化为「从 start 出发、沿扫描方向
|
|
48
|
+
* 累积的非负 sweep ∈ [0, |span|]」判定,跨 360°、负角、巨型角都正确(不死循环)。
|
|
49
|
+
*/
|
|
50
|
+
var arcAngleInRange = (startAngleDeg, endAngleDeg, angleDeg, toleranceDeg = 1e-7) => {
|
|
51
|
+
const span = endAngleDeg - startAngleDeg;
|
|
52
|
+
const total = Math.abs(span);
|
|
53
|
+
if (total >= 360 - toleranceDeg) return true;
|
|
54
|
+
const swept = normalizeDeg(span < 0 ? startAngleDeg - angleDeg : angleDeg - startAngleDeg);
|
|
55
|
+
return swept <= total + toleranceDeg || swept >= 360 - toleranceDeg;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* 射线(origin + 单位方向 dir)∩ 圆弧(center, radius, [startAngle, endAngle])
|
|
59
|
+
* @description 泛化 sector 的内联 rayCircle:先解 |origin + s·dir|² = radius² 得至多两个参数 s,
|
|
60
|
+
* 再用 arcAngleInRange 过滤掉不在弧角度区间内的交点。返回沿射线的正向参数 s(命中点 = origin + s·dir),
|
|
61
|
+
* 按 s 升序、仅含 s > tolerance 的正向交点;不在区间内的根被剔除。dir 必须为单位向量。
|
|
62
|
+
*/
|
|
63
|
+
var rayArc = (origin, dir, center, radius, startAngleDeg, endAngleDeg, tolerance = 1e-9) => {
|
|
64
|
+
const ox = origin[0] - center[0];
|
|
65
|
+
const oy = origin[1] - center[1];
|
|
66
|
+
const ux = dir[0];
|
|
67
|
+
const uy = dir[1];
|
|
68
|
+
const b = 2 * (ox * ux + oy * uy);
|
|
69
|
+
const c = ox * ox + oy * oy - radius * radius;
|
|
70
|
+
const disc = b * b - 4 * c;
|
|
71
|
+
if (disc < 0) return [];
|
|
72
|
+
const sq = Math.sqrt(disc);
|
|
73
|
+
const roots = [(-b - sq) / 2, (-b + sq) / 2];
|
|
74
|
+
const hits = [];
|
|
75
|
+
for (const s of roots) {
|
|
76
|
+
if (s <= tolerance) continue;
|
|
77
|
+
const px = ox + s * ux;
|
|
78
|
+
const py = oy + s * uy;
|
|
79
|
+
if (arcAngleInRange(startAngleDeg, endAngleDeg, Math.atan2(py, px) * (180 / Math.PI))) hits.push(s);
|
|
80
|
+
}
|
|
81
|
+
hits.sort((a, z) => a - z);
|
|
82
|
+
return hits;
|
|
83
|
+
};
|
|
25
84
|
/**
|
|
26
85
|
* 椭圆弧参数点:中心 + 半轴 rx/ry + 参数角(度)→ 椭圆周上点
|
|
27
86
|
* @description 与 arcEndPoint 同角度约定(SVG y-down);endpoint = [cx + rx·cosθ, cy + ry·sinθ]。
|
|
@@ -39,17 +98,16 @@ var ellipseArcBoundingPoints = (center, radiusX, radiusY, startAngleDeg, endAngl
|
|
|
39
98
|
const points = [ellipseArcPoint(center, radiusX, radiusY, startAngleDeg), ellipseArcPoint(center, radiusX, radiusY, endAngleDeg)];
|
|
40
99
|
const lo = Math.min(startAngleDeg, endAngleDeg);
|
|
41
100
|
const hi = Math.max(startAngleDeg, endAngleDeg);
|
|
42
|
-
const
|
|
43
|
-
const kEnd = Math.floor(hi / 90);
|
|
44
|
-
for (let k = kStart; k <= kEnd; k++) {
|
|
45
|
-
const angle = k * 90;
|
|
101
|
+
for (const angle of axisAngles(lo, hi)) {
|
|
46
102
|
if (angle === startAngleDeg || angle === endAngleDeg) continue;
|
|
47
103
|
points.push(ellipseArcPoint(center, radiusX, radiusY, angle));
|
|
48
104
|
}
|
|
49
105
|
return points;
|
|
50
106
|
};
|
|
51
107
|
//#endregion
|
|
108
|
+
exports.arcAngleInRange = arcAngleInRange;
|
|
52
109
|
exports.arcBoundingPoints = arcBoundingPoints;
|
|
53
110
|
exports.arcEndPoint = arcEndPoint;
|
|
54
111
|
exports.ellipseArcBoundingPoints = ellipseArcBoundingPoints;
|
|
55
112
|
exports.ellipseArcPoint = ellipseArcPoint;
|
|
113
|
+
exports.rayArc = rayArc;
|
|
@@ -6,6 +6,20 @@ export declare const arcEndPoint: (center: Position, radius: number, angleDeg: n
|
|
|
6
6
|
* @description 弧投影到 x/y 轴的极值只可能在弧端点或圆周轴向四点出现。endAngle < startAngle 时按 min..max 扫描;跨 360°(270→450)按数值区间正确处理;不去重——端角恰在 90°·k 上时调用方处理
|
|
7
7
|
*/
|
|
8
8
|
export declare const arcBoundingPoints: (center: Position, radius: number, startAngleDeg: number, endAngleDeg: number) => Array<Position>;
|
|
9
|
+
/**
|
|
10
|
+
* 角度 a(度)是否落在弧的角度区间 [startAngle, endAngle] 内(含端点,带容差)
|
|
11
|
+
* @description 与 ir/path arc 同约定:弧从 startAngle 扫到 endAngle,counterClockwise=false(缺省)
|
|
12
|
+
* 时角度递增(屏幕顺时针)、true 时角度递减(逆时针)。统一把扫描量化为「从 start 出发、沿扫描方向
|
|
13
|
+
* 累积的非负 sweep ∈ [0, |span|]」判定,跨 360°、负角、巨型角都正确(不死循环)。
|
|
14
|
+
*/
|
|
15
|
+
export declare const arcAngleInRange: (startAngleDeg: number, endAngleDeg: number, angleDeg: number, toleranceDeg?: number) => boolean;
|
|
16
|
+
/**
|
|
17
|
+
* 射线(origin + 单位方向 dir)∩ 圆弧(center, radius, [startAngle, endAngle])
|
|
18
|
+
* @description 泛化 sector 的内联 rayCircle:先解 |origin + s·dir|² = radius² 得至多两个参数 s,
|
|
19
|
+
* 再用 arcAngleInRange 过滤掉不在弧角度区间内的交点。返回沿射线的正向参数 s(命中点 = origin + s·dir),
|
|
20
|
+
* 按 s 升序、仅含 s > tolerance 的正向交点;不在区间内的根被剔除。dir 必须为单位向量。
|
|
21
|
+
*/
|
|
22
|
+
export declare const rayArc: (origin: Position, dir: Position, center: Position, radius: number, startAngleDeg: number, endAngleDeg: number, tolerance?: number) => Array<number>;
|
|
9
23
|
/**
|
|
10
24
|
* 椭圆弧参数点:中心 + 半轴 rx/ry + 参数角(度)→ 椭圆周上点
|
|
11
25
|
* @description 与 arcEndPoint 同角度约定(SVG y-down);endpoint = [cx + rx·cosθ, cy + ry·sinθ]。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"arc.d.ts","sourceRoot":"","sources":["../../../src/geometry/arc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"arc.d.ts","sourceRoot":"","sources":["../../../src/geometry/arc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AA8BxC,iDAAiD;AACjD,eAAO,MAAM,WAAW,GACtB,QAAQ,QAAQ,EAChB,QAAQ,MAAM,EACd,UAAU,MAAM,KACf,QAMF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,QAAQ,EAChB,QAAQ,MAAM,EACd,eAAe,MAAM,EACrB,aAAa,MAAM,KAClB,KAAK,CAAC,QAAQ,CAchB,CAAC;AAQF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,GAC1B,eAAe,MAAM,EACrB,aAAa,MAAM,EACnB,UAAU,MAAM,EAChB,qBAAmB,KAClB,OASF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,MAAM,GACjB,QAAQ,QAAQ,EAChB,KAAK,QAAQ,EACb,QAAQ,QAAQ,EAChB,QAAQ,MAAM,EACd,eAAe,MAAM,EACrB,aAAa,MAAM,EACnB,kBAAgB,KACf,KAAK,CAAC,MAAM,CAuBd,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAC1B,QAAQ,QAAQ,EAChB,SAAS,MAAM,EACf,SAAS,MAAM,EACf,UAAU,MAAM,KACf,QAMF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,wBAAwB,GACnC,QAAQ,QAAQ,EAChB,SAAS,MAAM,EACf,SAAS,MAAM,EACf,eAAe,MAAM,EACrB,aAAa,MAAM,KAClB,KAAK,CAAC,QAAQ,CAYhB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/geometry/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,OAAO,CAAC;AACtB,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/geometry/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,OAAO,CAAC;AACtB,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC"}
|
|
@@ -82,15 +82,15 @@ var rect = {
|
|
|
82
82
|
/**
|
|
83
83
|
* 矩形 outline:两对角 → 顺时针 path 算子序列
|
|
84
84
|
* @description from/to 任意顺序,归一化 (x0,y0)=min、(x1,y1)=max。直角 = 4 line + close(起点左上 (x0,y0));
|
|
85
|
-
* 圆角 = 4 line + 4 quarter-arc + close(起点 (x0+r, y0))。
|
|
85
|
+
* 圆角 = 4 line + 4 quarter-arc + close(起点 (x0+r, y0))。cornerRadius clamp 到 min(w,h)/2。
|
|
86
86
|
* 角度约定同 geometry/arc(y-down:0=+x, 90=+y/下, 180=-x, 270=-y/上)。
|
|
87
87
|
*/
|
|
88
|
-
var rectOutline = (from, to,
|
|
88
|
+
var rectOutline = (from, to, cornerRadius) => {
|
|
89
89
|
const x0 = Math.min(from[0], to[0]);
|
|
90
90
|
const x1 = Math.max(from[0], to[0]);
|
|
91
91
|
const y0 = Math.min(from[1], to[1]);
|
|
92
92
|
const y1 = Math.max(from[1], to[1]);
|
|
93
|
-
const r =
|
|
93
|
+
const r = cornerRadius === void 0 ? 0 : Math.min(cornerRadius, (x1 - x0) / 2, (y1 - y0) / 2);
|
|
94
94
|
if (r <= 0) return [
|
|
95
95
|
{
|
|
96
96
|
kind: "move",
|
|
@@ -54,8 +54,8 @@ export type RectOutlineOp = {
|
|
|
54
54
|
/**
|
|
55
55
|
* 矩形 outline:两对角 → 顺时针 path 算子序列
|
|
56
56
|
* @description from/to 任意顺序,归一化 (x0,y0)=min、(x1,y1)=max。直角 = 4 line + close(起点左上 (x0,y0));
|
|
57
|
-
* 圆角 = 4 line + 4 quarter-arc + close(起点 (x0+r, y0))。
|
|
57
|
+
* 圆角 = 4 line + 4 quarter-arc + close(起点 (x0+r, y0))。cornerRadius clamp 到 min(w,h)/2。
|
|
58
58
|
* 角度约定同 geometry/arc(y-down:0=+x, 90=+y/下, 180=-x, 270=-y/上)。
|
|
59
59
|
*/
|
|
60
|
-
export declare const rectOutline: (from: Position, to: Position,
|
|
60
|
+
export declare const rectOutline: (from: Position, to: Position, cornerRadius?: number) => Array<RectOutlineOp>;
|
|
61
61
|
//# sourceMappingURL=rect.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rect.d.ts","sourceRoot":"","sources":["../../../src/geometry/rect.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,KAAK,IAAI,EAAa,MAAM,SAAS,CAAC;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,gCAAgC;AAChC,MAAM,MAAM,IAAI,GAAG;IACjB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,cAAc;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,YAAY;;;;;;;;;;CAUf,CAAC;AAEX,+BAA+B;AAC/B,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAE1E,eAAO,MAAM,IAAI;IACf,WAAW;gBACC,IAAI,KAAG,QAAQ;IAC3B,uBAAuB;kBACT,IAAI,KAAK,QAAQ,KAAG,OAAO;IAMzC,sCAAsC;gBAC1B,IAAI,QAAQ,UAAU,KAAG,QAAQ;IAuC7C,qDAAqD;uBAClC,IAAI,UAAU,QAAQ,KAAG,QAAQ;IAUpD,gEAAgE;mBACjD,IAAI,QAAQ,IAAI,KAAK,MAAM,KAAG,QAAQ;CAItD,CAAC;AAEF,4FAA4F;AAC5F,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,QAAQ,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,QAAQ,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACvF;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtB;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GACtB,MAAM,QAAQ,EACd,IAAI,QAAQ,EACZ,
|
|
1
|
+
{"version":3,"file":"rect.d.ts","sourceRoot":"","sources":["../../../src/geometry/rect.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,KAAK,IAAI,EAAa,MAAM,SAAS,CAAC;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,gCAAgC;AAChC,MAAM,MAAM,IAAI,GAAG;IACjB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,cAAc;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,YAAY;;;;;;;;;;CAUf,CAAC;AAEX,+BAA+B;AAC/B,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAE1E,eAAO,MAAM,IAAI;IACf,WAAW;gBACC,IAAI,KAAG,QAAQ;IAC3B,uBAAuB;kBACT,IAAI,KAAK,QAAQ,KAAG,OAAO;IAMzC,sCAAsC;gBAC1B,IAAI,QAAQ,UAAU,KAAG,QAAQ;IAuC7C,qDAAqD;uBAClC,IAAI,UAAU,QAAQ,KAAG,QAAQ;IAUpD,gEAAgE;mBACjD,IAAI,QAAQ,IAAI,KAAK,MAAM,KAAG,QAAQ;CAItD,CAAC;AAEF,4FAA4F;AAC5F,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,QAAQ,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,QAAQ,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACvF;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtB;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GACtB,MAAM,QAAQ,EACd,IAAI,QAAQ,EACZ,eAAe,MAAM,KACpB,KAAK,CAAC,aAAa,CAgCrB,CAAC"}
|