@knowvah/dot-engine 2.2.0 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -265,22 +265,19 @@ function peg$parse(input, options) {
265
265
  function peg$f17(defs, rest) {
266
266
  return defs.concat(rest);
267
267
  }
268
- function peg$f18(defs) {
269
- return defs;
270
- }
271
- function peg$f19() {
268
+ function peg$f18() {
272
269
  return [];
273
270
  }
274
- function peg$f20(a) {
271
+ function peg$f19(a) {
275
272
  return a;
276
273
  }
277
- function peg$f21(pairs) {
274
+ function peg$f20(pairs) {
278
275
  return pairs;
279
276
  }
280
- function peg$f22(k, v) {
277
+ function peg$f21(k, v) {
281
278
  return { key: k, value: v };
282
279
  }
283
- function peg$f23(head, chain, attrs) {
280
+ function peg$f22(head, chain, attrs) {
284
281
  if (chain.length > 0) {
285
282
  const nodes = [head].concat(chain);
286
283
  return { type: "edge", nodes, attrs };
@@ -291,70 +288,70 @@ function peg$parse(input, options) {
291
288
  return { type: "node", id: head, attrs };
292
289
  }
293
290
  }
294
- function peg$f24(s) {
291
+ function peg$f23(s) {
295
292
  return s;
296
293
  }
297
- function peg$f25(n) {
294
+ function peg$f24(n) {
298
295
  return n;
299
296
  }
300
- function peg$f26(id, port, compass) {
297
+ function peg$f25(id, port, compass) {
301
298
  return { id, port, compass };
302
299
  }
303
- function peg$f27(id, port) {
300
+ function peg$f26(id, port) {
304
301
  return { id, port, compass: null };
305
302
  }
306
- function peg$f28(id) {
303
+ function peg$f27(id) {
307
304
  return { id, port: null, compass: null };
308
305
  }
309
- function peg$f29(s, rest) {
306
+ function peg$f28(s, rest) {
310
307
  return [s].concat(rest);
311
308
  }
312
- function peg$f30() {
309
+ function peg$f29() {
313
310
  return [];
314
311
  }
315
- function peg$f31(id, stmts) {
312
+ function peg$f30(id, stmts) {
316
313
  return { type: "subgraph", id, stmts };
317
314
  }
318
- function peg$f32(stmts) {
315
+ function peg$f31(stmts) {
319
316
  return { type: "subgraph", id: null, stmts };
320
317
  }
321
- function peg$f33(stmts) {
318
+ function peg$f32(stmts) {
322
319
  return { type: "subgraph", id: null, stmts };
323
320
  }
324
- function peg$f34(first, s) {
321
+ function peg$f33(first, s) {
325
322
  return s;
326
323
  }
327
- function peg$f35(first, rest) {
324
+ function peg$f34(first, rest) {
328
325
  return rest.length > 0 ? first + rest.join("") : first;
329
326
  }
330
- function peg$f36(chars) {
327
+ function peg$f35(chars) {
331
328
  return chars.join("");
332
329
  }
333
- function peg$f37() {
330
+ function peg$f36() {
334
331
  return '"';
335
332
  }
336
- function peg$f38() {
333
+ function peg$f37() {
337
334
  return "";
338
335
  }
339
- function peg$f39(c) {
336
+ function peg$f38(c) {
340
337
  return "\\" + c;
341
338
  }
342
- function peg$f40(content) {
339
+ function peg$f39(content) {
343
340
  return "" + content;
344
341
  }
345
- function peg$f41(chars) {
342
+ function peg$f40(chars) {
346
343
  return chars.join("");
347
344
  }
348
- function peg$f42(nested2, content) {
345
+ function peg$f41(nested2, content) {
349
346
  return "<" + content + ">";
350
347
  }
351
- function peg$f43(n) {
348
+ function peg$f42(n) {
352
349
  return n;
353
350
  }
354
- function peg$f44(first, rest) {
351
+ function peg$f43(first, rest) {
355
352
  return first + rest.join("");
356
353
  }
357
- function peg$f45(s) {
354
+ function peg$f44(s) {
358
355
  return Array.isArray(s) ? s.flat(Infinity).filter((x) => x !== null && x !== void 0).join("") : String(s);
359
356
  }
360
357
  let peg$currPos = options.peg$currPos | 0;
@@ -730,7 +727,7 @@ function peg$parse(input, options) {
730
727
  s12 = peg$parseAttrType();
731
728
  if (s12 !== peg$FAILED) {
732
729
  s2 = peg$parse_();
733
- s3 = peg$parseAttrList();
730
+ s3 = peg$parseAttrListReq();
734
731
  if (s3 !== peg$FAILED) {
735
732
  peg$savedPos = s0;
736
733
  s0 = peg$f12(s12, s3);
@@ -782,7 +779,7 @@ function peg$parse(input, options) {
782
779
  }
783
780
  return s0;
784
781
  }
785
- function peg$parseAttrList() {
782
+ function peg$parseAttrListReq() {
786
783
  let s0, s12, s2, s3, s4, s5, s6, s7;
787
784
  s0 = peg$currPos;
788
785
  s12 = peg$parse_();
@@ -825,49 +822,17 @@ function peg$parse(input, options) {
825
822
  peg$currPos = s0;
826
823
  s0 = peg$FAILED;
827
824
  }
825
+ return s0;
826
+ }
827
+ function peg$parseAttrList() {
828
+ let s0, s12;
829
+ s0 = peg$parseAttrListReq();
828
830
  if (s0 === peg$FAILED) {
829
831
  s0 = peg$currPos;
830
- s12 = peg$parse_();
831
- if (input.charCodeAt(peg$currPos) === 91) {
832
- s2 = peg$c3;
833
- peg$currPos++;
834
- } else {
835
- s2 = peg$FAILED;
836
- if (peg$silentFails === 0) {
837
- peg$fail(peg$e3);
838
- }
839
- }
840
- if (s2 !== peg$FAILED) {
841
- s3 = peg$parse_();
842
- s4 = peg$parseAttrDefs();
843
- s5 = peg$parse_();
844
- if (input.charCodeAt(peg$currPos) === 93) {
845
- s6 = peg$c4;
846
- peg$currPos++;
847
- } else {
848
- s6 = peg$FAILED;
849
- if (peg$silentFails === 0) {
850
- peg$fail(peg$e4);
851
- }
852
- }
853
- if (s6 !== peg$FAILED) {
854
- peg$savedPos = s0;
855
- s0 = peg$f18(s4);
856
- } else {
857
- peg$currPos = s0;
858
- s0 = peg$FAILED;
859
- }
860
- } else {
861
- peg$currPos = s0;
862
- s0 = peg$FAILED;
863
- }
864
- if (s0 === peg$FAILED) {
865
- s0 = peg$currPos;
866
- s12 = "";
867
- peg$savedPos = s0;
868
- s12 = peg$f19();
869
- s0 = s12;
870
- }
832
+ s12 = "";
833
+ peg$savedPos = s0;
834
+ s12 = peg$f18();
835
+ s0 = s12;
871
836
  }
872
837
  return s0;
873
838
  }
@@ -901,7 +866,7 @@ function peg$parse(input, options) {
901
866
  s5 = null;
902
867
  }
903
868
  peg$savedPos = s2;
904
- s2 = peg$f20(s3);
869
+ s2 = peg$f19(s3);
905
870
  } else {
906
871
  peg$currPos = s2;
907
872
  s2 = peg$FAILED;
@@ -934,14 +899,14 @@ function peg$parse(input, options) {
934
899
  s5 = null;
935
900
  }
936
901
  peg$savedPos = s2;
937
- s2 = peg$f20(s3);
902
+ s2 = peg$f19(s3);
938
903
  } else {
939
904
  peg$currPos = s2;
940
905
  s2 = peg$FAILED;
941
906
  }
942
907
  }
943
908
  peg$savedPos = s0;
944
- s12 = peg$f21(s12);
909
+ s12 = peg$f20(s12);
945
910
  s0 = s12;
946
911
  return s0;
947
912
  }
@@ -965,7 +930,7 @@ function peg$parse(input, options) {
965
930
  s5 = peg$parseAtom();
966
931
  if (s5 !== peg$FAILED) {
967
932
  peg$savedPos = s0;
968
- s0 = peg$f22(s12, s5);
933
+ s0 = peg$f21(s12, s5);
969
934
  } else {
970
935
  peg$currPos = s0;
971
936
  s0 = peg$FAILED;
@@ -992,7 +957,7 @@ function peg$parse(input, options) {
992
957
  s5 = peg$parseAttrList();
993
958
  if (s5 !== peg$FAILED) {
994
959
  peg$savedPos = s0;
995
- s0 = peg$f23(s12, s3, s5);
960
+ s0 = peg$f22(s12, s3, s5);
996
961
  } else {
997
962
  peg$currPos = s0;
998
963
  s0 = peg$FAILED;
@@ -1013,7 +978,7 @@ function peg$parse(input, options) {
1013
978
  s12 = peg$parseSubgraph();
1014
979
  if (s12 !== peg$FAILED) {
1015
980
  peg$savedPos = s0;
1016
- s12 = peg$f24(s12);
981
+ s12 = peg$f23(s12);
1017
982
  }
1018
983
  s0 = s12;
1019
984
  if (s0 === peg$FAILED) {
@@ -1021,7 +986,7 @@ function peg$parse(input, options) {
1021
986
  s12 = peg$parseNode();
1022
987
  if (s12 !== peg$FAILED) {
1023
988
  peg$savedPos = s0;
1024
- s12 = peg$f25(s12);
989
+ s12 = peg$f24(s12);
1025
990
  }
1026
991
  s0 = s12;
1027
992
  }
@@ -1061,7 +1026,7 @@ function peg$parse(input, options) {
1061
1026
  s9 = peg$parseAtom();
1062
1027
  if (s9 !== peg$FAILED) {
1063
1028
  peg$savedPos = s0;
1064
- s0 = peg$f26(s12, s5, s9);
1029
+ s0 = peg$f25(s12, s5, s9);
1065
1030
  } else {
1066
1031
  peg$currPos = s0;
1067
1032
  s0 = peg$FAILED;
@@ -1101,7 +1066,7 @@ function peg$parse(input, options) {
1101
1066
  s5 = peg$parseAtom();
1102
1067
  if (s5 !== peg$FAILED) {
1103
1068
  peg$savedPos = s0;
1104
- s0 = peg$f27(s12, s5);
1069
+ s0 = peg$f26(s12, s5);
1105
1070
  } else {
1106
1071
  peg$currPos = s0;
1107
1072
  s0 = peg$FAILED;
@@ -1119,7 +1084,7 @@ function peg$parse(input, options) {
1119
1084
  s12 = peg$parseAtom();
1120
1085
  if (s12 !== peg$FAILED) {
1121
1086
  peg$savedPos = s0;
1122
- s12 = peg$f28(s12);
1087
+ s12 = peg$f27(s12);
1123
1088
  }
1124
1089
  s0 = s12;
1125
1090
  }
@@ -1138,7 +1103,7 @@ function peg$parse(input, options) {
1138
1103
  s5 = peg$parseEdgeChain();
1139
1104
  if (s5 !== peg$FAILED) {
1140
1105
  peg$savedPos = s0;
1141
- s0 = peg$f29(s3, s5);
1106
+ s0 = peg$f28(s3, s5);
1142
1107
  } else {
1143
1108
  peg$currPos = s0;
1144
1109
  s0 = peg$FAILED;
@@ -1155,7 +1120,7 @@ function peg$parse(input, options) {
1155
1120
  s0 = peg$currPos;
1156
1121
  s12 = "";
1157
1122
  peg$savedPos = s0;
1158
- s12 = peg$f30();
1123
+ s12 = peg$f29();
1159
1124
  s0 = s12;
1160
1125
  }
1161
1126
  return s0;
@@ -1226,7 +1191,7 @@ function peg$parse(input, options) {
1226
1191
  }
1227
1192
  if (s9 !== peg$FAILED) {
1228
1193
  peg$savedPos = s0;
1229
- s0 = peg$f31(s3, s7);
1194
+ s0 = peg$f30(s3, s7);
1230
1195
  } else {
1231
1196
  peg$currPos = s0;
1232
1197
  s0 = peg$FAILED;
@@ -1277,7 +1242,7 @@ function peg$parse(input, options) {
1277
1242
  }
1278
1243
  if (s7 !== peg$FAILED) {
1279
1244
  peg$savedPos = s0;
1280
- s0 = peg$f32(s5);
1245
+ s0 = peg$f31(s5);
1281
1246
  } else {
1282
1247
  peg$currPos = s0;
1283
1248
  s0 = peg$FAILED;
@@ -1321,7 +1286,7 @@ function peg$parse(input, options) {
1321
1286
  }
1322
1287
  if (s5 !== peg$FAILED) {
1323
1288
  peg$savedPos = s0;
1324
- s0 = peg$f33(s3);
1289
+ s0 = peg$f32(s3);
1325
1290
  } else {
1326
1291
  peg$currPos = s0;
1327
1292
  s0 = peg$FAILED;
@@ -1360,7 +1325,7 @@ function peg$parse(input, options) {
1360
1325
  s7 = peg$parseQAtom();
1361
1326
  if (s7 !== peg$FAILED) {
1362
1327
  peg$savedPos = s3;
1363
- s3 = peg$f34(s12, s7);
1328
+ s3 = peg$f33(s12, s7);
1364
1329
  } else {
1365
1330
  peg$currPos = s3;
1366
1331
  s3 = peg$FAILED;
@@ -1387,7 +1352,7 @@ function peg$parse(input, options) {
1387
1352
  s7 = peg$parseQAtom();
1388
1353
  if (s7 !== peg$FAILED) {
1389
1354
  peg$savedPos = s3;
1390
- s3 = peg$f34(s12, s7);
1355
+ s3 = peg$f33(s12, s7);
1391
1356
  } else {
1392
1357
  peg$currPos = s3;
1393
1358
  s3 = peg$FAILED;
@@ -1398,7 +1363,7 @@ function peg$parse(input, options) {
1398
1363
  }
1399
1364
  }
1400
1365
  peg$savedPos = s0;
1401
- s0 = peg$f35(s12, s2);
1366
+ s0 = peg$f34(s12, s2);
1402
1367
  } else {
1403
1368
  peg$currPos = s0;
1404
1369
  s0 = peg$FAILED;
@@ -1446,7 +1411,7 @@ function peg$parse(input, options) {
1446
1411
  }
1447
1412
  if (s3 !== peg$FAILED) {
1448
1413
  peg$savedPos = s0;
1449
- s0 = peg$f36(s2);
1414
+ s0 = peg$f35(s2);
1450
1415
  } else {
1451
1416
  peg$currPos = s0;
1452
1417
  s0 = peg$FAILED;
@@ -1471,7 +1436,7 @@ function peg$parse(input, options) {
1471
1436
  }
1472
1437
  if (s12 !== peg$FAILED) {
1473
1438
  peg$savedPos = s0;
1474
- s12 = peg$f37();
1439
+ s12 = peg$f36();
1475
1440
  }
1476
1441
  s0 = s12;
1477
1442
  if (s0 === peg$FAILED) {
@@ -1487,7 +1452,7 @@ function peg$parse(input, options) {
1487
1452
  }
1488
1453
  if (s12 !== peg$FAILED) {
1489
1454
  peg$savedPos = s0;
1490
- s12 = peg$f38();
1455
+ s12 = peg$f37();
1491
1456
  }
1492
1457
  s0 = s12;
1493
1458
  if (s0 === peg$FAILED) {
@@ -1513,7 +1478,7 @@ function peg$parse(input, options) {
1513
1478
  }
1514
1479
  if (s2 !== peg$FAILED) {
1515
1480
  peg$savedPos = s0;
1516
- s0 = peg$f39(s2);
1481
+ s0 = peg$f38(s2);
1517
1482
  } else {
1518
1483
  peg$currPos = s0;
1519
1484
  s0 = peg$FAILED;
@@ -1562,7 +1527,7 @@ function peg$parse(input, options) {
1562
1527
  }
1563
1528
  if (s3 !== peg$FAILED) {
1564
1529
  peg$savedPos = s0;
1565
- s0 = peg$f40(s2);
1530
+ s0 = peg$f39(s2);
1566
1531
  } else {
1567
1532
  peg$currPos = s0;
1568
1533
  s0 = peg$FAILED;
@@ -1583,7 +1548,7 @@ function peg$parse(input, options) {
1583
1548
  s2 = peg$parseHtmlChar();
1584
1549
  }
1585
1550
  peg$savedPos = s0;
1586
- s12 = peg$f41(s12);
1551
+ s12 = peg$f40(s12);
1587
1552
  s0 = s12;
1588
1553
  return s0;
1589
1554
  }
@@ -1613,7 +1578,7 @@ function peg$parse(input, options) {
1613
1578
  }
1614
1579
  if (s3 !== peg$FAILED) {
1615
1580
  peg$savedPos = s0;
1616
- s0 = peg$f42(s12, s2);
1581
+ s0 = peg$f41(s12, s2);
1617
1582
  } else {
1618
1583
  peg$currPos = s0;
1619
1584
  s0 = peg$FAILED;
@@ -1658,7 +1623,7 @@ function peg$parse(input, options) {
1658
1623
  s2 = peg$parseName();
1659
1624
  if (s2 !== peg$FAILED) {
1660
1625
  peg$savedPos = s0;
1661
- s0 = peg$f43(s2);
1626
+ s0 = peg$f42(s2);
1662
1627
  } else {
1663
1628
  peg$currPos = s0;
1664
1629
  s0 = peg$FAILED;
@@ -1706,7 +1671,7 @@ function peg$parse(input, options) {
1706
1671
  }
1707
1672
  }
1708
1673
  peg$savedPos = s0;
1709
- s0 = peg$f44(s12, s2);
1674
+ s0 = peg$f43(s12, s2);
1710
1675
  } else {
1711
1676
  peg$currPos = s0;
1712
1677
  s0 = peg$FAILED;
@@ -1927,7 +1892,7 @@ function peg$parse(input, options) {
1927
1892
  }
1928
1893
  if (s12 !== peg$FAILED) {
1929
1894
  peg$savedPos = s0;
1930
- s12 = peg$f45(s12);
1895
+ s12 = peg$f44(s12);
1931
1896
  }
1932
1897
  s0 = s12;
1933
1898
  return s0;
@@ -29134,56 +29099,63 @@ function setEndTheta(P, e, merge) {
29134
29099
 
29135
29100
  // src/pathplan/solvers.ts
29136
29101
  var EPS2 = 1e-7;
29137
- var Solver = class _Solver {
29138
- static aeq0(x) {
29139
- return x < EPS2 && x > -EPS2;
29140
- }
29141
- static solve1(c, r) {
29142
- if (_Solver.aeq0(c[1])) return _Solver.aeq0(c[0]) ? 4 : 0;
29143
- r[0] = -c[0] / c[1];
29144
- return 1;
29145
- }
29146
- static solve2(c, r) {
29147
- if (_Solver.aeq0(c[2])) return _Solver.solve1(c, r);
29148
- const b2a = c[1] / (2 * c[2]);
29149
- const disc = b2a * b2a - c[0] / c[2];
29150
- if (disc < 0) return 0;
29151
- if (disc > 0) {
29152
- r[0] = -b2a + Math.sqrt(disc);
29153
- r[1] = -2 * b2a - r[0];
29154
- return 2;
29155
- }
29156
- r[0] = -b2a;
29157
- return 1;
29158
- }
29159
- static solve3neg(disc, q, b3a, r) {
29160
- const rr = 0.5 * Math.sqrt(-disc + q * q);
29102
+ function aeq02(x) {
29103
+ return x < EPS2 && x > -EPS2;
29104
+ }
29105
+ function solve3(coeff, roots) {
29106
+ const a = coeff[3], b = coeff[2], c = coeff[1], d = coeff[0];
29107
+ if (aeq02(a)) return solve2(coeff, roots);
29108
+ const bOver3a = b / (3 * a), cOverA = c / a, dOverA = d / a;
29109
+ let p = bOver3a * bOver3a;
29110
+ const q = dOverA + fma(2 * bOver3a, p, -(bOver3a * cOverA));
29111
+ p = cOverA / 3 - p;
29112
+ const disc = fma(q, q, 4 * p * p * p);
29113
+ let rootn;
29114
+ if (disc < 0) {
29115
+ const r = 0.5 * Math.sqrt(fma(q, q, -disc));
29161
29116
  const theta = Math.atan2(Math.sqrt(-disc), -q);
29162
- const temp = 2 * Math.cbrt(rr);
29163
- r[0] = temp * Math.cos(theta / 3) - b3a;
29164
- r[1] = temp * Math.cos((theta + 2 * Math.PI) / 3) - b3a;
29165
- r[2] = temp * Math.cos((theta - 2 * Math.PI) / 3) - b3a;
29166
- return 3;
29117
+ const temp = 2 * Math.cbrt(r);
29118
+ roots[0] = temp * Math.cos(theta / 3);
29119
+ roots[1] = temp * Math.cos((theta + Math.PI + Math.PI) / 3);
29120
+ roots[2] = temp * Math.cos((theta - Math.PI - Math.PI) / 3);
29121
+ rootn = 3;
29122
+ } else {
29123
+ const alpha = 0.5 * (Math.sqrt(disc) - q);
29124
+ const beta = -q - alpha;
29125
+ roots[0] = Math.cbrt(alpha) + Math.cbrt(beta);
29126
+ if (disc > 0) rootn = 1;
29127
+ else {
29128
+ roots[1] = roots[2] = -0.5 * roots[0];
29129
+ rootn = 3;
29130
+ }
29167
29131
  }
29168
- static solve3pos(disc, q, b3a, r) {
29169
- const al = 0.5 * (Math.sqrt(disc) - q);
29170
- r[0] = Math.cbrt(al) + Math.cbrt(-q - al) - b3a;
29171
- if (disc > 0) return 1;
29172
- r[1] = r[2] = -0.5 * (r[0] + b3a) - b3a;
29173
- return 3;
29132
+ for (let i = 0; i < rootn; i++) roots[i] -= bOver3a;
29133
+ return rootn;
29134
+ }
29135
+ function solve2(coeff, roots) {
29136
+ const a = coeff[2], b = coeff[1], c = coeff[0];
29137
+ if (aeq02(a)) return solve1(coeff, roots);
29138
+ const bOver2a = b / (2 * a);
29139
+ const cOverA = c / a;
29140
+ const disc = fma(bOver2a, bOver2a, -cOverA);
29141
+ if (disc < 0) {
29142
+ return 0;
29143
+ } else if (disc > 0) {
29144
+ roots[0] = -bOver2a + Math.sqrt(disc);
29145
+ roots[1] = fma(-2, bOver2a, -roots[0]);
29146
+ return 2;
29174
29147
  }
29175
- static solve3(c, r) {
29176
- const a = c[3], b = c[2], cv = c[1], d = c[0];
29177
- if (_Solver.aeq0(a)) return _Solver.solve2(c, r);
29178
- const b3a = b / (3 * a), p0 = b3a * b3a;
29179
- const q = 2 * b3a * p0 - b3a * cv / a + d / a;
29180
- const p = cv / (3 * a) - p0;
29181
- const disc = q * q + 4 * p * p * p;
29182
- return disc < 0 ? _Solver.solve3neg(disc, q, b3a, r) : _Solver.solve3pos(disc, q, b3a, r);
29148
+ roots[0] = -bOver2a;
29149
+ return 1;
29150
+ }
29151
+ function solve1(coeff, roots) {
29152
+ const a = coeff[1], b = coeff[0];
29153
+ if (aeq02(a)) {
29154
+ if (aeq02(b)) return 4;
29155
+ return 0;
29183
29156
  }
29184
- };
29185
- function solve3(coeff, roots) {
29186
- return Solver.solve3(coeff, roots);
29157
+ roots[0] = -b / a;
29158
+ return 1;
29187
29159
  }
29188
29160
 
29189
29161
  // src/pathplan/route.ts
@@ -29205,16 +29177,19 @@ var RouteHelper = class _RouteHelper {
29205
29177
  static B3(t) {
29206
29178
  return t * t * t;
29207
29179
  }
29180
+ /** @see lib/pathplan/route.c:B01 */
29208
29181
  static B01(t) {
29209
29182
  const u = 1 - t;
29210
- return u * u * (u + 3 * t);
29183
+ return u * u * fma(3, t, u);
29211
29184
  }
29185
+ /** @see lib/pathplan/route.c:B23 */
29212
29186
  static B23(t) {
29213
29187
  const u = 1 - t;
29214
- return t * t * (3 * u + t);
29188
+ return t * t * fma(3, u, t);
29215
29189
  }
29190
+ /** @see lib/pathplan/route.c:normv */
29216
29191
  static normv(v) {
29217
- const d = v.x * v.x + v.y * v.y;
29192
+ const d = fma(v.x, v.x, v.y * v.y);
29218
29193
  if (d > 1e-6) {
29219
29194
  const s = Math.sqrt(d);
29220
29195
  return { x: v.x / s, y: v.y / s };
@@ -29230,20 +29205,28 @@ var RouteHelper = class _RouteHelper {
29230
29205
  static ptScale(p, c) {
29231
29206
  return { x: p.x * c, y: p.y * c };
29232
29207
  }
29208
+ /** @see lib/pathplan/route.c:dot */
29233
29209
  static ptDot(a, b) {
29234
- return a.x * b.x + a.y * b.y;
29210
+ return fma(a.x, b.x, a.y * b.y);
29235
29211
  }
29212
+ /** @see lib/pathplan/route.c:dist (libm hypot, no contraction) */
29236
29213
  static ptDist(a, b) {
29237
- return Math.hypot(a.x - b.x, a.y - b.y);
29214
+ return libmHypot(a.x - b.x, a.y - b.y);
29238
29215
  }
29239
29216
  static distN(pts) {
29240
29217
  let rv = 0;
29241
29218
  for (let i = 1; i < pts.length; i++) rv += _RouteHelper.ptDist(pts[i], pts[i - 1]);
29242
29219
  return rv;
29243
29220
  }
29221
+ /**
29222
+ * The cubic's coefficients come out of catastrophic cancellation when the
29223
+ * spline is tangent to a barrier (tests/2646.dot), so clang's contraction
29224
+ * here decides solve3's root count; mirror it exactly.
29225
+ * @see lib/pathplan/route.c:points2coeff
29226
+ */
29244
29227
  static points2coeff(v0, v1, v2, v3, c) {
29245
- c[3] = v3 + 3 * v1 - (v0 + 3 * v2);
29246
- c[2] = 3 * v0 + 3 * v2 - 6 * v1;
29228
+ c[3] = fma(3, v1, v3) - fma(3, v2, v0);
29229
+ c[2] = fma(-6, v1, fma(3, v0, 3 * v2));
29247
29230
  c[1] = 3 * (v1 - v0);
29248
29231
  c[0] = v0;
29249
29232
  }
@@ -29283,7 +29266,7 @@ var RouteHelper = class _RouteHelper {
29283
29266
  const tv = xr[i];
29284
29267
  if (tv >= 0 && tv <= 1) {
29285
29268
  _RouteHelper.points2coeff(sps[0].y, sps[1].y, sps[2].y, sps[3].y, sc);
29286
- const sv = (sc[0] + tv * (sc[1] + tv * (sc[2] + tv * sc[3])) - lc.yc0) / lc.yc1;
29269
+ const sv = (fma(tv, fma(tv, fma(tv, sc[3], sc[2]), sc[1]), sc[0]) - lc.yc0) / lc.yc1;
29287
29270
  if (sv >= 0 && sv <= 1) _RouteHelper.addRoot(tv, acc);
29288
29271
  }
29289
29272
  }
@@ -29293,25 +29276,26 @@ var RouteHelper = class _RouteHelper {
29293
29276
  const sc = [0, 0, 0, 0], xr = [0, 0, 0];
29294
29277
  const rat = lc.yc1 / lc.xc1;
29295
29278
  _RouteHelper.points2coeff(
29296
- sps[0].y - rat * sps[0].x,
29297
- sps[1].y - rat * sps[1].x,
29298
- sps[2].y - rat * sps[2].x,
29299
- sps[3].y - rat * sps[3].x,
29279
+ fms(rat, sps[0].x, sps[0].y),
29280
+ fms(rat, sps[1].x, sps[1].y),
29281
+ fms(rat, sps[2].x, sps[2].y),
29282
+ fms(rat, sps[3].x, sps[3].y),
29300
29283
  sc
29301
29284
  );
29302
- sc[0] += rat * lc.xc0 - lc.yc0;
29285
+ sc[0] += fma(rat, lc.xc0, -lc.yc0);
29303
29286
  const xn = solve3(sc, xr);
29304
29287
  if (xn === 4) return 4;
29305
29288
  for (let i = 0; i < xn; i++) {
29306
29289
  const tv = xr[i];
29307
29290
  if (tv >= 0 && tv <= 1) {
29308
29291
  _RouteHelper.points2coeff(sps[0].x, sps[1].x, sps[2].x, sps[3].x, sc);
29309
- const sv = (sc[0] + tv * (sc[1] + tv * (sc[2] + tv * sc[3])) - lc.xc0) / lc.xc1;
29292
+ const sv = (fma(tv, fma(tv, fma(tv, sc[3], sc[2]), sc[1]), sc[0]) - lc.xc0) / lc.xc1;
29310
29293
  if (sv >= 0 && sv <= 1) _RouteHelper.addRoot(tv, acc);
29311
29294
  }
29312
29295
  }
29313
29296
  return acc.n;
29314
29297
  }
29298
+ /** @see lib/pathplan/route.c:splineintersectsline */
29315
29299
  static splineIntersectsLine(sps, lps, roots) {
29316
29300
  const lc = {
29317
29301
  xc0: lps[0].x,
@@ -29362,8 +29346,9 @@ var RouteHelper = class _RouteHelper {
29362
29346
  x0 += _RouteHelper.ptDot(tnas[i].a[0], tmp);
29363
29347
  x1 += _RouteHelper.ptDot(tnas[i].a[1], tmp);
29364
29348
  }
29365
- const det01 = c00 * c11 - c01 * c01;
29366
- const detX1 = x0 * c11 - x1 * c01, det0X = c00 * x1 - c01 * x0;
29349
+ const det01 = fma(c00, c11, -(c01 * c01));
29350
+ const det0X = fma(c00, x1, -(c01 * x0));
29351
+ const detX1 = fma(x0, c11, -(x1 * c01));
29367
29352
  if (Math.abs(det01) >= 1e-6) {
29368
29353
  scale0 = detX1 / det01;
29369
29354
  scale3 = det0X / det01;
@@ -29387,6 +29372,27 @@ var RouteHelper = class _RouteHelper {
29387
29372
  }
29388
29373
  return tnas;
29389
29374
  }
29375
+ /**
29376
+ * The max-deviation split of `reallyroutespline` (route.c:130-143): the
29377
+ * interior polyline point farthest from the fitted bezier.
29378
+ *
29379
+ * Faithful contract. On a geometrically symmetric channel two interior
29380
+ * deviations tie to within an ulp, so the split point (and the whole
29381
+ * spline) is decided by C's exact arithmetic, which this mirrors bit for
29382
+ * bit against the native arm64 oracle:
29383
+ * - `dist` is libm `hypot` (route.c:448) -> `libmHypot` via `ptDist`;
29384
+ * - the test is C's strict `(d = dist(p, inps[i])) > maxd` (route.c:139),
29385
+ * so an exact tie keeps the first index;
29386
+ * - clang's default `-ffp-contract=on` fuses the bezier eval at
29387
+ * route.c:137-138 as `fma(B3,p2, fma(B2,cp2, fma(B0,p1, B1*cp1)))`; the
29388
+ * B0..B3 weights and cp1/cp2 (route.c:130-131) are not fused. Fusing the
29389
+ * other product first is NOT equivalent (flips pt-issue-23-w9 and 32).
29390
+ * C is therefore not translation-equivariant on such ties (the winner
29391
+ * depends on absolute-coordinate rounding), and neither is this port.
29392
+ * This supersedes the former tolerant tie-break (accepted divergence A3).
29393
+ * Contraction map: .agent-notes/pathplan-fma-contraction-map.md.
29394
+ * @see lib/pathplan/route.c:reallyroutespline
29395
+ */
29390
29396
  static findMaxDev(inps, tnas, ends) {
29391
29397
  const { p0, v0, p1, v1 } = ends;
29392
29398
  const cp1 = _RouteHelper.ptAdd(p0, _RouteHelper.ptScale(v0, 1 / 3));
@@ -29394,10 +29400,12 @@ var RouteHelper = class _RouteHelper {
29394
29400
  let maxi = -1, maxd = -1;
29395
29401
  for (let i = 1; i < inps.length - 1; i++) {
29396
29402
  const t = tnas[i].t;
29397
- const px = _RouteHelper.B0(t) * p0.x + _RouteHelper.B1(t) * cp1.x + _RouteHelper.B2(t) * cp2.x + _RouteHelper.B3(t) * p1.x;
29398
- const py = _RouteHelper.B0(t) * p0.y + _RouteHelper.B1(t) * cp1.y + _RouteHelper.B2(t) * cp2.y + _RouteHelper.B3(t) * p1.y;
29403
+ const b0 = _RouteHelper.B0(t), b1 = _RouteHelper.B1(t);
29404
+ const b2 = _RouteHelper.B2(t), b3 = _RouteHelper.B3(t);
29405
+ const px = fma(b3, p1.x, fma(b2, cp2.x, fma(b0, p0.x, b1 * cp1.x)));
29406
+ const py = fma(b3, p1.y, fma(b2, cp2.y, fma(b0, p0.y, b1 * cp1.y)));
29399
29407
  const d = _RouteHelper.ptDist({ x: px, y: py }, inps[i]);
29400
- if (d > maxd * (1 + 1e-10) + 1e-10) {
29408
+ if (d > maxd) {
29401
29409
  maxd = d;
29402
29410
  maxi = i;
29403
29411
  }
@@ -33548,8 +33556,9 @@ function normalizeCopiedFlatSpline(orig, auxe) {
33548
33556
  if (orig.info.spl === void 0) return;
33549
33557
  if (swapEndsP(auxe) !== swapEndsP(orig)) swapEdgeSpline(orig);
33550
33558
  }
33551
- function makeFlatAdjEdges(g, edges, cnt, _et) {
33559
+ function makeFlatAdjEdges(g, edges, cnt, et) {
33552
33560
  const aux = buildFlatAux(g, edges, cnt);
33561
+ aux.auxg.info.flags = aux.auxg.info.flags & ~15 | et & 15;
33553
33562
  dotInitNodeEdge(aux.auxg);
33554
33563
  dotRank(aux.auxg);
33555
33564
  if (dotMincross(aux.auxg) !== 0) return 1;
@@ -33660,88 +33669,6 @@ function assembleFlatPath(P, tend, hend, mid) {
33660
33669
  for (let i = hend.boxn - 1; i >= 0; i--) addBox(P, hend.boxes[i]);
33661
33670
  }
33662
33671
 
33663
- // src/layout/dot/splines-flat-multi.ts
33664
- function portEq2(a, b) {
33665
- if (!a.defined && !b.defined) return true;
33666
- if (!a.defined || !b.defined) return false;
33667
- return a.p.x === b.p.x && a.p.y === b.p.y;
33668
- }
33669
- function flatPortKey(e, lo) {
33670
- return e.tail === lo ? { loP: e.info.tail_port, hiP: e.info.head_port } : { loP: e.info.head_port, hiP: e.info.tail_port };
33671
- }
33672
- function isNonAdjGroupable(x, g) {
33673
- return x.info.spl === void 0 && x.tail.info.rank !== void 0 && x.tail.info.rank === x.head.info.rank && !isFlatAdjacent(g, x);
33674
- }
33675
- function samePortsAs(x, lo, key) {
33676
- const k = flatPortKey(x, lo);
33677
- return portEq2(k.loP, key.loP) && portEq2(k.hiP, key.hiP);
33678
- }
33679
- function collectNonAdjacentFlatGroup(e, g) {
33680
- const u = e.tail, v = e.head;
33681
- const lo = (u.info.order ?? 0) <= (v.info.order ?? 0) ? u : v;
33682
- const key = flatPortKey(e, lo);
33683
- const sharesPair = (x) => x.tail === u && x.head === v || x.tail === v && x.head === u;
33684
- const group = g.edges.filter(
33685
- (x) => sharesPair(x) && isNonAdjGroupable(x, g) && samePortsAs(x, lo, key) && x.info.label === e.info.label
33686
- );
33687
- group.sort((a, b) => Number(b.tail === lo) - Number(a.tail === lo) || a.seq - b.seq);
33688
- return group;
33689
- }
33690
- function copyPathEnd(end) {
33691
- return {
33692
- ...end,
33693
- boxes: end.boxes.map((b) => ({ ll: { ...b.ll }, ur: { ...b.ur } }))
33694
- };
33695
- }
33696
- function routeGroupEdge(e, i, c) {
33697
- c.P.nbox = 0;
33698
- const endStepX = (i + 1) * c.stepx;
33699
- const endStepY = (i + 1) * c.stepy;
33700
- const mid = c.bottom ? bottomBoxes(c.tlast, c.hlast, endStepX, endStepY, c.stepy) : topBoxes(c.tlast, c.hlast, endStepX, endStepY, c.stepy);
33701
- assembleFlatPath(c.P, copyPathEnd(c.tend), copyPathEnd(c.hend), mid);
33702
- const pts = routeSplines(c.P);
33703
- if (pts === null || pts.length === 0) return false;
33704
- if (e.tail !== c.leftNode) pts.reverse();
33705
- clipAndInstall(e, e.head, pts, pts.length, { ...buildDotSinfo(), ignoreSwap: true });
33706
- return true;
33707
- }
33708
- function routeFlatEdgeGroupFaithful(g, edges, cnt) {
33709
- const lead = edges[0];
33710
- if (g.info.rank === void 0 || lead.tail.info.rank === void 0 || lead.head.info.rank !== lead.tail.info.rank) return false;
33711
- const tailIsLeft = (lead.tail.info.order ?? 0) <= (lead.head.info.order ?? 0);
33712
- const leftNode = tailIsLeft ? lead.tail : lead.head;
33713
- const rightNode = tailIsLeft ? lead.head : lead.tail;
33714
- const sample = tailIsLeft ? lead : {
33715
- ...lead,
33716
- tail: leftNode,
33717
- head: rightNode,
33718
- info: { ...lead.info, tail_port: lead.info.head_port, head_port: lead.info.tail_port }
33719
- };
33720
- const { bottom, side } = flatSide(sample);
33721
- const ctx = flatBboxCtx(g);
33722
- const ranksep = graphRanksep(g);
33723
- const P = freshFlatPath();
33724
- const tend = makeFlatEndBox({ ctx, P, e: sample, n: leftNode, side, ranksep, isBegin: true });
33725
- const hend = makeFlatEndBox({ ctx, P, e: sample, n: rightNode, side, ranksep, isBegin: false });
33726
- const stepx = (g.info.nodesep ?? 18) / (cnt + 1);
33727
- const stepy = flatVspace(g, leftNode, !bottom) / (cnt + 1);
33728
- const rc = {
33729
- P,
33730
- tend,
33731
- hend,
33732
- tlast: tend.boxes[tend.boxn - 1],
33733
- hlast: hend.boxes[hend.boxn - 1],
33734
- bottom,
33735
- stepx,
33736
- stepy,
33737
- leftNode
33738
- };
33739
- for (let i = 0; i < cnt; i++) {
33740
- if (!routeGroupEdge(edges[i], i, rc)) return false;
33741
- }
33742
- return true;
33743
- }
33744
-
33745
33672
  // src/layout/dot/splines-flat-labeled.ts
33746
33673
  var LBL_SPACE = 6;
33747
33674
  function findLabelNode(e) {
@@ -33996,6 +33923,93 @@ function makeAdjFlatNoPortEdge(g, e) {
33996
33923
  return true;
33997
33924
  }
33998
33925
 
33926
+ // src/layout/dot/splines-flat-multi.ts
33927
+ function portEq2(a, b) {
33928
+ if (!a.defined && !b.defined) return true;
33929
+ if (!a.defined || !b.defined) return false;
33930
+ return a.p.x === b.p.x && a.p.y === b.p.y;
33931
+ }
33932
+ function flatPortKey(e, lo) {
33933
+ return e.tail === lo ? { loP: e.info.tail_port, hiP: e.info.head_port } : { loP: e.info.head_port, hiP: e.info.tail_port };
33934
+ }
33935
+ function isNonAdjGroupable(x, g) {
33936
+ return x.info.spl === void 0 && x.tail.info.rank !== void 0 && x.tail.info.rank === x.head.info.rank && !isFlatAdjacent(g, x);
33937
+ }
33938
+ function samePortsAs(x, lo, key) {
33939
+ const k = flatPortKey(x, lo);
33940
+ return portEq2(k.loP, key.loP) && portEq2(k.hiP, key.hiP);
33941
+ }
33942
+ function collectNonAdjacentFlatGroup(e, g) {
33943
+ const u = e.tail, v = e.head;
33944
+ const lo = (u.info.order ?? 0) <= (v.info.order ?? 0) ? u : v;
33945
+ const key = flatPortKey(e, lo);
33946
+ const sharesPair = (x) => x.tail === u && x.head === v || x.tail === v && x.head === u;
33947
+ const group = g.edges.filter(
33948
+ (x) => sharesPair(x) && isNonAdjGroupable(x, g) && samePortsAs(x, lo, key) && x.info.label === e.info.label
33949
+ );
33950
+ group.sort((a, b) => Number(b.tail === lo) - Number(a.tail === lo) || a.seq - b.seq);
33951
+ return group;
33952
+ }
33953
+ function copyPathEnd(end) {
33954
+ return {
33955
+ ...end,
33956
+ boxes: end.boxes.map((b) => ({ ll: { ...b.ll }, ur: { ...b.ur } }))
33957
+ };
33958
+ }
33959
+ function routeGroupEdge(e, i, c) {
33960
+ c.P.nbox = 0;
33961
+ const endStepX = (i + 1) * c.stepx;
33962
+ const endStepY = (i + 1) * c.stepy;
33963
+ const mid = c.bottom ? bottomBoxes(c.tlast, c.hlast, endStepX, endStepY, c.stepy) : topBoxes(c.tlast, c.hlast, endStepX, endStepY, c.stepy);
33964
+ assembleFlatPath(c.P, copyPathEnd(c.tend), copyPathEnd(c.hend), mid);
33965
+ const pts = c.et === EDGETYPE_SPLINE ? routeSplines(c.P) : routePolylines(c.P);
33966
+ if (pts === null || pts.length === 0) return false;
33967
+ if (e.tail !== c.leftNode) pts.reverse();
33968
+ clipAndInstall(e, e.head, pts, pts.length, { ...buildDotSinfo(), ignoreSwap: true });
33969
+ return true;
33970
+ }
33971
+ function routeFlatEdgeGroupFaithful(g, edges, cnt, et) {
33972
+ const lead = edges[0];
33973
+ if (g.info.rank === void 0 || lead.tail.info.rank === void 0 || lead.head.info.rank !== lead.tail.info.rank) return false;
33974
+ if (et === EDGETYPE_LINE) {
33975
+ makeSimpleFlat(edges, et);
33976
+ return true;
33977
+ }
33978
+ const tailIsLeft = (lead.tail.info.order ?? 0) <= (lead.head.info.order ?? 0);
33979
+ const leftNode = tailIsLeft ? lead.tail : lead.head;
33980
+ const rightNode = tailIsLeft ? lead.head : lead.tail;
33981
+ const sample = tailIsLeft ? lead : {
33982
+ ...lead,
33983
+ tail: leftNode,
33984
+ head: rightNode,
33985
+ info: { ...lead.info, tail_port: lead.info.head_port, head_port: lead.info.tail_port }
33986
+ };
33987
+ const { bottom, side } = flatSide(sample);
33988
+ const ctx = flatBboxCtx(g);
33989
+ const ranksep = graphRanksep(g);
33990
+ const P = freshFlatPath();
33991
+ const tend = makeFlatEndBox({ ctx, P, e: sample, n: leftNode, side, ranksep, isBegin: true });
33992
+ const hend = makeFlatEndBox({ ctx, P, e: sample, n: rightNode, side, ranksep, isBegin: false });
33993
+ const stepx = (g.info.nodesep ?? 18) / (cnt + 1);
33994
+ const stepy = flatVspace(g, leftNode, !bottom) / (cnt + 1);
33995
+ const rc = {
33996
+ P,
33997
+ tend,
33998
+ hend,
33999
+ tlast: tend.boxes[tend.boxn - 1],
34000
+ hlast: hend.boxes[hend.boxn - 1],
34001
+ bottom,
34002
+ et,
34003
+ stepx,
34004
+ stepy,
34005
+ leftNode
34006
+ };
34007
+ for (let i = 0; i < cnt; i++) {
34008
+ if (!routeGroupEdge(edges[i], i, rc)) return false;
34009
+ }
34010
+ return true;
34011
+ }
34012
+
33999
34013
  // src/layout/dot/edge-route-boxes.ts
34000
34014
  var FUDGE2 = 2;
34001
34015
  function makeTailBox(nb, startPy) {
@@ -34295,7 +34309,10 @@ function isAdjacentPortFlat(e, g) {
34295
34309
  return e.tail.info.rank !== void 0 && e.tail.info.rank === e.head.info.rank && isFlatAdjacent(g, e) && hasDefinedPort(e);
34296
34310
  }
34297
34311
  function isGroupableFlat(x, g) {
34298
- return x.info.spl === void 0 && isAdjacentPortFlat(x, g);
34312
+ return x.info.spl === void 0 && x.tail.info.rank !== void 0 && x.tail.info.rank === x.head.info.rank && isFlatAdjacent(g, x);
34313
+ }
34314
+ function joinsPortedFlatGroup(e, g) {
34315
+ return isAdjFlatCandidate(e) && isGroupableFlat(e, g) && collectAdjacentFlatGroup(e, g).some(hasDefinedPort);
34299
34316
  }
34300
34317
  function collectAdjacentFlatGroup(e, g) {
34301
34318
  const u = e.tail, v = e.head;
@@ -34310,11 +34327,11 @@ function routeFaithfulSidePort(e, g) {
34310
34327
  const sameRank = e.tail.info.rank !== void 0 && e.tail.info.rank === e.head.info.rank;
34311
34328
  if (sameRank && isFlatAdjacent(g, e)) {
34312
34329
  const group = collectAdjacentFlatGroup(e, g);
34313
- return makeFlatAdjEdges(g, group, group.length, EDGETYPE_SPLINE) === 0 && e.info.spl !== void 0;
34330
+ return makeFlatAdjEdges(g, group, group.length, edgeType(g)) === 0 && e.info.spl !== void 0;
34314
34331
  }
34315
34332
  if (sameRank) {
34316
34333
  const group = collectNonAdjacentFlatGroup(e, g);
34317
- return routeFlatEdgeGroupFaithful(g, group, group.length) && e.info.spl !== void 0;
34334
+ return routeFlatEdgeGroupFaithful(g, group, group.length, edgeType(g)) && e.info.spl !== void 0;
34318
34335
  }
34319
34336
  const pts = routeRegularEdgeFaithful(g, e);
34320
34337
  if (pts === null) return false;
@@ -34335,11 +34352,12 @@ function isLostFlatAdjRecordEdge(g, e) {
34335
34352
  function routeFlatEdge(e, g) {
34336
34353
  if (isLostFlatAdjRecordEdge(g, e)) return true;
34337
34354
  if (makeFlatLabeledEdge(g, e)) return true;
34355
+ if (joinsPortedFlatGroup(e, g) && routeFaithfulSidePort(e, g)) return true;
34338
34356
  if (makeAdjFlatNoPortEdge(g, e)) return true;
34339
34357
  if ((hasSidePort(e) || isAdjacentPortFlat(e, g)) && routeFaithfulSidePort(e, g)) return true;
34340
34358
  if (e.tail.info.rank !== void 0 && e.tail.info.rank === e.head.info.rank && e.info.label === void 0 && !isFlatAdjacent(g, e)) {
34341
34359
  const group = collectNonAdjacentFlatGroup(e, g);
34342
- if (group.length > 0 && routeFlatEdgeGroupFaithful(g, group, group.length) && e.info.spl !== void 0) return true;
34360
+ if (group.length > 0 && routeFlatEdgeGroupFaithful(g, group, group.length, edgeType(g)) && e.info.spl !== void 0) return true;
34343
34361
  }
34344
34362
  return false;
34345
34363
  }
@@ -36636,7 +36654,6 @@ function buildEdges(g, nodeArr, orthoNodes) {
36636
36654
  const oes = outIndex.get(n);
36637
36655
  if (oes === void 0) continue;
36638
36656
  for (const e of oes) {
36639
- if (e.tail === e.head) continue;
36640
36657
  if (concentrate) {
36641
36658
  const ti = e.tail.id;
36642
36659
  const hi = e.head.id;
@@ -48189,11 +48206,11 @@ function addClusters(g) {
48189
48206
  g.info.clust = clusters;
48190
48207
  g.info.n_cluster = clusters.length;
48191
48208
  }
48192
- function layoutComponents(g, comps, solve2, pinned) {
48209
+ function layoutComponents(g, comps, solve4, pinned) {
48193
48210
  for (const gc of comps) {
48194
48211
  setEdgeTypeFromAttr(gc, EDGETYPE_LINE);
48195
- solveModel2(gc, solve2.mode, solve2.model);
48196
- maybeRemoveOverlap(gc, solve2.am);
48212
+ solveModel2(gc, solve4.mode, solve4.model);
48213
+ maybeRemoveOverlap(gc, solve4.am);
48197
48214
  splineEdgesShifted(gc);
48198
48215
  }
48199
48216
  const pinfo = {