@crazyhappyone/auto-graph 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.cjs +352 -31
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +352 -31
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +353 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -2
- package/dist/index.d.ts +16 -2
- package/dist/index.js +353 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.cjs
CHANGED
|
@@ -3147,6 +3147,15 @@ function fitDslLabel(label, measurer) {
|
|
|
3147
3147
|
function point(value) {
|
|
3148
3148
|
return { x: value.x, y: value.y };
|
|
3149
3149
|
}
|
|
3150
|
+
|
|
3151
|
+
// src/ir/diagnostics.ts
|
|
3152
|
+
var DELIVERABILITY_DIAGNOSTIC_CODES = /* @__PURE__ */ new Set([
|
|
3153
|
+
"constraints.locked-target-not-moved",
|
|
3154
|
+
"routing.evidence.crossing_forbidden",
|
|
3155
|
+
"routing.obstacle.unavoidable",
|
|
3156
|
+
"route_obstacle_fallback",
|
|
3157
|
+
"routing.text-clearance.unresolved"
|
|
3158
|
+
]);
|
|
3150
3159
|
var DEFAULT_OPTIONS = {
|
|
3151
3160
|
nodesep: 80,
|
|
3152
3161
|
ranksep: 100,
|
|
@@ -3345,6 +3354,51 @@ function routeEdge(input) {
|
|
|
3345
3354
|
)
|
|
3346
3355
|
);
|
|
3347
3356
|
if (hardClearCandidate !== void 0) {
|
|
3357
|
+
let bestPoints2 = hardClearCandidate.points;
|
|
3358
|
+
if (input.kind === "obstacle-avoiding") {
|
|
3359
|
+
const allObstacles = [...softObstacles, ...hardObstacles];
|
|
3360
|
+
for (const candidate of candidateRoutes) {
|
|
3361
|
+
if (routeCrossesBoxes(candidate.points, hardObstacles) || routeIntersectsEndpointInteriors(
|
|
3362
|
+
candidate.points,
|
|
3363
|
+
candidate.endpointObstacles
|
|
3364
|
+
)) {
|
|
3365
|
+
continue;
|
|
3366
|
+
}
|
|
3367
|
+
const rerouted2 = greedyRerouteAroundObstacles(
|
|
3368
|
+
candidate.points,
|
|
3369
|
+
allObstacles,
|
|
3370
|
+
3
|
|
3371
|
+
);
|
|
3372
|
+
if (!routeCrossesBoxes(rerouted2, allObstacles) && !routeIntersectsEndpointInteriors(
|
|
3373
|
+
rerouted2,
|
|
3374
|
+
candidate.endpointObstacles
|
|
3375
|
+
)) {
|
|
3376
|
+
return {
|
|
3377
|
+
points: finalizeRoute(
|
|
3378
|
+
rerouted2,
|
|
3379
|
+
softObstacles,
|
|
3380
|
+
hardObstacles,
|
|
3381
|
+
diagnostics
|
|
3382
|
+
),
|
|
3383
|
+
diagnostics
|
|
3384
|
+
};
|
|
3385
|
+
}
|
|
3386
|
+
}
|
|
3387
|
+
const rerouted = greedyRerouteAroundObstacles(
|
|
3388
|
+
bestPoints2,
|
|
3389
|
+
allObstacles,
|
|
3390
|
+
3
|
|
3391
|
+
);
|
|
3392
|
+
const reroutedAvoidsEndpointInteriors = !routeIntersectsEndpointInteriors(
|
|
3393
|
+
rerouted,
|
|
3394
|
+
hardClearCandidate.endpointObstacles
|
|
3395
|
+
);
|
|
3396
|
+
if (reroutedAvoidsEndpointInteriors) {
|
|
3397
|
+
if (routeCrossesBoxes(rerouted, hardObstacles) && !routeCrossesBoxes(bestPoints2, hardObstacles)) ; else {
|
|
3398
|
+
bestPoints2 = rerouted;
|
|
3399
|
+
}
|
|
3400
|
+
}
|
|
3401
|
+
}
|
|
3348
3402
|
diagnostics.push({
|
|
3349
3403
|
severity: "warning",
|
|
3350
3404
|
code: "routing.obstacle.unavoidable",
|
|
@@ -3352,7 +3406,7 @@ function routeEdge(input) {
|
|
|
3352
3406
|
});
|
|
3353
3407
|
return {
|
|
3354
3408
|
points: finalizeRoute(
|
|
3355
|
-
|
|
3409
|
+
bestPoints2,
|
|
3356
3410
|
softObstacles,
|
|
3357
3411
|
hardObstacles,
|
|
3358
3412
|
diagnostics
|
|
@@ -3361,6 +3415,33 @@ function routeEdge(input) {
|
|
|
3361
3415
|
};
|
|
3362
3416
|
}
|
|
3363
3417
|
if (hardObstacles.length > 0) {
|
|
3418
|
+
let bestPoints2 = candidateRoutes[0]?.points ?? fallbackRoute(input, defaultAnchors);
|
|
3419
|
+
if (input.kind === "obstacle-avoiding") {
|
|
3420
|
+
const allObstacles = [...softObstacles, ...hardObstacles];
|
|
3421
|
+
for (const candidate of candidateRoutes) {
|
|
3422
|
+
const rerouted = greedyRerouteAroundObstacles(
|
|
3423
|
+
candidate.points,
|
|
3424
|
+
allObstacles,
|
|
3425
|
+
5
|
|
3426
|
+
);
|
|
3427
|
+
if (!routeCrossesBoxes(rerouted, allObstacles)) {
|
|
3428
|
+
return {
|
|
3429
|
+
points: finalizeRoute(
|
|
3430
|
+
rerouted,
|
|
3431
|
+
softObstacles,
|
|
3432
|
+
hardObstacles,
|
|
3433
|
+
diagnostics
|
|
3434
|
+
),
|
|
3435
|
+
diagnostics
|
|
3436
|
+
};
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
bestPoints2 = greedyRerouteAroundObstacles(
|
|
3440
|
+
candidateRoutes[0]?.points ?? fallbackRoute(input, defaultAnchors),
|
|
3441
|
+
allObstacles,
|
|
3442
|
+
5
|
|
3443
|
+
);
|
|
3444
|
+
}
|
|
3364
3445
|
diagnostics.push({
|
|
3365
3446
|
severity: "error",
|
|
3366
3447
|
code: "routing.evidence.crossing_forbidden",
|
|
@@ -3368,7 +3449,7 @@ function routeEdge(input) {
|
|
|
3368
3449
|
});
|
|
3369
3450
|
return {
|
|
3370
3451
|
points: finalizeRoute(
|
|
3371
|
-
|
|
3452
|
+
bestPoints2,
|
|
3372
3453
|
softObstacles,
|
|
3373
3454
|
hardObstacles,
|
|
3374
3455
|
diagnostics
|
|
@@ -3376,6 +3457,33 @@ function routeEdge(input) {
|
|
|
3376
3457
|
diagnostics
|
|
3377
3458
|
};
|
|
3378
3459
|
}
|
|
3460
|
+
let bestPoints = candidateRoutes[0]?.points ?? fallbackRoute(input, defaultAnchors);
|
|
3461
|
+
if (input.kind === "obstacle-avoiding") {
|
|
3462
|
+
const allObstacles = [...softObstacles, ...hardObstacles];
|
|
3463
|
+
for (const candidate of candidateRoutes) {
|
|
3464
|
+
const rerouted = greedyRerouteAroundObstacles(
|
|
3465
|
+
candidate.points,
|
|
3466
|
+
allObstacles,
|
|
3467
|
+
5
|
|
3468
|
+
);
|
|
3469
|
+
if (!routeCrossesBoxes(rerouted, allObstacles)) {
|
|
3470
|
+
return {
|
|
3471
|
+
points: finalizeRoute(
|
|
3472
|
+
rerouted,
|
|
3473
|
+
softObstacles,
|
|
3474
|
+
hardObstacles,
|
|
3475
|
+
diagnostics
|
|
3476
|
+
),
|
|
3477
|
+
diagnostics
|
|
3478
|
+
};
|
|
3479
|
+
}
|
|
3480
|
+
}
|
|
3481
|
+
bestPoints = greedyRerouteAroundObstacles(
|
|
3482
|
+
candidateRoutes[0]?.points ?? fallbackRoute(input, defaultAnchors),
|
|
3483
|
+
allObstacles,
|
|
3484
|
+
5
|
|
3485
|
+
);
|
|
3486
|
+
}
|
|
3379
3487
|
diagnostics.push({
|
|
3380
3488
|
severity: "warning",
|
|
3381
3489
|
code: "routing.obstacle.unavoidable",
|
|
@@ -3383,7 +3491,7 @@ function routeEdge(input) {
|
|
|
3383
3491
|
});
|
|
3384
3492
|
return {
|
|
3385
3493
|
points: finalizeRoute(
|
|
3386
|
-
|
|
3494
|
+
bestPoints,
|
|
3387
3495
|
softObstacles,
|
|
3388
3496
|
hardObstacles,
|
|
3389
3497
|
diagnostics
|
|
@@ -3393,21 +3501,29 @@ function routeEdge(input) {
|
|
|
3393
3501
|
}
|
|
3394
3502
|
function finalizeRoute(points, softObstacles, hardObstacles, diagnostics) {
|
|
3395
3503
|
const simplified = simplifyRoute(points);
|
|
3504
|
+
if (simplified.length >= 3) {
|
|
3505
|
+
return simplified;
|
|
3506
|
+
}
|
|
3396
3507
|
const crossesHardObstacles = routeCrossesBoxes(simplified, hardObstacles);
|
|
3397
3508
|
const crossesSoftObstacles = routeCrossesBoxes(simplified, softObstacles);
|
|
3398
|
-
if (
|
|
3509
|
+
if (!crossesHardObstacles && !crossesSoftObstacles) {
|
|
3510
|
+
return simplified;
|
|
3511
|
+
}
|
|
3512
|
+
const expanded = expandFallbackRoute(simplified, [
|
|
3513
|
+
...softObstacles,
|
|
3514
|
+
...hardObstacles
|
|
3515
|
+
]);
|
|
3516
|
+
const expandedCrossesHard = routeCrossesBoxes(expanded, hardObstacles);
|
|
3517
|
+
const expandedCrossesSoft = routeCrossesBoxes(expanded, softObstacles);
|
|
3518
|
+
if (expandedCrossesHard || expandedCrossesSoft) {
|
|
3399
3519
|
diagnostics.push({
|
|
3400
|
-
severity:
|
|
3520
|
+
severity: expandedCrossesHard ? "error" : "warning",
|
|
3401
3521
|
code: "route_obstacle_fallback",
|
|
3402
3522
|
message: "Obstacle-aware routing fell back to fewer than three route points.",
|
|
3403
3523
|
detail: { pointCount: simplified.length }
|
|
3404
3524
|
});
|
|
3405
|
-
return expandFallbackRoute(simplified, [
|
|
3406
|
-
...softObstacles,
|
|
3407
|
-
...hardObstacles
|
|
3408
|
-
]);
|
|
3409
3525
|
}
|
|
3410
|
-
return
|
|
3526
|
+
return expanded;
|
|
3411
3527
|
}
|
|
3412
3528
|
function expandFallbackRoute(points, obstacles) {
|
|
3413
3529
|
if (points.length !== 2) {
|
|
@@ -3438,12 +3554,12 @@ function expandFallbackRoute(points, obstacles) {
|
|
|
3438
3554
|
const hv = diagonalDetourHV(source, target, obstacles);
|
|
3439
3555
|
const vh = diagonalDetourVH(source, target, obstacles);
|
|
3440
3556
|
const viable = [hv, vh].filter((c) => !routeCrossesBoxes(c, obstacles));
|
|
3441
|
-
|
|
3557
|
+
const [firstViable, ...remainingViable] = viable;
|
|
3558
|
+
if (firstViable !== void 0) {
|
|
3442
3559
|
const directLen = Math.hypot(target.x - source.x, target.y - source.y);
|
|
3443
|
-
let best =
|
|
3444
|
-
for (
|
|
3445
|
-
|
|
3446
|
-
if (cand !== void 0 && pathLength(cand) - directLen < pathLength(best) - directLen) {
|
|
3560
|
+
let best = firstViable;
|
|
3561
|
+
for (const cand of remainingViable) {
|
|
3562
|
+
if (pathLength(cand) - directLen < pathLength(best) - directLen) {
|
|
3447
3563
|
best = cand;
|
|
3448
3564
|
}
|
|
3449
3565
|
}
|
|
@@ -3533,6 +3649,70 @@ function insetBox(box, margin) {
|
|
|
3533
3649
|
height: box.height - margin * 2
|
|
3534
3650
|
};
|
|
3535
3651
|
}
|
|
3652
|
+
function greedyRerouteAroundObstacles(points, obstacles, maxIterations) {
|
|
3653
|
+
let current = [...points];
|
|
3654
|
+
for (let iter = 0; iter < maxIterations; iter++) {
|
|
3655
|
+
const improved = pushRouteAwayFromObstacles(current, obstacles);
|
|
3656
|
+
if (improved === null) {
|
|
3657
|
+
break;
|
|
3658
|
+
}
|
|
3659
|
+
current = improved;
|
|
3660
|
+
if (!routeCrossesBoxes(current, obstacles)) {
|
|
3661
|
+
break;
|
|
3662
|
+
}
|
|
3663
|
+
}
|
|
3664
|
+
return current;
|
|
3665
|
+
}
|
|
3666
|
+
function pushRouteAwayFromObstacles(points, obstacles) {
|
|
3667
|
+
const result = [];
|
|
3668
|
+
let improved = false;
|
|
3669
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
3670
|
+
const a = points[i];
|
|
3671
|
+
const b = points[i + 1];
|
|
3672
|
+
if (a === void 0 || b === void 0) {
|
|
3673
|
+
result.push(a ?? b ?? { x: 0, y: 0 });
|
|
3674
|
+
continue;
|
|
3675
|
+
}
|
|
3676
|
+
result.push(a);
|
|
3677
|
+
const intersectors = obstacles.filter(
|
|
3678
|
+
(obs) => segmentIntersectsBox(a, b, obs)
|
|
3679
|
+
);
|
|
3680
|
+
if (intersectors.length === 0) {
|
|
3681
|
+
continue;
|
|
3682
|
+
}
|
|
3683
|
+
const mx = (a.x + b.x) / 2;
|
|
3684
|
+
const my = (a.y + b.y) / 2;
|
|
3685
|
+
const isHorizontal = a.y === b.y;
|
|
3686
|
+
const margin = 12;
|
|
3687
|
+
let bestWaypoint = null;
|
|
3688
|
+
let bestDist = Infinity;
|
|
3689
|
+
for (const obs of intersectors) {
|
|
3690
|
+
const candidates = isHorizontal ? [
|
|
3691
|
+
{ x: mx, y: obs.y - margin },
|
|
3692
|
+
{ x: mx, y: obs.y + obs.height + margin }
|
|
3693
|
+
] : [
|
|
3694
|
+
{ x: obs.x - margin, y: my },
|
|
3695
|
+
{ x: obs.x + obs.width + margin, y: my }
|
|
3696
|
+
];
|
|
3697
|
+
for (const wp of candidates) {
|
|
3698
|
+
const dist = Math.hypot(wp.x - mx, wp.y - my);
|
|
3699
|
+
if (dist < bestDist) {
|
|
3700
|
+
bestDist = dist;
|
|
3701
|
+
bestWaypoint = wp;
|
|
3702
|
+
}
|
|
3703
|
+
}
|
|
3704
|
+
}
|
|
3705
|
+
if (bestWaypoint !== null) {
|
|
3706
|
+
result.push(bestWaypoint);
|
|
3707
|
+
improved = true;
|
|
3708
|
+
}
|
|
3709
|
+
}
|
|
3710
|
+
const last = points[points.length - 1];
|
|
3711
|
+
if (last !== void 0) {
|
|
3712
|
+
result.push(last);
|
|
3713
|
+
}
|
|
3714
|
+
return improved ? result : null;
|
|
3715
|
+
}
|
|
3536
3716
|
function fallbackRoute(input, defaultAnchors) {
|
|
3537
3717
|
return [
|
|
3538
3718
|
getEdgePort(
|
|
@@ -4029,6 +4209,7 @@ function solveDiagram(diagram, options = {}) {
|
|
|
4029
4209
|
];
|
|
4030
4210
|
const initialContentBounds = layoutBoxes.length === 0 ? { x: 0, y: 0, width: 0} : unionBoxes(layoutBoxes);
|
|
4031
4211
|
placeEvidenceBlocks(
|
|
4212
|
+
options.obstacleMargin ?? 0,
|
|
4032
4213
|
[
|
|
4033
4214
|
...coordinatedMatrices,
|
|
4034
4215
|
...coordinatedTables,
|
|
@@ -4095,17 +4276,35 @@ function solveDiagram(diagram, options = {}) {
|
|
|
4095
4276
|
...baseTextAnnotations.filter(isPreRouteTextObstacle),
|
|
4096
4277
|
...frameTextAnnotation.filter(isPreRouteTextObstacle)
|
|
4097
4278
|
];
|
|
4279
|
+
const margin = options.obstacleMargin ?? 0;
|
|
4280
|
+
const softObstacles = [
|
|
4281
|
+
...coordinatedTables.map((table) => expandBox(table.box, margin)),
|
|
4282
|
+
...coordinatedEvidencePanels.map((panel) => expandBox(panel.box, margin))
|
|
4283
|
+
];
|
|
4284
|
+
const hardObstacles = coordinatedMatrices.map(
|
|
4285
|
+
(matrix) => expandBox(matrix.box, margin)
|
|
4286
|
+
);
|
|
4287
|
+
const titleBarObstacles = [];
|
|
4288
|
+
if (frame !== void 0) {
|
|
4289
|
+
titleBarObstacles.push(expandBox(frame.titleBox, margin));
|
|
4290
|
+
}
|
|
4291
|
+
for (const swimlane of coordinatedSwimlanes) {
|
|
4292
|
+
for (const lane of swimlane.lanes) {
|
|
4293
|
+
if (lane.headerBox !== void 0 && lane.headerBox.width > 0 && lane.headerBox.height > 0) {
|
|
4294
|
+
titleBarObstacles.push(expandBox(lane.headerBox, margin));
|
|
4295
|
+
}
|
|
4296
|
+
}
|
|
4297
|
+
}
|
|
4098
4298
|
const coordinatedEdges = coordinateEdges(
|
|
4099
4299
|
styledEdges,
|
|
4100
4300
|
nodeGeometryById,
|
|
4101
4301
|
coordinatedNodes,
|
|
4102
|
-
[...nodeGeometryById.values()].map(
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
],
|
|
4302
|
+
[...nodeGeometryById.values()].map(
|
|
4303
|
+
(geometry) => options.routingGutter === void 0 ? geometry.obstacleBox : expandBox(geometry.obstacleBox, options.routingGutter)
|
|
4304
|
+
),
|
|
4305
|
+
[...softObstacles, ...titleBarObstacles],
|
|
4107
4306
|
routingTextObstacles,
|
|
4108
|
-
|
|
4307
|
+
hardObstacles,
|
|
4109
4308
|
diagram.direction,
|
|
4110
4309
|
options,
|
|
4111
4310
|
diagnostics
|
|
@@ -4140,6 +4339,16 @@ function solveDiagram(diagram, options = {}) {
|
|
|
4140
4339
|
options.pageBounds
|
|
4141
4340
|
)
|
|
4142
4341
|
);
|
|
4342
|
+
let degraded = false;
|
|
4343
|
+
const resultDiagnostics = diagnostics.map((diagnostic) => {
|
|
4344
|
+
if (DELIVERABILITY_DIAGNOSTIC_CODES.has(diagnostic.code)) {
|
|
4345
|
+
degraded = true;
|
|
4346
|
+
if (options.strict) {
|
|
4347
|
+
return { ...diagnostic, severity: "error" };
|
|
4348
|
+
}
|
|
4349
|
+
}
|
|
4350
|
+
return diagnostic;
|
|
4351
|
+
});
|
|
4143
4352
|
return {
|
|
4144
4353
|
id: diagram.id,
|
|
4145
4354
|
...diagram.title === void 0 ? {} : { title: diagram.title },
|
|
@@ -4151,7 +4360,8 @@ function solveDiagram(diagram, options = {}) {
|
|
|
4151
4360
|
...coordinatedMatrices.length === 0 ? {} : { matrices: coordinatedMatrices },
|
|
4152
4361
|
...coordinatedTables.length === 0 ? {} : { tables: coordinatedTables },
|
|
4153
4362
|
...coordinatedEvidencePanels.length === 0 ? {} : { evidencePanels: coordinatedEvidencePanels },
|
|
4154
|
-
diagnostics,
|
|
4363
|
+
diagnostics: resultDiagnostics,
|
|
4364
|
+
degraded,
|
|
4155
4365
|
bounds: frame === void 0 ? unionBoxes(boundsBase) : unionBoxes([...boundsBase, frame.box, frame.titleBox]),
|
|
4156
4366
|
...frame === void 0 ? {} : { frame },
|
|
4157
4367
|
...textAnnotations.length === 0 ? {} : { textAnnotations },
|
|
@@ -5537,16 +5747,25 @@ function blockBox(block, defaultSize) {
|
|
|
5537
5747
|
height: block.size?.height ?? defaultSize.height
|
|
5538
5748
|
};
|
|
5539
5749
|
}
|
|
5540
|
-
function placeEvidenceBlocks(blocks, contentBounds) {
|
|
5750
|
+
function placeEvidenceBlocks(obstacleMargin, blocks, contentBounds) {
|
|
5751
|
+
const margin = normalizeInsets(obstacleMargin);
|
|
5752
|
+
const horizontalGap = Math.max(
|
|
5753
|
+
DEFAULT_EVIDENCE_BLOCK_GAP,
|
|
5754
|
+
margin.right + margin.left
|
|
5755
|
+
);
|
|
5756
|
+
const verticalGap = Math.max(
|
|
5757
|
+
DEFAULT_EVIDENCE_BLOCK_GAP,
|
|
5758
|
+
margin.bottom + margin.top
|
|
5759
|
+
);
|
|
5541
5760
|
let nextY = contentBounds.y;
|
|
5542
|
-
const x = contentBounds.x + contentBounds.width +
|
|
5761
|
+
const x = contentBounds.x + contentBounds.width + horizontalGap;
|
|
5543
5762
|
for (const block of blocks) {
|
|
5544
5763
|
if (block.position !== void 0) {
|
|
5545
5764
|
continue;
|
|
5546
5765
|
}
|
|
5547
5766
|
block.box.x = x;
|
|
5548
5767
|
block.box.y = nextY;
|
|
5549
|
-
nextY += block.box.height +
|
|
5768
|
+
nextY += block.box.height + verticalGap;
|
|
5550
5769
|
}
|
|
5551
5770
|
}
|
|
5552
5771
|
function columnXOffsets(table, box) {
|
|
@@ -6402,9 +6621,7 @@ function edgeLabelAnchorCandidates(points, placement, layout2) {
|
|
|
6402
6621
|
{ x: placement.x, y: placement.y + offset }
|
|
6403
6622
|
);
|
|
6404
6623
|
}
|
|
6405
|
-
|
|
6406
|
-
}
|
|
6407
|
-
if (segment.start.x === segment.end.x) {
|
|
6624
|
+
} else if (segment.start.x === segment.end.x) {
|
|
6408
6625
|
const needed = layout2.box.width / 2 + EDGE_LABEL_CLEARANCE;
|
|
6409
6626
|
const maxSteps = Math.max(12, Math.ceil(needed / EDGE_LABEL_CLEARANCE));
|
|
6410
6627
|
for (let step = 1; step <= maxSteps; step += 1) {
|
|
@@ -6414,7 +6631,83 @@ function edgeLabelAnchorCandidates(points, placement, layout2) {
|
|
|
6414
6631
|
{ x: placement.x - offset, y: placement.y }
|
|
6415
6632
|
);
|
|
6416
6633
|
}
|
|
6417
|
-
|
|
6634
|
+
} else {
|
|
6635
|
+
const dx = segment.end.x - segment.start.x;
|
|
6636
|
+
const dy = segment.end.y - segment.start.y;
|
|
6637
|
+
const segLen = Math.hypot(dx, dy);
|
|
6638
|
+
if (segLen > 0) {
|
|
6639
|
+
const nx = -dy / segLen;
|
|
6640
|
+
const ny = dx / segLen;
|
|
6641
|
+
const needed = (Math.abs(nx) * layout2.box.width + Math.abs(ny) * layout2.box.height) / 2 + EDGE_LABEL_CLEARANCE;
|
|
6642
|
+
const maxSteps = Math.max(12, Math.ceil(needed / EDGE_LABEL_CLEARANCE));
|
|
6643
|
+
for (let step = 1; step <= maxSteps; step += 1) {
|
|
6644
|
+
const offset = EDGE_LABEL_CLEARANCE * step;
|
|
6645
|
+
candidates.push(
|
|
6646
|
+
{ x: placement.x + nx * offset, y: placement.y + ny * offset },
|
|
6647
|
+
{ x: placement.x - nx * offset, y: placement.y - ny * offset }
|
|
6648
|
+
);
|
|
6649
|
+
}
|
|
6650
|
+
}
|
|
6651
|
+
}
|
|
6652
|
+
const totalLen = points.reduce((sum, p, idx) => {
|
|
6653
|
+
if (idx === 0) return 0;
|
|
6654
|
+
const prev = points[idx - 1];
|
|
6655
|
+
return sum + Math.hypot((p?.x ?? 0) - (prev?.x ?? 0), (p?.y ?? 0) - (prev?.y ?? 0));
|
|
6656
|
+
}, 0);
|
|
6657
|
+
if (totalLen > 200) {
|
|
6658
|
+
for (const ratio of [0.25, 0.75]) {
|
|
6659
|
+
const qp = labelPlacementAtRatio(points, ratio, totalLen);
|
|
6660
|
+
if (qp !== void 0) {
|
|
6661
|
+
candidates.push(qp);
|
|
6662
|
+
const qTargetDist = totalLen * ratio;
|
|
6663
|
+
let qTravelled = 0;
|
|
6664
|
+
let seg;
|
|
6665
|
+
for (let si = 1; si < points.length; si++) {
|
|
6666
|
+
const sp = points[si - 1];
|
|
6667
|
+
const sc = points[si];
|
|
6668
|
+
if (sp === void 0 || sc === void 0) continue;
|
|
6669
|
+
const sl = Math.hypot(sc.x - sp.x, sc.y - sp.y);
|
|
6670
|
+
if (sl <= 0) continue;
|
|
6671
|
+
if (qTravelled + sl >= qTargetDist) {
|
|
6672
|
+
seg = { start: sp, end: sc, length: sl };
|
|
6673
|
+
break;
|
|
6674
|
+
}
|
|
6675
|
+
qTravelled += sl;
|
|
6676
|
+
}
|
|
6677
|
+
if (seg !== void 0) {
|
|
6678
|
+
const segLen = Math.hypot(
|
|
6679
|
+
seg.end.x - seg.start.x,
|
|
6680
|
+
seg.end.y - seg.start.y
|
|
6681
|
+
);
|
|
6682
|
+
const qpNeeded = seg.start.y === seg.end.y ? layout2.box.height / 2 + EDGE_LABEL_CLEARANCE : seg.start.x === seg.end.x ? layout2.box.width / 2 + EDGE_LABEL_CLEARANCE : (Math.abs(seg.start.y - seg.end.y) * layout2.box.width + Math.abs(seg.end.x - seg.start.x) * layout2.box.height) / (2 * segLen) + EDGE_LABEL_CLEARANCE;
|
|
6683
|
+
const qpMaxSteps = Math.max(
|
|
6684
|
+
12,
|
|
6685
|
+
Math.ceil(qpNeeded / EDGE_LABEL_CLEARANCE)
|
|
6686
|
+
);
|
|
6687
|
+
for (let step = 1; step <= qpMaxSteps; step += 1) {
|
|
6688
|
+
const offset = EDGE_LABEL_CLEARANCE * step;
|
|
6689
|
+
if (seg.start.y === seg.end.y) {
|
|
6690
|
+
candidates.push(
|
|
6691
|
+
{ x: qp.x, y: qp.y - offset },
|
|
6692
|
+
{ x: qp.x, y: qp.y + offset }
|
|
6693
|
+
);
|
|
6694
|
+
} else if (seg.start.x === seg.end.x) {
|
|
6695
|
+
candidates.push(
|
|
6696
|
+
{ x: qp.x - offset, y: qp.y },
|
|
6697
|
+
{ x: qp.x + offset, y: qp.y }
|
|
6698
|
+
);
|
|
6699
|
+
} else {
|
|
6700
|
+
const nx = -(seg.end.y - seg.start.y) / segLen;
|
|
6701
|
+
const ny = (seg.end.x - seg.start.x) / segLen;
|
|
6702
|
+
candidates.push(
|
|
6703
|
+
{ x: qp.x + nx * offset, y: qp.y + ny * offset },
|
|
6704
|
+
{ x: qp.x - nx * offset, y: qp.y - ny * offset }
|
|
6705
|
+
);
|
|
6706
|
+
}
|
|
6707
|
+
}
|
|
6708
|
+
}
|
|
6709
|
+
}
|
|
6710
|
+
}
|
|
6418
6711
|
}
|
|
6419
6712
|
return candidates;
|
|
6420
6713
|
}
|
|
@@ -6471,6 +6764,34 @@ function nonZeroSegments2(points) {
|
|
|
6471
6764
|
}
|
|
6472
6765
|
return segments;
|
|
6473
6766
|
}
|
|
6767
|
+
function labelPlacementAtRatio(points, ratio, totalLength) {
|
|
6768
|
+
if (points.length < 2 || ratio < 0 || ratio > 1) {
|
|
6769
|
+
return void 0;
|
|
6770
|
+
}
|
|
6771
|
+
const targetDist = totalLength * ratio;
|
|
6772
|
+
let travelled = 0;
|
|
6773
|
+
for (let idx = 1; idx < points.length; idx++) {
|
|
6774
|
+
const prev = points[idx - 1];
|
|
6775
|
+
const curr = points[idx];
|
|
6776
|
+
if (prev === void 0 || curr === void 0) {
|
|
6777
|
+
continue;
|
|
6778
|
+
}
|
|
6779
|
+
const segLen = Math.hypot(curr.x - prev.x, curr.y - prev.y);
|
|
6780
|
+
if (segLen <= 0) {
|
|
6781
|
+
continue;
|
|
6782
|
+
}
|
|
6783
|
+
if (travelled + segLen >= targetDist) {
|
|
6784
|
+
const t = (targetDist - travelled) / segLen;
|
|
6785
|
+
const offset = labelOffset2({ start: prev, end: curr, length: segLen });
|
|
6786
|
+
return {
|
|
6787
|
+
x: prev.x + (curr.x - prev.x) * t + offset.x,
|
|
6788
|
+
y: prev.y + (curr.y - prev.y) * t + offset.y
|
|
6789
|
+
};
|
|
6790
|
+
}
|
|
6791
|
+
travelled += segLen;
|
|
6792
|
+
}
|
|
6793
|
+
return void 0;
|
|
6794
|
+
}
|
|
6474
6795
|
function labelOffset2(segment) {
|
|
6475
6796
|
const offset = 10;
|
|
6476
6797
|
const dx = segment.end.x - segment.start.x;
|
|
@@ -6584,7 +6905,7 @@ function isValidEdgeId(value) {
|
|
|
6584
6905
|
return value.length > 0 && EDGE_ID_PATTERN.test(value);
|
|
6585
6906
|
}
|
|
6586
6907
|
var directionSchema = zod.z.enum(["TB", "LR", "BT", "RL"]);
|
|
6587
|
-
var routeKindSchema = zod.z.enum(["orthogonal", "straight"]);
|
|
6908
|
+
var routeKindSchema = zod.z.enum(["orthogonal", "straight", "obstacle-avoiding"]);
|
|
6588
6909
|
var outputFormatSchema = zod.z.enum(["svg", "excalidraw"]);
|
|
6589
6910
|
var edgeStrokeStyleSchema = zod.z.enum(["solid", "dashed"]);
|
|
6590
6911
|
var edgeArrowheadSchema = zod.z.enum(["triangle", "hollowTriangle"]);
|
|
@@ -7183,7 +7504,7 @@ function renderDiagramDsl(source, options = {}) {
|
|
|
7183
7504
|
return { diagnostics };
|
|
7184
7505
|
}
|
|
7185
7506
|
const solved = solveDiagram(normalized.diagram, {
|
|
7186
|
-
routeKind: normalized.diagram.metadata?.routeKind === "straight" ? "straight" : "orthogonal",
|
|
7507
|
+
routeKind: normalized.diagram.metadata?.routeKind === "straight" ? "straight" : normalized.diagram.metadata?.routeKind === "obstacle-avoiding" ? "obstacle-avoiding" : "orthogonal",
|
|
7187
7508
|
...solvePortShiftingOption(normalized.diagram.metadata?.portShifting),
|
|
7188
7509
|
...options.textMeasurer === void 0 ? {} : { textMeasurer: options.textMeasurer }
|
|
7189
7510
|
});
|