@tscircuit/rectdiff 0.0.10 → 0.0.12

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
@@ -1,5 +1,8 @@
1
1
  // lib/RectDiffPipeline.ts
2
- import { BasePipelineSolver as BasePipelineSolver2, definePipelineStep } from "@tscircuit/solver-utils";
2
+ import {
3
+ BasePipelineSolver as BasePipelineSolver3,
4
+ definePipelineStep as definePipelineStep2
5
+ } from "@tscircuit/solver-utils";
3
6
 
4
7
  // lib/solvers/RectDiffSolver.ts
5
8
  import { BaseSolver } from "@tscircuit/solver-utils";
@@ -1274,6 +1277,7 @@ var RectDiffSolver = class extends BaseSolver {
1274
1277
  height: p.rect.height,
1275
1278
  fill: colors.fill,
1276
1279
  stroke: colors.stroke,
1280
+ layer: `z${p.zLayers.join(",")}`,
1277
1281
  label: `free
1278
1282
  z:${p.zLayers.join(",")}`
1279
1283
  });
@@ -1342,40 +1346,737 @@ function createBaseVisualization(srj, title = "RectDiff") {
1342
1346
  };
1343
1347
  }
1344
1348
 
1349
+ // lib/solvers/GapFillSolver/GapFillSolverPipeline.ts
1350
+ import {
1351
+ BasePipelineSolver as BasePipelineSolver2,
1352
+ definePipelineStep
1353
+ } from "@tscircuit/solver-utils";
1354
+
1355
+ // lib/solvers/GapFillSolver/FindSegmentsWithAdjacentEmptySpaceSolver.ts
1356
+ import { BaseSolver as BaseSolver2 } from "@tscircuit/solver-utils";
1357
+ import Flatbush from "flatbush";
1358
+
1359
+ // lib/solvers/GapFillSolver/projectToUncoveredSegments.ts
1360
+ var EPS2 = 1e-4;
1361
+ function projectToUncoveredSegments(primaryEdge, overlappingEdges) {
1362
+ const isHorizontal = Math.abs(primaryEdge.start.y - primaryEdge.end.y) < EPS2;
1363
+ const isVertical = Math.abs(primaryEdge.start.x - primaryEdge.end.x) < EPS2;
1364
+ if (!isHorizontal && !isVertical) return [];
1365
+ const axis = isHorizontal ? "x" : "y";
1366
+ const perp = isHorizontal ? "y" : "x";
1367
+ const lineCoord = primaryEdge.start[perp];
1368
+ const p0 = primaryEdge.start[axis];
1369
+ const p1 = primaryEdge.end[axis];
1370
+ const pMin = Math.min(p0, p1);
1371
+ const pMax = Math.max(p0, p1);
1372
+ const clamp2 = (v) => Math.max(pMin, Math.min(pMax, v));
1373
+ const intervals = [];
1374
+ for (const e of overlappingEdges) {
1375
+ if (e === primaryEdge) continue;
1376
+ const eIsHorizontal = Math.abs(e.start.y - e.end.y) < EPS2;
1377
+ const eIsVertical = Math.abs(e.start.x - e.end.x) < EPS2;
1378
+ if (axis === "x" && !eIsHorizontal) continue;
1379
+ if (axis === "y" && !eIsVertical) continue;
1380
+ if (Math.abs(e.start[perp] - lineCoord) > EPS2) continue;
1381
+ const eMin = Math.min(e.start[axis], e.end[axis]);
1382
+ const eMax = Math.max(e.start[axis], e.end[axis]);
1383
+ const s = clamp2(eMin);
1384
+ const t = clamp2(eMax);
1385
+ if (t - s > EPS2) intervals.push({ s, e: t });
1386
+ }
1387
+ if (intervals.length === 0) {
1388
+ return [
1389
+ {
1390
+ ...primaryEdge,
1391
+ start: { ...primaryEdge.start },
1392
+ end: { ...primaryEdge.end }
1393
+ }
1394
+ ];
1395
+ }
1396
+ intervals.sort((a, b) => a.s - b.s);
1397
+ const merged = [];
1398
+ for (const it of intervals) {
1399
+ const last = merged[merged.length - 1];
1400
+ if (!last || it.s > last.e + EPS2) merged.push({ ...it });
1401
+ else last.e = Math.max(last.e, it.e);
1402
+ }
1403
+ const uncovered = [];
1404
+ let cursor = pMin;
1405
+ for (const m of merged) {
1406
+ if (m.s > cursor + EPS2) uncovered.push({ s: cursor, e: m.s });
1407
+ cursor = Math.max(cursor, m.e);
1408
+ if (cursor >= pMax - EPS2) break;
1409
+ }
1410
+ if (pMax > cursor + EPS2) uncovered.push({ s: cursor, e: pMax });
1411
+ if (uncovered.length === 0) return [];
1412
+ return uncovered.filter((u) => u.e - u.s > EPS2).map((u) => {
1413
+ const start = axis === "x" ? { x: u.s, y: lineCoord } : { x: lineCoord, y: u.s };
1414
+ const end = axis === "x" ? { x: u.e, y: lineCoord } : { x: lineCoord, y: u.e };
1415
+ return {
1416
+ parent: primaryEdge.parent,
1417
+ facingDirection: primaryEdge.facingDirection,
1418
+ start,
1419
+ end,
1420
+ z: primaryEdge.z
1421
+ };
1422
+ });
1423
+ }
1424
+
1425
+ // lib/solvers/GapFillSolver/edge-constants.ts
1426
+ var EDGES = [
1427
+ {
1428
+ facingDirection: "x-",
1429
+ dx: -1,
1430
+ dy: 0,
1431
+ startX: -0.5,
1432
+ startY: 0.5,
1433
+ endX: -0.5,
1434
+ endY: -0.5
1435
+ },
1436
+ {
1437
+ facingDirection: "x+",
1438
+ dx: 1,
1439
+ dy: 0,
1440
+ startX: 0.5,
1441
+ startY: 0.5,
1442
+ endX: 0.5,
1443
+ endY: -0.5
1444
+ },
1445
+ {
1446
+ facingDirection: "y-",
1447
+ dx: 0,
1448
+ dy: -1,
1449
+ startX: -0.5,
1450
+ startY: -0.5,
1451
+ endX: 0.5,
1452
+ endY: -0.5
1453
+ },
1454
+ {
1455
+ facingDirection: "y+",
1456
+ dx: 0,
1457
+ dy: 1,
1458
+ startX: 0.5,
1459
+ startY: 0.5,
1460
+ endX: -0.5,
1461
+ endY: 0.5
1462
+ }
1463
+ ];
1464
+ var EDGE_MAP = {
1465
+ "x-": EDGES.find((e) => e.facingDirection === "x-"),
1466
+ "x+": EDGES.find((e) => e.facingDirection === "x+"),
1467
+ "y-": EDGES.find((e) => e.facingDirection === "y-"),
1468
+ "y+": EDGES.find((e) => e.facingDirection === "y+")
1469
+ };
1470
+
1471
+ // lib/solvers/GapFillSolver/visuallyOffsetLine.ts
1472
+ var OFFSET_DIR_MAP = {
1473
+ "x-": {
1474
+ x: -1,
1475
+ y: 0
1476
+ },
1477
+ "x+": {
1478
+ x: 1,
1479
+ y: 0
1480
+ },
1481
+ "y-": {
1482
+ x: 0,
1483
+ y: -1
1484
+ },
1485
+ "y+": {
1486
+ x: 0,
1487
+ y: 1
1488
+ }
1489
+ };
1490
+ var visuallyOffsetLine = (line, dir, amt) => {
1491
+ const offset = OFFSET_DIR_MAP[dir];
1492
+ return line.map((p) => ({
1493
+ x: p.x + offset.x * amt,
1494
+ y: p.y + offset.y * amt
1495
+ }));
1496
+ };
1497
+
1498
+ // lib/solvers/GapFillSolver/FindSegmentsWithAdjacentEmptySpaceSolver.ts
1499
+ import "@tscircuit/math-utils";
1500
+ var EPS3 = 1e-4;
1501
+ var FindSegmentsWithAdjacentEmptySpaceSolver = class extends BaseSolver2 {
1502
+ constructor(input) {
1503
+ super();
1504
+ this.input = input;
1505
+ for (const node of this.input.meshNodes) {
1506
+ for (const edge of EDGES) {
1507
+ let start = {
1508
+ x: node.center.x + node.width * edge.startX,
1509
+ y: node.center.y + node.height * edge.startY
1510
+ };
1511
+ let end = {
1512
+ x: node.center.x + node.width * edge.endX,
1513
+ y: node.center.y + node.height * edge.endY
1514
+ };
1515
+ if (start.x > end.x) {
1516
+ ;
1517
+ [start, end] = [end, start];
1518
+ }
1519
+ if (Math.abs(start.x - end.x) < EPS3 && start.y > end.y) {
1520
+ ;
1521
+ [start, end] = [end, start];
1522
+ }
1523
+ for (const z of node.availableZ) {
1524
+ this.unprocessedEdges.push({
1525
+ parent: node,
1526
+ start,
1527
+ end,
1528
+ facingDirection: edge.facingDirection,
1529
+ z
1530
+ });
1531
+ }
1532
+ }
1533
+ }
1534
+ this.allEdges = [...this.unprocessedEdges];
1535
+ this.edgeSpatialIndex = new Flatbush(this.allEdges.length);
1536
+ for (const edge of this.allEdges) {
1537
+ this.edgeSpatialIndex.add(
1538
+ edge.start.x,
1539
+ edge.start.y,
1540
+ edge.end.x,
1541
+ edge.end.y
1542
+ );
1543
+ }
1544
+ this.edgeSpatialIndex.finish();
1545
+ }
1546
+ allEdges;
1547
+ unprocessedEdges = [];
1548
+ segmentsWithAdjacentEmptySpace = [];
1549
+ edgeSpatialIndex;
1550
+ lastCandidateEdge = null;
1551
+ lastOverlappingEdges = null;
1552
+ lastUncoveredSegments = null;
1553
+ _step() {
1554
+ if (this.unprocessedEdges.length === 0) {
1555
+ this.solved = true;
1556
+ this.lastCandidateEdge = null;
1557
+ this.lastOverlappingEdges = null;
1558
+ this.lastUncoveredSegments = null;
1559
+ return;
1560
+ }
1561
+ const candidateEdge = this.unprocessedEdges.shift();
1562
+ this.lastCandidateEdge = candidateEdge;
1563
+ const nearbyEdges = this.edgeSpatialIndex.search(
1564
+ candidateEdge.start.x - EPS3,
1565
+ candidateEdge.start.y - EPS3,
1566
+ candidateEdge.end.x + EPS3,
1567
+ candidateEdge.end.y + EPS3
1568
+ );
1569
+ const overlappingEdges = nearbyEdges.map((i) => this.allEdges[i]).filter((e) => e.z === candidateEdge.z);
1570
+ this.lastOverlappingEdges = overlappingEdges;
1571
+ const uncoveredSegments = projectToUncoveredSegments(
1572
+ candidateEdge,
1573
+ overlappingEdges
1574
+ );
1575
+ this.lastUncoveredSegments = uncoveredSegments;
1576
+ this.segmentsWithAdjacentEmptySpace.push(...uncoveredSegments);
1577
+ }
1578
+ getOutput() {
1579
+ return {
1580
+ segmentsWithAdjacentEmptySpace: this.segmentsWithAdjacentEmptySpace
1581
+ };
1582
+ }
1583
+ visualize() {
1584
+ const graphics = {
1585
+ title: "FindSegmentsWithAdjacentEmptySpace",
1586
+ coordinateSystem: "cartesian",
1587
+ rects: [],
1588
+ points: [],
1589
+ lines: [],
1590
+ circles: [],
1591
+ arrows: [],
1592
+ texts: []
1593
+ };
1594
+ for (const node of this.input.meshNodes) {
1595
+ graphics.rects.push({
1596
+ center: node.center,
1597
+ width: node.width,
1598
+ height: node.height,
1599
+ stroke: "rgba(0, 0, 0, 0.1)"
1600
+ });
1601
+ }
1602
+ for (const unprocessedEdge of this.unprocessedEdges) {
1603
+ graphics.lines.push({
1604
+ points: visuallyOffsetLine(
1605
+ [unprocessedEdge.start, unprocessedEdge.end],
1606
+ unprocessedEdge.facingDirection,
1607
+ -0.1
1608
+ ),
1609
+ strokeColor: "rgba(0, 0, 255, 0.5)",
1610
+ strokeDash: "5 5"
1611
+ });
1612
+ }
1613
+ for (const edge of this.segmentsWithAdjacentEmptySpace) {
1614
+ graphics.lines.push({
1615
+ points: [edge.start, edge.end],
1616
+ strokeColor: "rgba(0,255,0, 0.5)"
1617
+ });
1618
+ }
1619
+ if (this.lastCandidateEdge) {
1620
+ graphics.lines.push({
1621
+ points: [this.lastCandidateEdge.start, this.lastCandidateEdge.end],
1622
+ strokeColor: "blue"
1623
+ });
1624
+ }
1625
+ if (this.lastOverlappingEdges) {
1626
+ for (const edge of this.lastOverlappingEdges) {
1627
+ graphics.lines.push({
1628
+ points: visuallyOffsetLine(
1629
+ [edge.start, edge.end],
1630
+ edge.facingDirection,
1631
+ 0.05
1632
+ ),
1633
+ strokeColor: "red",
1634
+ strokeDash: "2 2"
1635
+ });
1636
+ }
1637
+ }
1638
+ if (this.lastUncoveredSegments) {
1639
+ for (const edge of this.lastUncoveredSegments) {
1640
+ graphics.lines.push({
1641
+ points: visuallyOffsetLine(
1642
+ [edge.start, edge.end],
1643
+ edge.facingDirection,
1644
+ -0.05
1645
+ ),
1646
+ strokeColor: "green",
1647
+ strokeDash: "2 2"
1648
+ });
1649
+ }
1650
+ }
1651
+ return graphics;
1652
+ }
1653
+ };
1654
+
1655
+ // lib/solvers/GapFillSolver/ExpandEdgesToEmptySpaceSolver.ts
1656
+ import { BaseSolver as BaseSolver3 } from "@tscircuit/solver-utils";
1657
+ import RBush from "rbush";
1658
+
1659
+ // lib/solvers/GapFillSolver/getBoundsFromCorners.ts
1660
+ var getBoundsFromCorners = (corners) => {
1661
+ return {
1662
+ minX: Math.min(...corners.map((c) => c.x)),
1663
+ minY: Math.min(...corners.map((c) => c.y)),
1664
+ maxX: Math.max(...corners.map((c) => c.x)),
1665
+ maxY: Math.max(...corners.map((c) => c.y))
1666
+ };
1667
+ };
1668
+
1669
+ // lib/solvers/GapFillSolver/ExpandEdgesToEmptySpaceSolver.ts
1670
+ import { segmentToBoxMinDistance } from "@tscircuit/math-utils";
1671
+ var EPS4 = 1e-4;
1672
+ var ExpandEdgesToEmptySpaceSolver = class extends BaseSolver3 {
1673
+ constructor(input) {
1674
+ super();
1675
+ this.input = input;
1676
+ this.unprocessedSegments = [...this.input.segmentsWithAdjacentEmptySpace];
1677
+ this.rectSpatialIndex = new RBush();
1678
+ this.rectSpatialIndex.load(
1679
+ this.input.inputMeshNodes.map((n) => ({
1680
+ ...n,
1681
+ minX: n.center.x - n.width / 2,
1682
+ minY: n.center.y - n.height / 2,
1683
+ maxX: n.center.x + n.width / 2,
1684
+ maxY: n.center.y + n.height / 2
1685
+ }))
1686
+ );
1687
+ }
1688
+ unprocessedSegments = [];
1689
+ expandedSegments = [];
1690
+ lastSegment = null;
1691
+ lastSearchBounds = null;
1692
+ lastCollidingNodes = null;
1693
+ lastSearchCorner1 = null;
1694
+ lastSearchCorner2 = null;
1695
+ lastExpandedSegment = null;
1696
+ rectSpatialIndex;
1697
+ _step() {
1698
+ if (this.unprocessedSegments.length === 0) {
1699
+ this.solved = true;
1700
+ return;
1701
+ }
1702
+ const segment = this.unprocessedSegments.shift();
1703
+ this.lastSegment = segment;
1704
+ const { dx, dy } = EDGE_MAP[segment.facingDirection];
1705
+ const deltaStartEnd = {
1706
+ x: segment.end.x - segment.start.x,
1707
+ y: segment.end.y - segment.start.y
1708
+ };
1709
+ const segLength = Math.sqrt(deltaStartEnd.x ** 2 + deltaStartEnd.y ** 2);
1710
+ const normDeltaStartEnd = {
1711
+ x: deltaStartEnd.x / segLength,
1712
+ y: deltaStartEnd.y / segLength
1713
+ };
1714
+ let collidingNodes = null;
1715
+ let searchDistance = 1;
1716
+ const searchCorner1 = {
1717
+ x: segment.start.x + dx * EPS4 + normDeltaStartEnd.x * EPS4 * 10,
1718
+ y: segment.start.y + dy * EPS4 + normDeltaStartEnd.y * EPS4 * 10
1719
+ };
1720
+ const searchCorner2 = {
1721
+ x: segment.end.x + dx * EPS4 - normDeltaStartEnd.x * EPS4 * 10,
1722
+ y: segment.end.y + dy * EPS4 - normDeltaStartEnd.y * EPS4 * 10
1723
+ };
1724
+ this.lastSearchCorner1 = searchCorner1;
1725
+ this.lastSearchCorner2 = searchCorner2;
1726
+ while ((!collidingNodes || collidingNodes.length === 0) && searchDistance < 1e3) {
1727
+ const searchBounds = getBoundsFromCorners([
1728
+ searchCorner1,
1729
+ searchCorner2,
1730
+ {
1731
+ x: searchCorner1.x + dx * searchDistance,
1732
+ y: searchCorner1.y + dy * searchDistance
1733
+ },
1734
+ {
1735
+ x: searchCorner2.x + dx * searchDistance,
1736
+ y: searchCorner2.y + dy * searchDistance
1737
+ }
1738
+ ]);
1739
+ this.lastSearchBounds = searchBounds;
1740
+ collidingNodes = this.rectSpatialIndex.search(searchBounds).filter((n) => n.availableZ.includes(segment.z)).filter(
1741
+ (n) => n.capacityMeshNodeId !== segment.parent.capacityMeshNodeId
1742
+ );
1743
+ searchDistance *= 4;
1744
+ }
1745
+ if (!collidingNodes || collidingNodes.length === 0) {
1746
+ return;
1747
+ }
1748
+ this.lastCollidingNodes = collidingNodes;
1749
+ let smallestDistance = Infinity;
1750
+ for (const node of collidingNodes) {
1751
+ const distance = segmentToBoxMinDistance(segment.start, segment.end, node);
1752
+ if (distance < smallestDistance) {
1753
+ smallestDistance = distance;
1754
+ }
1755
+ }
1756
+ const expandDistance = smallestDistance;
1757
+ const nodeBounds = getBoundsFromCorners([
1758
+ segment.start,
1759
+ segment.end,
1760
+ {
1761
+ x: segment.start.x + dx * expandDistance,
1762
+ y: segment.start.y + dy * expandDistance
1763
+ },
1764
+ {
1765
+ x: segment.end.x + dx * expandDistance,
1766
+ y: segment.end.y + dy * expandDistance
1767
+ }
1768
+ ]);
1769
+ const nodeCenter = {
1770
+ x: (nodeBounds.minX + nodeBounds.maxX) / 2,
1771
+ y: (nodeBounds.minY + nodeBounds.maxY) / 2
1772
+ };
1773
+ const nodeWidth = nodeBounds.maxX - nodeBounds.minX;
1774
+ const nodeHeight = nodeBounds.maxY - nodeBounds.minY;
1775
+ const expandedSegment = {
1776
+ segment,
1777
+ newNode: {
1778
+ capacityMeshNodeId: `new-${segment.parent.capacityMeshNodeId}-${this.expandedSegments.length}`,
1779
+ center: nodeCenter,
1780
+ width: nodeWidth,
1781
+ height: nodeHeight,
1782
+ availableZ: [segment.z],
1783
+ layer: segment.parent.layer
1784
+ }
1785
+ };
1786
+ this.lastExpandedSegment = expandedSegment;
1787
+ if (nodeWidth < EPS4 || nodeHeight < EPS4) {
1788
+ return;
1789
+ }
1790
+ this.expandedSegments.push(expandedSegment);
1791
+ this.rectSpatialIndex.insert({
1792
+ ...expandedSegment.newNode,
1793
+ ...nodeBounds
1794
+ });
1795
+ }
1796
+ getOutput() {
1797
+ return {
1798
+ expandedSegments: this.expandedSegments
1799
+ };
1800
+ }
1801
+ visualize() {
1802
+ const graphics = {
1803
+ title: "ExpandEdgesToEmptySpace",
1804
+ coordinateSystem: "cartesian",
1805
+ rects: [],
1806
+ points: [],
1807
+ lines: [],
1808
+ circles: [],
1809
+ arrows: [],
1810
+ texts: []
1811
+ };
1812
+ for (const node of this.input.inputMeshNodes) {
1813
+ graphics.rects.push({
1814
+ center: node.center,
1815
+ width: node.width,
1816
+ height: node.height,
1817
+ stroke: "rgba(0, 0, 0, 0.1)",
1818
+ layer: `z${node.availableZ.join(",")}`,
1819
+ label: [
1820
+ `node ${node.capacityMeshNodeId}`,
1821
+ `z:${node.availableZ.join(",")}`
1822
+ ].join("\n")
1823
+ });
1824
+ }
1825
+ for (const { newNode } of this.expandedSegments) {
1826
+ graphics.rects.push({
1827
+ center: newNode.center,
1828
+ width: newNode.width,
1829
+ height: newNode.height,
1830
+ fill: "green",
1831
+ label: `expandedSegment (z=${newNode.availableZ.join(",")})`,
1832
+ layer: `z${newNode.availableZ.join(",")}`
1833
+ });
1834
+ }
1835
+ if (this.lastSegment) {
1836
+ graphics.lines.push({
1837
+ points: [this.lastSegment.start, this.lastSegment.end],
1838
+ strokeColor: "rgba(0, 0, 255, 0.5)"
1839
+ });
1840
+ }
1841
+ if (this.lastSearchBounds) {
1842
+ graphics.rects.push({
1843
+ center: {
1844
+ x: (this.lastSearchBounds.minX + this.lastSearchBounds.maxX) / 2,
1845
+ y: (this.lastSearchBounds.minY + this.lastSearchBounds.maxY) / 2
1846
+ },
1847
+ width: this.lastSearchBounds.maxX - this.lastSearchBounds.minX,
1848
+ height: this.lastSearchBounds.maxY - this.lastSearchBounds.minY,
1849
+ fill: "rgba(0, 0, 255, 0.25)"
1850
+ });
1851
+ }
1852
+ if (this.lastSearchCorner1 && this.lastSearchCorner2) {
1853
+ graphics.points.push({
1854
+ x: this.lastSearchCorner1.x,
1855
+ y: this.lastSearchCorner1.y,
1856
+ color: "rgba(0, 0, 255, 0.5)",
1857
+ label: ["searchCorner1", `z=${this.lastSegment?.z}`].join("\n")
1858
+ });
1859
+ graphics.points.push({
1860
+ x: this.lastSearchCorner2.x,
1861
+ y: this.lastSearchCorner2.y,
1862
+ color: "rgba(0, 0, 255, 0.5)",
1863
+ label: ["searchCorner2", `z=${this.lastSegment?.z}`].join("\n")
1864
+ });
1865
+ }
1866
+ if (this.lastExpandedSegment) {
1867
+ graphics.rects.push({
1868
+ center: this.lastExpandedSegment.newNode.center,
1869
+ width: this.lastExpandedSegment.newNode.width,
1870
+ height: this.lastExpandedSegment.newNode.height,
1871
+ fill: "purple",
1872
+ label: `expandedSegment (z=${this.lastExpandedSegment.segment.z})`
1873
+ });
1874
+ }
1875
+ if (this.lastCollidingNodes) {
1876
+ for (const node of this.lastCollidingNodes) {
1877
+ graphics.rects.push({
1878
+ center: node.center,
1879
+ width: node.width,
1880
+ height: node.height,
1881
+ fill: "rgba(255, 0, 0, 0.5)"
1882
+ });
1883
+ }
1884
+ }
1885
+ return graphics;
1886
+ }
1887
+ };
1888
+
1889
+ // lib/solvers/GapFillSolver/GapFillSolverPipeline.ts
1890
+ var GapFillSolverPipeline = class extends BasePipelineSolver2 {
1891
+ findSegmentsWithAdjacentEmptySpaceSolver;
1892
+ expandEdgesToEmptySpaceSolver;
1893
+ pipelineDef = [
1894
+ definePipelineStep(
1895
+ "findSegmentsWithAdjacentEmptySpaceSolver",
1896
+ FindSegmentsWithAdjacentEmptySpaceSolver,
1897
+ (gapFillPipeline) => [
1898
+ {
1899
+ meshNodes: gapFillPipeline.inputProblem.meshNodes
1900
+ }
1901
+ ],
1902
+ {
1903
+ onSolved: () => {
1904
+ }
1905
+ }
1906
+ ),
1907
+ definePipelineStep(
1908
+ "expandEdgesToEmptySpaceSolver",
1909
+ ExpandEdgesToEmptySpaceSolver,
1910
+ (gapFillPipeline) => [
1911
+ {
1912
+ inputMeshNodes: gapFillPipeline.inputProblem.meshNodes,
1913
+ segmentsWithAdjacentEmptySpace: gapFillPipeline.findSegmentsWithAdjacentEmptySpaceSolver.getOutput().segmentsWithAdjacentEmptySpace
1914
+ }
1915
+ ],
1916
+ {
1917
+ onSolved: () => {
1918
+ }
1919
+ }
1920
+ )
1921
+ ];
1922
+ getOutput() {
1923
+ const expandedSegments = this.expandEdgesToEmptySpaceSolver?.getOutput().expandedSegments ?? [];
1924
+ const expandedNodes = expandedSegments.map((es) => es.newNode);
1925
+ return {
1926
+ outputNodes: [...this.inputProblem.meshNodes, ...expandedNodes]
1927
+ };
1928
+ }
1929
+ initialVisualize() {
1930
+ const graphics = {
1931
+ title: "GapFillSolverPipeline - Initial",
1932
+ coordinateSystem: "cartesian",
1933
+ rects: [],
1934
+ points: [],
1935
+ lines: [],
1936
+ circles: [],
1937
+ arrows: [],
1938
+ texts: []
1939
+ };
1940
+ for (const node of this.inputProblem.meshNodes) {
1941
+ graphics.rects.push({
1942
+ center: node.center,
1943
+ width: node.width,
1944
+ height: node.height,
1945
+ stroke: "rgba(0, 0, 0, 0.3)",
1946
+ fill: "rgba(100, 100, 100, 0.1)",
1947
+ layer: `z${node.availableZ.join(",")}`,
1948
+ label: [
1949
+ `node ${node.capacityMeshNodeId}`,
1950
+ `z:${node.availableZ.join(",")}`
1951
+ ].join("\n")
1952
+ });
1953
+ }
1954
+ return graphics;
1955
+ }
1956
+ finalVisualize() {
1957
+ const graphics = {
1958
+ title: "GapFillSolverPipeline - Final",
1959
+ coordinateSystem: "cartesian",
1960
+ rects: [],
1961
+ points: [],
1962
+ lines: [],
1963
+ circles: [],
1964
+ arrows: [],
1965
+ texts: []
1966
+ };
1967
+ const { outputNodes } = this.getOutput();
1968
+ const expandedSegments = this.expandEdgesToEmptySpaceSolver?.getOutput().expandedSegments ?? [];
1969
+ const expandedNodeIds = new Set(
1970
+ expandedSegments.map((es) => es.newNode.capacityMeshNodeId)
1971
+ );
1972
+ for (const node of outputNodes) {
1973
+ const isExpanded = expandedNodeIds.has(node.capacityMeshNodeId);
1974
+ graphics.rects.push({
1975
+ center: node.center,
1976
+ width: node.width,
1977
+ height: node.height,
1978
+ stroke: isExpanded ? "rgba(0, 128, 0, 0.8)" : "rgba(0, 0, 0, 0.3)",
1979
+ fill: isExpanded ? "rgba(0, 200, 0, 0.3)" : "rgba(100, 100, 100, 0.1)",
1980
+ layer: `z${node.availableZ.join(",")}`,
1981
+ label: [
1982
+ `${isExpanded ? "[expanded] " : ""}node ${node.capacityMeshNodeId}`,
1983
+ `z:${node.availableZ.join(",")}`
1984
+ ].join("\n")
1985
+ });
1986
+ }
1987
+ return graphics;
1988
+ }
1989
+ };
1990
+
1345
1991
  // lib/RectDiffPipeline.ts
