@cardenelabs/cdl 0.48.0 → 0.49.0
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/CHANGELOG.md +26 -1
- package/dist/index.cjs +171 -86
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +171 -86
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +160 -82
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +160 -82
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
- package/src/layout/collisions.ts +293 -139
- package/src/layout-with-validation.ts +4 -2
- package/src/visual-validate.ts +62 -6
package/dist/react.js
CHANGED
|
@@ -1839,7 +1839,7 @@ function resolveEdgeLabelOverlapsWithChainAndPropagate(edges, obstacles, minClea
|
|
|
1839
1839
|
{ axis: "y", sign: dy >= 0 ? 1 : -1 },
|
|
1840
1840
|
{ axis: "x", sign: dx >= 0 ? 1 : -1 }
|
|
1841
1841
|
];
|
|
1842
|
-
const \u52D5\u304B\u3057\u305F\
|
|
1842
|
+
const \u52D5\u304B\u3057\u305F\u7BB12 = (axis, sign) => ({
|
|
1843
1843
|
...label,
|
|
1844
1844
|
x: label.x + (axis === "x" ? sign * \u91CF : 0),
|
|
1845
1845
|
y: label.y + (axis === "y" ? sign * \u91CF : 0)
|
|
@@ -1864,7 +1864,7 @@ function resolveEdgeLabelOverlapsWithChainAndPropagate(edges, obstacles, minClea
|
|
|
1864
1864
|
return false;
|
|
1865
1865
|
};
|
|
1866
1866
|
for (const \u5019 of \u5019\u88DC) {
|
|
1867
|
-
if (\u60AA\u304F\u3059\u308B(\u52D5\u304B\u3057\u305F\
|
|
1867
|
+
if (\u60AA\u304F\u3059\u308B(\u52D5\u304B\u3057\u305F\u7BB12(\u5019.axis, \u5019.sign))) continue;
|
|
1868
1868
|
out.push({
|
|
1869
1869
|
target: { kind: "label", id: label.id },
|
|
1870
1870
|
axis: \u5019.axis,
|
|
@@ -2030,15 +2030,7 @@ function resolveEdgeLabelOverlapsWithChainAndPropagate(edges, obstacles, minClea
|
|
|
2030
2030
|
edgePathShifts: edgePathShiftMap
|
|
2031
2031
|
};
|
|
2032
2032
|
}
|
|
2033
|
-
function
|
|
2034
|
-
if (edges.length === 0) return edges;
|
|
2035
|
-
const labeledIds = new Set(
|
|
2036
|
-
edges.filter((e) => e.label?.trim() || e.sub?.trim()).map((e) => e.id)
|
|
2037
|
-
);
|
|
2038
|
-
if (labeledIds.size === 0) return edges;
|
|
2039
|
-
const \u7BB1\u305F\u3061 = obstacles.filter((o) => o.kind === "node" || o.kind === "lane-label");
|
|
2040
|
-
const edgeById = /* @__PURE__ */ new Map();
|
|
2041
|
-
for (const e of edges) edgeById.set(e.id, e);
|
|
2033
|
+
function \u7DDA\u306E\u6E2C\u308A\u65B9\u3092\u4F5C\u308B() {
|
|
2042
2034
|
const \u533A\u9593cache = /* @__PURE__ */ new Map();
|
|
2043
2035
|
const \u533A\u9593 = (id, d) => {
|
|
2044
2036
|
const hit = \u533A\u9593cache.get(id);
|
|
@@ -2074,7 +2066,143 @@ function resolveLabelClearanceAfterPathPasses(edges, obstacles, maxIter = 8) {
|
|
|
2074
2066
|
const dy = Math.max(0, Math.max(box.y - (b.y + b.h), b.y - (box.y + box.h)));
|
|
2075
2067
|
return Math.hypot(dx, dy) >= \u4F59\u88D5;
|
|
2076
2068
|
};
|
|
2077
|
-
|
|
2069
|
+
return { \u533A\u9593, \u9060\u3044 };
|
|
2070
|
+
}
|
|
2071
|
+
var \u672D\u306E\u6700\u5927\u79FB\u52D5 = CHAIN_SHIFT_MAX_ACCUMULATED * 2;
|
|
2072
|
+
var \u96E2\u308C\u91CF = (a, b) => ({
|
|
2073
|
+
x: Math.max(a.x - (b.x + b.w), b.x - (a.x + a.w)),
|
|
2074
|
+
y: Math.max(a.y - (b.y + b.h), b.y - (a.y + a.h))
|
|
2075
|
+
});
|
|
2076
|
+
var \u52D5\u304B\u3057\u305F\u7BB1 = (box, axis, sign, amount) => ({
|
|
2077
|
+
...box,
|
|
2078
|
+
x: box.x + (axis === "x" ? sign * amount : 0),
|
|
2079
|
+
y: box.y + (axis === "y" ? sign * amount : 0)
|
|
2080
|
+
});
|
|
2081
|
+
function \u672D\u306E\u79FB\u52D5\u3092\u585E\u3050\u76F8\u624B\u3092\u63A2\u3059(\u5468\u308A, label, \u884C\u304D\u5148) {
|
|
2082
|
+
const { \u7BB1\u305F\u3061, labels, edges, edgeById, \u6E2C\u308A\u65B9 } = \u5468\u308A;
|
|
2083
|
+
for (const obs of \u7BB1\u305F\u3061) {
|
|
2084
|
+
const \u524D = computeGap(label, obs);
|
|
2085
|
+
const \u5F8C = computeGap(\u884C\u304D\u5148, obs);
|
|
2086
|
+
if (\u5F8C < Math.min(\u524D, requiredNearClearance("edge-label", obs.kind))) return { \u76F8\u624B: `${obs.kind}:${obs.id}`, \u524D, \u5F8C };
|
|
2087
|
+
}
|
|
2088
|
+
const \u672D\u306E\u8981\u6C42 = requiredNearClearance("edge-label", "edge-label");
|
|
2089
|
+
for (const \u4ED6 of labels) {
|
|
2090
|
+
if (\u4ED6.id === label.id) continue;
|
|
2091
|
+
const \u524D = computeGap(label, \u4ED6);
|
|
2092
|
+
const \u5F8C = computeGap(\u884C\u304D\u5148, \u4ED6);
|
|
2093
|
+
if (\u5F8C < Math.min(\u524D, \u672D\u306E\u8981\u6C42)) return { \u76F8\u624B: `edge-label:${\u4ED6.id}`, \u524D, \u5F8C };
|
|
2094
|
+
}
|
|
2095
|
+
const \u81EA\u5206 = edgeById.get(label.id);
|
|
2096
|
+
const \u81EA\u5206\u306E\u533A\u9593 = \u81EA\u5206 ? \u6E2C\u308A\u65B9.\u533A\u9593(\u81EA\u5206.id, \u81EA\u5206.d) : [];
|
|
2097
|
+
if (\u81EA\u5206\u306E\u533A\u9593.length > 0) {
|
|
2098
|
+
const \u524D = measurePathLabelGapSegs(\u81EA\u5206\u306E\u533A\u9593, label);
|
|
2099
|
+
const \u5F8C = measurePathLabelGapSegs(\u81EA\u5206\u306E\u533A\u9593, \u884C\u304D\u5148);
|
|
2100
|
+
if (\u5F8C > Math.max(\u524D, DIST_LABEL_PATH_MAX)) return { \u76F8\u624B: "\u81EA\u5206\u306E\u7DDA", \u524D, \u5F8C };
|
|
2101
|
+
}
|
|
2102
|
+
for (const \u76F8\u624B of edges) {
|
|
2103
|
+
if (\u76F8\u624B.id === label.id) continue;
|
|
2104
|
+
if (\u6E2C\u308A\u65B9.\u9060\u3044(label, \u76F8\u624B.id, \u76F8\u624B.d, LABEL_TO_PATH_CLEARANCE) && \u6E2C\u308A\u65B9.\u9060\u3044(\u884C\u304D\u5148, \u76F8\u624B.id, \u76F8\u624B.d, LABEL_TO_PATH_CLEARANCE)) continue;
|
|
2105
|
+
const segs = segmentsExcludingOwnPath(\u6E2C\u308A\u65B9.\u533A\u9593(\u76F8\u624B.id, \u76F8\u624B.d), \u81EA\u5206\u306E\u533A\u9593);
|
|
2106
|
+
if (segs.length === 0) continue;
|
|
2107
|
+
const \u524D = measurePathLabelGapSegs(segs, label);
|
|
2108
|
+
const \u5F8C = measurePathLabelGapSegs(segs, \u884C\u304D\u5148);
|
|
2109
|
+
if (\u5F8C < Math.min(\u524D, LABEL_TO_PATH_CLEARANCE)) return { \u76F8\u624B: `edge-path:${\u76F8\u624B.id}`, \u524D, \u5F8C };
|
|
2110
|
+
}
|
|
2111
|
+
return null;
|
|
2112
|
+
}
|
|
2113
|
+
function \u77E9\u5F62\u306E\u5019\u88DC(label, static\u7BB1, required) {
|
|
2114
|
+
const sep = \u96E2\u308C\u91CF(label, static\u7BB1);
|
|
2115
|
+
const \u5411\u304D = (axis) => {
|
|
2116
|
+
const a = axis === "x" ? label.x + label.w / 2 : label.y + label.h / 2;
|
|
2117
|
+
const b = axis === "x" ? static\u7BB1.x + static\u7BB1.w / 2 : static\u7BB1.y + static\u7BB1.h / 2;
|
|
2118
|
+
return a >= b ? 1 : -1;
|
|
2119
|
+
};
|
|
2120
|
+
return [
|
|
2121
|
+
{ axis: "x", sign: \u5411\u304D("x"), amount: required - sep.x + NEAR_MISS_MARGIN },
|
|
2122
|
+
{ axis: "y", sign: \u5411\u304D("y"), amount: required - sep.y + NEAR_MISS_MARGIN }
|
|
2123
|
+
];
|
|
2124
|
+
}
|
|
2125
|
+
function \u7DDA\u304B\u3089\u96E2\u308C\u308B\u91CF(segs, label, gap, axis, sign) {
|
|
2126
|
+
const \u6700\u5927\u79FB\u52D5 = \u672D\u306E\u6700\u5927\u79FB\u52D5;
|
|
2127
|
+
const \u6E80\u305F\u3059 = (\u91CF) => measurePathLabelGapSegs(segs, \u52D5\u304B\u3057\u305F\u7BB1(label, axis, sign, \u91CF)) >= LABEL_TO_PATH_CLEARANCE;
|
|
2128
|
+
let lo = 0;
|
|
2129
|
+
let hi = Math.max(4, LABEL_TO_PATH_CLEARANCE - gap);
|
|
2130
|
+
while (!\u6E80\u305F\u3059(hi)) {
|
|
2131
|
+
if (hi >= \u6700\u5927\u79FB\u52D5) return null;
|
|
2132
|
+
lo = hi;
|
|
2133
|
+
hi = Math.min(hi * 2, \u6700\u5927\u79FB\u52D5);
|
|
2134
|
+
}
|
|
2135
|
+
for (let k = 0; k < 12; k += 1) {
|
|
2136
|
+
const mid = (lo + hi) / 2;
|
|
2137
|
+
if (\u6E80\u305F\u3059(mid)) hi = mid;
|
|
2138
|
+
else lo = mid;
|
|
2139
|
+
}
|
|
2140
|
+
return hi + NEAR_MISS_MARGIN;
|
|
2141
|
+
}
|
|
2142
|
+
var \u5411\u304D\u306E\u9806 = [
|
|
2143
|
+
{ axis: "y", sign: -1, \u540D\u524D: "\u4E0A" },
|
|
2144
|
+
{ axis: "y", sign: 1, \u540D\u524D: "\u4E0B" },
|
|
2145
|
+
{ axis: "x", sign: -1, \u540D\u524D: "\u5DE6" },
|
|
2146
|
+
{ axis: "x", sign: 1, \u540D\u524D: "\u53F3" }
|
|
2147
|
+
];
|
|
2148
|
+
function \u672D\u304C\u52D5\u3051\u306A\u3044\u7406\u7531(labelId, \u76F8\u624B, edges, obstacles) {
|
|
2149
|
+
const edgeById = new Map(edges.map((e) => [e.id, e]));
|
|
2150
|
+
const \u81EA\u5206 = edgeById.get(labelId);
|
|
2151
|
+
if (!\u81EA\u5206) return null;
|
|
2152
|
+
const labels = edges.filter((e) => e.label?.trim() || e.sub?.trim()).map((e) => ({ kind: "edge-label", id: e.id, ...computeLabelBBoxWorld(e) }));
|
|
2153
|
+
const label = labels.find((l) => l.id === labelId);
|
|
2154
|
+
if (!label) return null;
|
|
2155
|
+
const \u6E2C\u308A\u65B9 = \u7DDA\u306E\u6E2C\u308A\u65B9\u3092\u4F5C\u308B();
|
|
2156
|
+
const \u5468\u308A = {
|
|
2157
|
+
\u7BB1\u305F\u3061: obstacles.filter((o) => o.kind === "node" || o.kind === "lane-label"),
|
|
2158
|
+
labels,
|
|
2159
|
+
edges,
|
|
2160
|
+
edgeById,
|
|
2161
|
+
\u6E2C\u308A\u65B9
|
|
2162
|
+
};
|
|
2163
|
+
const \u5019\u88DC = [];
|
|
2164
|
+
if (\u76F8\u624B.kind === "edge-path") {
|
|
2165
|
+
const \u7DDA = edgeById.get(\u76F8\u624B.id);
|
|
2166
|
+
if (!\u7DDA) return null;
|
|
2167
|
+
const segs = segmentsExcludingOwnPath(\u6E2C\u308A\u65B9.\u533A\u9593(\u7DDA.id, \u7DDA.d), \u6E2C\u308A\u65B9.\u533A\u9593(\u81EA\u5206.id, \u81EA\u5206.d));
|
|
2168
|
+
if (segs.length === 0) return null;
|
|
2169
|
+
const gap = measurePathLabelGapSegs(segs, label);
|
|
2170
|
+
for (const \u5411\u304D of \u5411\u304D\u306E\u9806) {
|
|
2171
|
+
\u5019\u88DC.push({ axis: \u5411\u304D.axis, sign: \u5411\u304D.sign, amount: \u7DDA\u304B\u3089\u96E2\u308C\u308B\u91CF(segs, label, gap, \u5411\u304D.axis, \u5411\u304D.sign) });
|
|
2172
|
+
}
|
|
2173
|
+
} else {
|
|
2174
|
+
const required = requiredNearClearance("edge-label", \u76F8\u624B.kind);
|
|
2175
|
+
for (const c of \u77E9\u5F62\u306E\u5019\u88DC(label, \u76F8\u624B, required)) {
|
|
2176
|
+
if (c.amount > 0) \u5019\u88DC.push(c);
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
if (\u5019\u88DC.length === 0) return null;
|
|
2180
|
+
const \u7406\u7531 = [];
|
|
2181
|
+
for (const c of \u5019\u88DC) {
|
|
2182
|
+
const \u9806 = \u5411\u304D\u306E\u9806.findIndex((v) => v.axis === c.axis && v.sign === c.sign);
|
|
2183
|
+
const \u540D\u524D = \u5411\u304D\u306E\u9806[\u9806].\u540D\u524D;
|
|
2184
|
+
if (c.amount === null || c.amount > \u672D\u306E\u6700\u5927\u79FB\u52D5) {
|
|
2185
|
+
\u7406\u7531.push({ \u9806, \u6587: `${\u540D\u524D}=\u4E0A\u9650 ${\u672D\u306E\u6700\u5927\u79FB\u52D5} \u3092\u8D8A\u3048\u308B` });
|
|
2186
|
+
continue;
|
|
2187
|
+
}
|
|
2188
|
+
const \u585E\u3050 = \u672D\u306E\u79FB\u52D5\u3092\u585E\u3050\u76F8\u624B\u3092\u63A2\u3059(\u5468\u308A, label, \u52D5\u304B\u3057\u305F\u7BB1(label, c.axis, c.sign, c.amount));
|
|
2189
|
+
if (!\u585E\u3050) return null;
|
|
2190
|
+
\u7406\u7531.push({ \u9806, \u6587: `${\u540D\u524D}=${\u585E\u3050.\u76F8\u624B} (${\u585E\u3050.\u524D.toFixed(0)}\u2192${\u585E\u3050.\u5F8C.toFixed(0)})` });
|
|
2191
|
+
}
|
|
2192
|
+
return `\u9003\u3052\u5834\u306A\u3057: ${\u7406\u7531.sort((a, b) => a.\u9806 - b.\u9806).map((r) => r.\u6587).join(" / ")}`;
|
|
2193
|
+
}
|
|
2194
|
+
function resolveLabelClearanceAfterPathPasses(edges, obstacles, maxIter = 8) {
|
|
2195
|
+
if (edges.length === 0) return edges;
|
|
2196
|
+
const labeledIds = new Set(
|
|
2197
|
+
edges.filter((e) => e.label?.trim() || e.sub?.trim()).map((e) => e.id)
|
|
2198
|
+
);
|
|
2199
|
+
if (labeledIds.size === 0) return edges;
|
|
2200
|
+
const \u7BB1\u305F\u3061 = obstacles.filter((o) => o.kind === "node" || o.kind === "lane-label");
|
|
2201
|
+
const edgeById = /* @__PURE__ */ new Map();
|
|
2202
|
+
for (const e of edges) edgeById.set(e.id, e);
|
|
2203
|
+
const \u6E2C\u308A\u65B9 = \u7DDA\u306E\u6E2C\u308A\u65B9\u3092\u4F5C\u308B();
|
|
2204
|
+
const { \u533A\u9593, \u9060\u3044 } = \u6E2C\u308A\u65B9;
|
|
2205
|
+
const \u6700\u5927\u79FB\u52D5 = \u672D\u306E\u6700\u5927\u79FB\u52D5;
|
|
2078
2206
|
const shiftMap = /* @__PURE__ */ new Map();
|
|
2079
2207
|
const getShift = (id) => shiftMap.get(id) ?? { dx: 0, dy: 0 };
|
|
2080
2208
|
const labelBBoxes = () => {
|
|
@@ -2087,50 +2215,12 @@ function resolveLabelClearanceAfterPathPasses(edges, obstacles, maxIter = 8) {
|
|
|
2087
2215
|
}
|
|
2088
2216
|
return out;
|
|
2089
2217
|
};
|
|
2090
|
-
const \u96E2\u308C\u91CF = (a, b) => ({
|
|
2091
|
-
x: Math.max(a.x - (b.x + b.w), b.x - (a.x + a.w)),
|
|
2092
|
-
y: Math.max(a.y - (b.y + b.h), b.y - (a.y + a.h))
|
|
2093
|
-
});
|
|
2094
|
-
const \u52D5\u304B\u3057\u305F\u7BB1 = (box, axis, sign, amount) => ({
|
|
2095
|
-
...box,
|
|
2096
|
-
x: box.x + (axis === "x" ? sign * amount : 0),
|
|
2097
|
-
y: box.y + (axis === "y" ? sign * amount : 0)
|
|
2098
|
-
});
|
|
2099
2218
|
for (let iter = 0; iter < maxIter; iter += 1) {
|
|
2100
2219
|
const labels = labelBBoxes();
|
|
2101
2220
|
const \u672D\u306E\u8981\u6C42 = requiredNearClearance("edge-label", "edge-label");
|
|
2102
2221
|
let \u52D5\u3044\u305F = false;
|
|
2103
2222
|
const \u4ECA\u56DE\u52D5\u304B\u3057\u305F = /* @__PURE__ */ new Set();
|
|
2104
|
-
const \u5B89\u5168\u304B = (label, \u884C\u304D\u5148) => {
|
|
2105
|
-
for (const obs of \u7BB1\u305F\u3061) {
|
|
2106
|
-
const \u524D = computeGap(label, obs);
|
|
2107
|
-
const \u5F8C = computeGap(\u884C\u304D\u5148, obs);
|
|
2108
|
-
if (\u5F8C < Math.min(\u524D, requiredNearClearance("edge-label", obs.kind))) return false;
|
|
2109
|
-
}
|
|
2110
|
-
for (const \u4ED6 of labels) {
|
|
2111
|
-
if (\u4ED6.id === label.id) continue;
|
|
2112
|
-
const \u524D = computeGap(label, \u4ED6);
|
|
2113
|
-
const \u5F8C = computeGap(\u884C\u304D\u5148, \u4ED6);
|
|
2114
|
-
if (\u5F8C < Math.min(\u524D, \u672D\u306E\u8981\u6C42)) return false;
|
|
2115
|
-
}
|
|
2116
|
-
const \u81EA\u5206 = edgeById.get(label.id);
|
|
2117
|
-
const \u81EA\u5206\u306E\u533A\u9593 = \u81EA\u5206 ? \u533A\u9593(\u81EA\u5206.id, \u81EA\u5206.d) : [];
|
|
2118
|
-
if (\u81EA\u5206\u306E\u533A\u9593.length > 0) {
|
|
2119
|
-
const \u524D = measurePathLabelGapSegs(\u81EA\u5206\u306E\u533A\u9593, label);
|
|
2120
|
-
const \u5F8C = measurePathLabelGapSegs(\u81EA\u5206\u306E\u533A\u9593, \u884C\u304D\u5148);
|
|
2121
|
-
if (\u5F8C > Math.max(\u524D, DIST_LABEL_PATH_MAX)) return false;
|
|
2122
|
-
}
|
|
2123
|
-
for (const \u76F8\u624B of edges) {
|
|
2124
|
-
if (\u76F8\u624B.id === label.id) continue;
|
|
2125
|
-
if (\u9060\u3044(label, \u76F8\u624B.id, \u76F8\u624B.d, LABEL_TO_PATH_CLEARANCE) && \u9060\u3044(\u884C\u304D\u5148, \u76F8\u624B.id, \u76F8\u624B.d, LABEL_TO_PATH_CLEARANCE)) continue;
|
|
2126
|
-
const segs = segmentsExcludingOwnPath(\u533A\u9593(\u76F8\u624B.id, \u76F8\u624B.d), \u81EA\u5206\u306E\u533A\u9593);
|
|
2127
|
-
if (segs.length === 0) continue;
|
|
2128
|
-
const \u524D = measurePathLabelGapSegs(segs, label);
|
|
2129
|
-
const \u5F8C = measurePathLabelGapSegs(segs, \u884C\u304D\u5148);
|
|
2130
|
-
if (\u5F8C < Math.min(\u524D, LABEL_TO_PATH_CLEARANCE)) return false;
|
|
2131
|
-
}
|
|
2132
|
-
return true;
|
|
2133
|
-
};
|
|
2223
|
+
const \u5B89\u5168\u304B = (label, \u884C\u304D\u5148) => \u672D\u306E\u79FB\u52D5\u3092\u585E\u3050\u76F8\u624B\u3092\u63A2\u3059({ \u7BB1\u305F\u3061, labels, edges, edgeById, \u6E2C\u308A\u65B9 }, label, \u884C\u304D\u5148) === null;
|
|
2134
2224
|
const \u9003\u304C\u3059 = (label, \u5019\u88DC) => {
|
|
2135
2225
|
for (const c of \u5019\u88DC.slice().sort((a, b) => a.amount - b.amount)) {
|
|
2136
2226
|
if (c.amount <= 0) continue;
|
|
@@ -2146,18 +2236,6 @@ function resolveLabelClearanceAfterPathPasses(edges, obstacles, maxIter = 8) {
|
|
|
2146
2236
|
}
|
|
2147
2237
|
return false;
|
|
2148
2238
|
};
|
|
2149
|
-
const \u77E9\u5F62\u306E\u5019\u88DC = (label, static\u7BB1, required) => {
|
|
2150
|
-
const sep = \u96E2\u308C\u91CF(label, static\u7BB1);
|
|
2151
|
-
const \u5411\u304D = (axis) => {
|
|
2152
|
-
const a = axis === "x" ? label.x + label.w / 2 : label.y + label.h / 2;
|
|
2153
|
-
const b = axis === "x" ? static\u7BB1.x + static\u7BB1.w / 2 : static\u7BB1.y + static\u7BB1.h / 2;
|
|
2154
|
-
return a >= b ? 1 : -1;
|
|
2155
|
-
};
|
|
2156
|
-
return [
|
|
2157
|
-
{ axis: "x", sign: \u5411\u304D("x"), amount: required - sep.x + NEAR_MISS_MARGIN },
|
|
2158
|
-
{ axis: "y", sign: \u5411\u304D("y"), amount: required - sep.y + NEAR_MISS_MARGIN }
|
|
2159
|
-
];
|
|
2160
|
-
};
|
|
2161
2239
|
for (const label of labels) {
|
|
2162
2240
|
if (\u4ECA\u56DE\u52D5\u304B\u3057\u305F.has(label.id)) continue;
|
|
2163
2241
|
for (const obs of \u7BB1\u305F\u3061) {
|
|
@@ -2214,22 +2292,7 @@ function resolveLabelClearanceAfterPathPasses(edges, obstacles, maxIter = 8) {
|
|
|
2214
2292
|
}
|
|
2215
2293
|
}
|
|
2216
2294
|
if (!\u8FD1\u3044\u70B9) continue;
|
|
2217
|
-
const \u5FC5\u8981\u91CF = (axis, sign) =>
|
|
2218
|
-
const \u6E80\u305F\u3059 = (\u91CF) => measurePathLabelGapSegs(segs, \u52D5\u304B\u3057\u305F\u7BB1(label, axis, sign, \u91CF)) >= LABEL_TO_PATH_CLEARANCE;
|
|
2219
|
-
let lo = 0;
|
|
2220
|
-
let hi = Math.max(4, LABEL_TO_PATH_CLEARANCE - gap);
|
|
2221
|
-
while (!\u6E80\u305F\u3059(hi)) {
|
|
2222
|
-
if (hi >= \u6700\u5927\u79FB\u52D5) return null;
|
|
2223
|
-
lo = hi;
|
|
2224
|
-
hi = Math.min(hi * 2, \u6700\u5927\u79FB\u52D5);
|
|
2225
|
-
}
|
|
2226
|
-
for (let k = 0; k < 12; k += 1) {
|
|
2227
|
-
const mid = (lo + hi) / 2;
|
|
2228
|
-
if (\u6E80\u305F\u3059(mid)) hi = mid;
|
|
2229
|
-
else lo = mid;
|
|
2230
|
-
}
|
|
2231
|
-
return hi + NEAR_MISS_MARGIN;
|
|
2232
|
-
};
|
|
2295
|
+
const \u5FC5\u8981\u91CF = (axis, sign) => \u7DDA\u304B\u3089\u96E2\u308C\u308B\u91CF(segs, label, gap, axis, sign);
|
|
2233
2296
|
const dx = \u82AF.x - \u8FD1\u3044\u70B9.x;
|
|
2234
2297
|
const dy = \u82AF.y - \u8FD1\u3044\u70B9.y;
|
|
2235
2298
|
const \u5019\u88DC = [];
|
|
@@ -4965,9 +5028,15 @@ function visualValidateLaid(laid, diag, opts) {
|
|
|
4965
5028
|
const counts = emptyCounts();
|
|
4966
5029
|
const profile = "production";
|
|
4967
5030
|
const skipped = SKIPPED_AXES[profile];
|
|
4968
|
-
const push = (axis, detail, severity = "error") => {
|
|
5031
|
+
const push = (axis, detail, severity = "error", reason) => {
|
|
4969
5032
|
if (skipped.has(axis)) return;
|
|
4970
|
-
violations.push({
|
|
5033
|
+
violations.push({
|
|
5034
|
+
axis,
|
|
5035
|
+
diagramId: safeDiagramId(diag),
|
|
5036
|
+
detail,
|
|
5037
|
+
severity,
|
|
5038
|
+
...reason !== void 0 ? { reason } : {}
|
|
5039
|
+
});
|
|
4971
5040
|
counts[axis]++;
|
|
4972
5041
|
};
|
|
4973
5042
|
return visualValidateInner(
|
|
@@ -5279,10 +5348,19 @@ function runAxes(laid, diag, violations, counts, push, profile, skippedAxes, \u5
|
|
|
5279
5348
|
}
|
|
5280
5349
|
}
|
|
5281
5350
|
const nears = detectNearCollisions(bboxes, laid.edges);
|
|
5351
|
+
const \u672D\u306E\u969C\u5BB3\u7269 = bboxes.filter((b) => b.kind === "node" || b.kind === "lane-label");
|
|
5352
|
+
const \u8FBA\u306E\u9806 = new Map(laid.edges.map((e, i) => [e.id, i]));
|
|
5282
5353
|
for (const n of nears) {
|
|
5354
|
+
const a\u306F\u672D = n.a.kind === "edge-label";
|
|
5355
|
+
const b\u306F\u672D = n.b.kind === "edge-label";
|
|
5356
|
+
const \u52D5\u304B\u3059 = a\u306F\u672D && b\u306F\u672D ? (\u8FBA\u306E\u9806.get(n.a.id) ?? 0) > (\u8FBA\u306E\u9806.get(n.b.id) ?? 0) ? n.a : n.b : a\u306F\u672D ? n.a : b\u306F\u672D ? n.b : null;
|
|
5357
|
+
const \u76F8\u624B = \u52D5\u304B\u3059 === n.a ? n.b : n.a;
|
|
5358
|
+
const reason = \u52D5\u304B\u3059 !== null ? \u672D\u304C\u52D5\u3051\u306A\u3044\u7406\u7531(\u52D5\u304B\u3059.id, \u76F8\u624B, laid.edges, \u672D\u306E\u969C\u5BB3\u7269) ?? void 0 : void 0;
|
|
5283
5359
|
push(
|
|
5284
5360
|
"clearance",
|
|
5285
|
-
`${n.a.kind}:${n.a.id} \u2194 ${n.b.kind}:${n.b.id} gap=${n.gap.toFixed(1)}px (need ${n.required}px)
|
|
5361
|
+
`${n.a.kind}:${n.a.id} \u2194 ${n.b.kind}:${n.b.id} gap=${n.gap.toFixed(1)}px (need ${n.required}px)`,
|
|
5362
|
+
"error",
|
|
5363
|
+
reason
|
|
5286
5364
|
);
|
|
5287
5365
|
}
|
|
5288
5366
|
const PROXIMITY_WARN_THRESHOLD = DIST_LABEL_PATH_MAX;
|