1346
- var RectDiffPipeline = class extends BasePipelineSolver2 {
1992
+ var RectDiffPipeline = class extends BasePipelineSolver3 {
1347
1993
  rectDiffSolver;
1994
+ gapFillSolver;
1348
1995
  pipelineDef = [
1349
- definePipelineStep(
1996
+ definePipelineStep2(
1350
1997
  "rectDiffSolver",
1351
1998
  RectDiffSolver,
1352
- (instance) => [
1999
+ (rectDiffPipeline) => [
1353
2000
  {
1354
- simpleRouteJson: instance.inputProblem.simpleRouteJson,
1355
- gridOptions: instance.inputProblem.gridOptions
2001
+ simpleRouteJson: rectDiffPipeline.inputProblem.simpleRouteJson,
2002
+ gridOptions: rectDiffPipeline.inputProblem.gridOptions
1356
2003
  }
1357
2004
  ],
1358
2005
  {
1359
2006
  onSolved: () => {
1360
2007
  }
1361
2008
  }
2009
+ ),
2010
+ definePipelineStep2(
2011
+ "gapFillSolver",
2012
+ GapFillSolverPipeline,
2013
+ (rectDiffPipeline) => [
2014
+ {
2015
+ meshNodes: rectDiffPipeline.rectDiffSolver?.getOutput().meshNodes ?? []
2016
+ }
2017
+ ]
1362
2018
  )
1363
2019
  ];
1364
2020
  getConstructorParams() {
1365
2021
  return [this.inputProblem];
1366
2022
  }
1367
2023
  getOutput() {
1368
- return this.getSolver("rectDiffSolver").getOutput();
2024
+ const gapFillOutput = this.gapFillSolver?.getOutput();
2025
+ if (gapFillOutput) {
2026
+ return { meshNodes: gapFillOutput.outputNodes };
2027
+ }
2028
+ return this.rectDiffSolver.getOutput();
1369
2029
  }
1370
- visualize() {
1371
- const solver = this.getSolver("rectDiffSolver");
1372
- if (solver) {
1373
- return solver.visualize();
2030
+ initialVisualize() {
2031
+ console.log("RectDiffPipeline - initialVisualize");
2032
+ const graphics = createBaseVisualization(
2033
+ this.inputProblem.simpleRouteJson,
2034
+ "RectDiffPipeline - Initial"
2035
+ );
2036
+ const initialNodes = this.rectDiffSolver?.getOutput().meshNodes ?? [];
2037
+ for (const node of initialNodes) {
2038
+ graphics.rects.push({
2039
+ center: node.center,
2040
+ width: node.width,
2041
+ height: node.height,
2042
+ stroke: "rgba(0, 0, 0, 0.3)",
2043
+ fill: "rgba(100, 100, 100, 0.1)",
2044
+ layer: `z${node.availableZ.join(",")}`,
2045
+ label: [
2046
+ `node ${node.capacityMeshNodeId}`,
2047
+ `z:${node.availableZ.join(",")}`
2048
+ ].join("\n")
2049
+ });
1374
2050
  }
1375
- return createBaseVisualization(
2051
+ return graphics;
2052
+ }
2053
+ finalVisualize() {
2054
+ const graphics = createBaseVisualization(
1376
2055
  this.inputProblem.simpleRouteJson,
1377
- "RectDiff Pipeline (not started)"
2056
+ "RectDiffPipeline - Final"
2057
+ );
2058
+ const { meshNodes: outputNodes } = this.getOutput();
2059
+ const initialNodeIds = new Set(
2060
+ (this.rectDiffSolver?.getOutput().meshNodes ?? []).map(
2061
+ (n) => n.capacityMeshNodeId
2062
+ )
1378
2063
  );
2064
+ for (const node of outputNodes) {
2065
+ const isExpanded = !initialNodeIds.has(node.capacityMeshNodeId);
2066
+ graphics.rects.push({
2067
+ center: node.center,
2068
+ width: node.width,
2069
+ height: node.height,
2070
+ stroke: isExpanded ? "rgba(0, 128, 0, 0.8)" : "rgba(0, 0, 0, 0.3)",
2071
+ fill: isExpanded ? "rgba(0, 200, 0, 0.3)" : "rgba(100, 100, 100, 0.1)",
2072
+ layer: `z${node.availableZ.join(",")}`,
2073
+ label: [
2074
+ `${isExpanded ? "[expanded] " : ""}node ${node.capacityMeshNodeId}`,
2075
+ `z:${node.availableZ.join(",")}`
2076
+ ].join("\n")
2077
+ });
2078
+ }
2079
+ return graphics;
1379
2080
  }
1380
2081
  };
1381
2082
  export {