@tscircuit/rectdiff 0.0.28 → 0.0.29

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.
Files changed (47) hide show
  1. package/.github/workflows/bun-pver-release.yml +24 -45
  2. package/dist/index.d.ts +0 -46
  3. package/dist/index.js +220 -775
  4. package/lib/RectDiffPipeline.ts +0 -46
  5. package/lib/types/srj-types.ts +0 -1
  6. package/package.json +1 -2
  7. package/pages/repro/merge-single-layer-node.page.tsx +17 -0
  8. package/tests/__snapshots__/board-outline.snap.svg +2 -2
  9. package/tests/solver/__snapshots__/rectDiffGridSolverPipeline.snap.svg +1 -1
  10. package/tests/solver/both-points-equivalent/__snapshots__/both-points-equivalent.snap.svg +1 -1
  11. package/tests/solver/bugreport01-be84eb/__snapshots__/bugreport01-be84eb.snap.svg +1 -1
  12. package/tests/solver/bugreport02-bc4361/__snapshots__/bugreport02-bc4361.snap.svg +1 -1
  13. package/tests/solver/bugreport03-fe4a17/__snapshots__/bugreport03-fe4a17.snap.svg +1 -1
  14. package/tests/solver/bugreport07-d3f3be/__snapshots__/bugreport07-d3f3be.snap.svg +1 -1
  15. package/tests/solver/bugreport08-e3ec95/__snapshots__/bugreport08-e3ec95.snap.svg +1 -1
  16. package/tests/solver/bugreport09-618e09/__snapshots__/bugreport09-618e09.snap.svg +1 -1
  17. package/tests/solver/bugreport10-71239a/__snapshots__/bugreport10-71239a.snap.svg +1 -1
  18. package/tests/solver/bugreport11-b2de3c/__snapshots__/bugreport11-b2de3c.snap.svg +1 -1
  19. package/tests/solver/bugreport12-35ce1c/__snapshots__/bugreport12-35ce1c.snap.svg +1 -1
  20. package/tests/solver/bugreport13-b9a758/__snapshots__/bugreport13-b9a758.snap.svg +1 -1
  21. package/tests/solver/bugreport16-d95f38/__snapshots__/bugreport16-d95f38.snap.svg +1 -1
  22. package/tests/solver/bugreport19/__snapshots__/bugreport19.snap.svg +1 -1
  23. package/tests/solver/bugreport20-obstacle-clipping/__snapshots__/bugreport20-obstacle-clipping.snap.svg +1 -1
  24. package/tests/solver/bugreport21-board-outline/__snapshots__/bugreport21-board-outline.snap.svg +2 -2
  25. package/tests/solver/bugreport22-2a75ce/__snapshots__/bugreport22-2a75ce.snap.svg +1 -1
  26. package/tests/solver/bugreport23-LGA15x4/__snapshots__/bugreport23-LGA15x4.snap.svg +1 -1
  27. package/tests/solver/bugreport24-05597c/__snapshots__/bugreport24-05597c.snap.svg +1 -1
  28. package/tests/solver/bugreport25-4b1d55/__snapshots__/bugreport25-4b1d55.snap.svg +1 -1
  29. package/tests/solver/bugreport36-bf8303/__snapshots__/bugreport36-bf8303.snap.svg +1 -1
  30. package/tests/solver/interaction/__snapshots__/interaction.snap.svg +1 -1
  31. package/tests/solver/multi-point/__snapshots__/multi-point.snap.svg +1 -1
  32. package/tests/solver/no-better-path/__snapshots__/no-better-path.snap.svg +1 -1
  33. package/tests/solver/repros/merge-single-layer-node/merge-single-layer-node.json +861 -0
  34. package/tests/solver/{bugreport50-multi-support-layer-merge/bugreport50-multi-support-layer-merge.test.ts → repros/merge-single-layer-node/merge-single-layer-node.test.ts} +7 -42
  35. package/tests/solver/transitivity/__snapshots__/transitivity.snap.svg +2 -2
  36. package/tsconfig.json +5 -1
  37. package/vite.config.ts +4 -0
  38. package/lib/solvers/AdjacentLayerContainmentMergeSolver/AdjacentLayerContainmentMergeSolver.ts +0 -456
  39. package/lib/solvers/OuterLayerContainmentMergeSolver/OuterLayerContainmentMergeSolver.ts +0 -314
  40. package/pages/bugreports/bugreport50-multi-support-layer-merge.page.tsx +0 -19
  41. package/pages/pour.page.tsx +0 -18
  42. package/test-assets/bugreport49-634662.json +0 -412
  43. package/tests/outer-layer-containment-merge-solver.test.ts +0 -73
  44. package/tests/solver/bugreport49-634662/__snapshots__/bugreport49-634662.snap.svg +0 -44
  45. package/tests/solver/bugreport49-634662/bugreport49-634662.test.ts +0 -130
  46. package/tests/solver/bugreport50-multi-support-layer-merge/__snapshots__/bugreport50-multi-support-layer-merge.snap.svg +0 -44
  47. package/tests/solver/bugreport50-multi-support-layer-merge/bugreport50-multi-support-layer-merge.json +0 -972
@@ -1,5 +1,5 @@
1
1
  import { expect, test } from "bun:test"
2
- import srj_json from "./bugreport50-multi-support-layer-merge.json"
2
+ import inputProblems from "./merge-single-layer-node.json"
3
3
  import {
4
4
  getBounds,
5
5
  getSvgFromGraphicsObject,
@@ -12,46 +12,10 @@ import { RectDiffPipeline } from "lib/RectDiffPipeline"
12
12
  import { makeCapacityMeshNodeWithLayerInfo } from "tests/fixtures/makeCapacityMeshNodeWithLayerInfo"
13
13
  import { makeSimpleRouteOutlineGraphics } from "tests/fixtures/makeSimpleRouteOutlineGraphics"
14
14
 
15
- const wrapped = Array.isArray(srj_json) ? srj_json[0] : srj_json
16
- const srj = wrapped.simple_route_json ?? wrapped.simpleRouteJson ?? wrapped
17
-
18
- const getFreeNodeCounts = (
19
- meshNodes: ReturnType<RectDiffPipeline["getOutput"]>["meshNodes"],
20
- ) => {
21
- const counts = new Map<string, number>()
22
-
23
- for (const node of meshNodes) {
24
- if (node._containsObstacle || node._containsTarget) continue
25
-
26
- const key = node.availableZ.join(",")
27
- counts.set(key, (counts.get(key) ?? 0) + 1)
28
- }
29
-
30
- return counts
31
- }
32
-
33
- test("bugreport50-multi-support-layer-merge promotes adjacent-layer nodes supported by multiple peers", () => {
34
- const solver = new RectDiffPipeline({
35
- simpleRouteJson: srj,
36
- })
37
-
38
- solver.solve()
39
-
40
- const counts = getFreeNodeCounts(solver.getOutput().meshNodes)
41
- const z0 = counts.get("0") ?? 0
42
- const z01 = counts.get("0,1") ?? 0
43
-
44
- expect(z01).toBeGreaterThan(40)
45
- expect(z01).toBeGreaterThan(z0)
46
- expect(z0).toBeLessThan(10)
47
- })
48
-
49
- test("bugreport50-multi-support-layer-merge", async () => {
50
- const solver = new RectDiffPipeline({
51
- simpleRouteJson: srj,
52
- })
53
-
54
- const outline = makeSimpleRouteOutlineGraphics(srj)
15
+ test("node-solver input repro snapshot", async () => {
16
+ const problem = inputProblems[0]!
17
+ const solver = new RectDiffPipeline(problem)
18
+ const outline = makeSimpleRouteOutlineGraphics(problem.simpleRouteJson)
55
19
 
56
20
  solver.solve()
57
21
 
@@ -59,7 +23,7 @@ test("bugreport50-multi-support-layer-merge", async () => {
59
23
  const rectsByCombo = makeCapacityMeshNodeWithLayerInfo(meshNodes)
60
24
  const allGraphicsObjects: GraphicsObject[] = []
61
25
 
62
- for (const z of Array.from({ length: srj.layerCount }, (_, index) => index)) {
26
+ for (let z = 0; z < problem.simpleRouteJson.layerCount; z++) {
63
27
  const layerRects: Rect[] = []
64
28
 
65
29
  for (const [key, rects] of rectsByCombo) {
@@ -121,5 +85,6 @@ test("bugreport50-multi-support-layer-merge", async () => {
121
85
  svgWidth,
122
86
  svgHeight,
123
87
  })
88
+
124
89
  await expect(svg).toMatchSvgSnapshot(import.meta.path)
125
90
  })
@@ -1,4 +1,4 @@
1
- <svg width="640" height="1652" viewBox="0 0 640 1652" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="white"/><g><polyline data-points="-5,-5 25,-5 25,25 -5,25 -5,-5" data-type="line" data-label="bounds" points="39.99999999999997,745.6944444444446 600,745.6944444444446 600,185.6944444444445 39.99999999999997,185.6944444444445 39.99999999999997,745.6944444444446" fill="none" stroke="#111827" stroke-width="1.866666666666667"/></g><g><polyline data-points="-5,-48.02083333333333 25,-48.02083333333333 25,-18.02083333333333 -5,-18.02083333333333 -5,-48.02083333333333" data-type="line" data-label="bounds" points="39.99999999999997,1548.75 600,1548.75 600,988.75 39.99999999999997,988.75 39.99999999999997,1548.75" fill="none" stroke="#111827" stroke-width="1.866666666666667"/></g><g><rect data-type="rect" data-label="node" data-x="2.25" data-y="13.25" x="39.99999999999997" y="185.6944444444445" width="270.66666666666663" height="438.6666666666667" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="17.25" data-y="2.25" x="310.66666666666663" y="475.0277777777778" width="289.33333333333337" height="270.66666666666674" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="14.5" data-y="17.75" x="310.66666666666663" y="185.6944444444445" width="186.66666666666669" height="270.6666666666667" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="14.924999999999997" data-y="10" x="376.9333333333333" y="456.3611111111112" width="70" height="18.66666666666663" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="18.5375" data-y="10" x="446.9333333333334" y="456.3611111111112" width="64.86666666666656" height="18.66666666666663" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="2.75" data-y="-2.75" x="58.66666666666664" y="661.6944444444446" width="252" height="84" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="22.75" data-y="18.0375" x="516" y="185.6944444444445" width="84" height="259.93333333333334" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="-2.75" data-y="0.5" x="39.99999999999997" y="624.3611111111112" width="84.00000000000001" height="37.33333333333337" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="5.275" data-y="0.5" x="175.79999999999998" y="624.3611111111112" width="112.00000000000003" height="37.33333333333337" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="11.775" data-y="10" x="329.3333333333333" y="456.3611111111112" width="47.60000000000002" height="18.66666666666663" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="22.6375" data-y="10.2875" x="511.79999999999995" y="445.62777777777785" width="88.20000000000005" height="29.399999999999977" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="8.8875" data-y="0.5" x="287.79999999999995" y="624.3611111111112" width="22.866666666666674" height="37.33333333333337" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="0" data-y="1" x="123.99999999999999" y="624.3611111111112" width="18.66666666666667" height="18.66666666666663" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="1.3875" data-y="0" x="142.66666666666666" y="643.0277777777778" width="33.133333333333326" height="18.666666666666742" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="20" data-y="15.2875" x="497.3333333333333" y="288.3611111111112" width="18.666666666666686" height="157.26666666666665" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="20" data-y="22.75" x="497.3333333333333" y="185.6944444444445" width="18.666666666666686" height="84" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="-4.5" data-y="-2.68125" x="39.99999999999997" y="661.6944444444446" width="18.66666666666667" height="81.43333333333328" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="1.8875" data-y="1" x="161.33333333333331" y="624.3611111111112" width="14.466666666666669" height="18.66666666666663" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="19.8875" data-y="10.7875" x="497.3333333333333" y="445.62777777777785" width="14.46666666666664" height="10.733333333333348" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="0" data-y="0" x="123.99999999999999" y="643.0277777777778" width="18.66666666666667" height="18.666666666666742" fill="red" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="10" data-y="10" x="310.66666666666663" y="456.3611111111112" width="18.666666666666686" height="18.66666666666663" fill="red" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="20" data-y="20" x="497.3333333333333" y="269.6944444444445" width="18.666666666666686" height="18.666666666666686" fill="red" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="1" data-y="1" x="142.66666666666666" y="624.3611111111112" width="18.666666666666657" height="18.66666666666663" fill="red" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="2.25" data-y="-29.77083333333333" x="39.99999999999997" y="988.75" width="270.66666666666663" height="438.66666666666674" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="17.25" data-y="-40.77083333333333" x="310.66666666666663" y="1278.0833333333335" width="289.33333333333337" height="270.6666666666665" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="14.5" data-y="-25.27083333333333" x="310.66666666666663" y="988.75" width="186.66666666666669" height="270.66666666666674" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="14.924999999999997" data-y="-33.02083333333333" x="376.9333333333333" y="1259.4166666666667" width="70" height="18.666666666666742" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="18.5375" data-y="-33.02083333333333" x="446.9333333333334" y="1259.4166666666667" width="64.86666666666656" height="18.666666666666742" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="2.75" data-y="-45.77083333333333" x="58.66666666666664" y="1464.75" width="252" height="84" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="22.75" data-y="-24.983333333333327" x="516" y="988.75" width="84" height="259.9333333333334" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="-2.75" data-y="-42.52083333333333" x="39.99999999999997" y="1427.4166666666667" width="84.00000000000001" height="37.33333333333326" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="5.275" data-y="-42.52083333333333" x="175.79999999999998" y="1427.4166666666667" width="112.00000000000003" height="37.33333333333326" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="11.775" data-y="-33.02083333333333" x="329.3333333333333" y="1259.4166666666667" width="47.60000000000002" height="18.666666666666742" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="22.6375" data-y="-32.73333333333333" x="511.79999999999995" y="1248.6833333333334" width="88.20000000000005" height="29.40000000000009" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="8.8875" data-y="-42.52083333333333" x="287.79999999999995" y="1427.4166666666667" width="22.866666666666674" height="37.33333333333326" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="0" data-y="-42.02083333333333" x="123.99999999999999" y="1427.4166666666667" width="18.66666666666667" height="18.666666666666742" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="1.3875" data-y="-43.02083333333333" x="142.66666666666666" y="1446.0833333333335" width="33.133333333333326" height="18.666666666666515" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="20" data-y="-27.733333333333327" x="497.3333333333333" y="1091.4166666666667" width="18.666666666666686" height="157.26666666666665" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="20" data-y="-20.27083333333333" x="497.3333333333333" y="988.75" width="18.666666666666686" height="84" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="-4.5" data-y="-45.70208333333333" x="39.99999999999997" y="1464.75" width="18.66666666666667" height="81.4333333333334" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="1.8875" data-y="-42.02083333333333" x="161.33333333333331" y="1427.4166666666667" width="14.466666666666669" height="18.666666666666742" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="19.8875" data-y="-32.23333333333333" x="497.3333333333333" y="1248.6833333333334" width="14.46666666666664" height="10.733333333333348" fill="#dbeafe" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="10" data-y="-33.02083333333333" x="310.66666666666663" y="1259.4166666666667" width="18.666666666666686" height="18.666666666666742" fill="#fef3c7" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="0" data-y="-43.02083333333333" x="123.99999999999999" y="1446.0833333333335" width="18.66666666666667" height="18.666666666666515" fill="#fef3c7" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="1" data-y="-42.02083333333333" x="142.66666666666666" y="1427.4166666666667" width="18.666666666666657" height="18.666666666666742" fill="#fef3c7" stroke="black" stroke-width="0.05357142857142857"/></g><g><rect data-type="rect" data-label="node" data-x="20" data-y="-23.02083333333333" x="497.3333333333333" y="1072.75" width="18.666666666666686" height="18.666666666666742" fill="#fef3c7" stroke="black" stroke-width="0.05357142857142857"/></g><text data-type="text" data-label="Layer z=0" data-x="0" data-y="28.916666666666664" x="133.33333333333331" y="112.58333333333348" fill="black" font-size="9.333333333333334" font-family="sans-serif" text-anchor="end" dominant-baseline="text-before-edge">Layer z=0</text><text data-type="text" data-label="Layer z=1" data-x="0" data-y="-14.104166666666664" x="133.33333333333331" y="915.6388888888889" fill="black" font-size="9.333333333333334" font-family="sans-serif" text-anchor="end" dominant-baseline="text-before-edge">Layer z=1</text><g id="crosshair" style="display: none"><line id="crosshair-h" y1="0" y2="1652" stroke="#666" stroke-width="0.5"/><line id="crosshair-v" x1="0" x2="640" stroke="#666" stroke-width="0.5"/><text id="coordinates" font-family="monospace" font-size="12" fill="#666"></text></g><script><![CDATA[
1
+ <svg width="640" height="1652" viewBox="0 0 640 1652" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="white"/><g><polyline data-points="-5,-5 25,-5 25,25 -5,25 -5,-5" data-type="line" data-label="bounds" points="40,745.6944444444446 600,745.6944444444446 600,185.69444444444457 40,185.69444444444457 40,745.6944444444446" fill="none" stroke="#111827" stroke-width="1.8666666666666665"/></g><g><polyline data-points="-5,-48.02083333333333 25,-48.02083333333333 25,-18.02083333333333 -5,-18.02083333333333 -5,-48.02083333333333" data-type="line" data-label="bounds" points="40,1548.75 600,1548.75 600,988.75 40,988.75 40,1548.75" fill="none" stroke="#111827" stroke-width="1.8666666666666665"/></g><g><rect data-type="rect" data-label="node" data-x="2.25" data-y="13.25" x="40" y="185.69444444444457" width="270.66666666666663" height="438.66666666666663" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="17.25" data-y="2.25" x="310.66666666666663" y="475.0277777777779" width="289.33333333333337" height="270.6666666666667" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="14.5" data-y="17.75" x="310.66666666666663" y="185.69444444444457" width="186.66666666666663" height="270.66666666666663" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="14.925" data-y="10" x="376.9333333333333" y="456.3611111111112" width="70" height="18.666666666666686" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="18.5375" data-y="10" x="446.9333333333333" y="456.3611111111112" width="64.86666666666667" height="18.666666666666686" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="2.7500000000000004" data-y="-2.75" x="58.66666666666667" y="661.6944444444446" width="251.99999999999994" height="84" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="22.75" data-y="18.0375" x="516" y="185.69444444444457" width="84" height="259.9333333333333" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="-2.75" data-y="0.5" x="40" y="624.3611111111112" width="83.99999999999999" height="37.33333333333337" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="5.275" data-y="0.5" x="175.79999999999998" y="624.3611111111112" width="111.99999999999997" height="37.33333333333337" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="11.774999999999999" data-y="10" x="329.33333333333326" y="456.3611111111112" width="47.599999999999966" height="18.666666666666686" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="22.637500000000003" data-y="10.2875" x="511.79999999999995" y="445.6277777777779" width="88.20000000000005" height="29.399999999999977" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="8.8875" data-y="0.5" x="287.79999999999995" y="624.3611111111112" width="22.866666666666674" height="37.33333333333337" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="0" data-y="1" x="123.99999999999999" y="624.3611111111112" width="18.66666666666667" height="18.66666666666663" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="1.3875000000000002" data-y="0" x="142.66666666666666" y="643.0277777777778" width="33.133333333333326" height="18.666666666666742" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="20" data-y="15.2875" x="497.33333333333326" y="288.36111111111126" width="18.666666666666742" height="157.26666666666665" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="20" data-y="22.75" x="497.33333333333326" y="185.69444444444457" width="18.666666666666742" height="84" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="-4.5" data-y="-2.68125" x="40" y="661.6944444444446" width="18.66666666666667" height="81.43333333333328" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="1.8875000000000002" data-y="1" x="161.33333333333331" y="624.3611111111112" width="14.466666666666669" height="18.66666666666663" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="19.887500000000003" data-y="10.7875" x="497.33333333333326" y="445.6277777777779" width="14.466666666666754" height="10.733333333333292" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="0" data-y="0" x="123.99999999999999" y="643.0277777777778" width="18.66666666666667" height="18.666666666666742" fill="red" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="10" data-y="10" x="310.66666666666663" y="456.3611111111112" width="18.66666666666663" height="18.666666666666686" fill="red" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="20" data-y="20" x="497.33333333333326" y="269.69444444444457" width="18.666666666666742" height="18.666666666666686" fill="red" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="1" data-y="1" x="142.66666666666666" y="624.3611111111112" width="18.666666666666657" height="18.66666666666663" fill="red" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="2.25" data-y="-29.77083333333333" x="40" y="988.75" width="270.66666666666663" height="438.6666666666665" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="17.25" data-y="-40.77083333333333" x="310.66666666666663" y="1278.0833333333333" width="289.33333333333337" height="270.66666666666674" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="14.5" data-y="-25.27083333333333" x="310.66666666666663" y="988.75" width="186.66666666666663" height="270.6666666666665" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="14.925" data-y="-33.02083333333333" x="376.9333333333333" y="1259.4166666666665" width="70" height="18.666666666666742" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="18.5375" data-y="-33.02083333333333" x="446.9333333333333" y="1259.4166666666665" width="64.86666666666667" height="18.666666666666742" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="2.7500000000000004" data-y="-45.77083333333333" x="58.66666666666667" y="1464.75" width="251.99999999999994" height="84" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="22.75" data-y="-24.983333333333327" x="516" y="988.75" width="84" height="259.93333333333317" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="-2.75" data-y="-42.52083333333333" x="40" y="1427.4166666666665" width="83.99999999999999" height="37.333333333333485" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="5.275" data-y="-42.52083333333333" x="175.79999999999998" y="1427.4166666666665" width="111.99999999999997" height="37.333333333333485" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="11.774999999999999" data-y="-33.02083333333333" x="329.33333333333326" y="1259.4166666666665" width="47.599999999999966" height="18.666666666666742" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="22.637500000000003" data-y="-32.73333333333333" x="511.79999999999995" y="1248.6833333333332" width="88.20000000000005" height="29.40000000000009" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="8.8875" data-y="-42.52083333333333" x="287.79999999999995" y="1427.4166666666665" width="22.866666666666674" height="37.333333333333485" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="0" data-y="-42.02083333333333" x="123.99999999999999" y="1427.4166666666665" width="18.66666666666667" height="18.666666666666742" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="1.3875000000000002" data-y="-43.02083333333333" x="142.66666666666666" y="1446.0833333333333" width="33.133333333333326" height="18.666666666666742" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="20" data-y="-27.733333333333327" x="497.33333333333326" y="1091.4166666666665" width="18.666666666666742" height="157.26666666666665" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="20" data-y="-20.27083333333333" x="497.33333333333326" y="988.75" width="18.666666666666742" height="84" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="-4.5" data-y="-45.70208333333333" x="40" y="1464.75" width="18.66666666666667" height="81.43333333333317" fill="#dbeafe" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="10" data-y="-33.02083333333333" x="310.66666666666663" y="1259.4166666666665" width="18.66666666666663" height="18.666666666666742" fill="#fef3c7" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="0" data-y="-43.02083333333333" x="123.99999999999999" y="1446.0833333333333" width="18.66666666666667" height="18.666666666666742" fill="#fef3c7" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="1.3875000000000002" data-y="-42.02083333333333" x="142.66666666666666" y="1427.4166666666665" width="33.133333333333326" height="18.666666666666742" fill="#fef3c7" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="19.887500000000003" data-y="-32.23333333333333" x="497.33333333333326" y="1248.6833333333332" width="14.466666666666754" height="10.733333333333348" fill="#fef3c7" stroke="black" stroke-width="0.053571428571428575"/></g><g><rect data-type="rect" data-label="node" data-x="20" data-y="-23.02083333333333" x="497.33333333333326" y="1072.75" width="18.666666666666742" height="18.666666666666515" fill="#fef3c7" stroke="black" stroke-width="0.053571428571428575"/></g><text data-type="text" data-label="Layer z=0" data-x="0" data-y="28.916666666666664" x="133.33333333333331" y="112.58333333333348" fill="black" font-size="9.333333333333332" font-family="sans-serif" text-anchor="end" dominant-baseline="text-before-edge">Layer z=0</text><text data-type="text" data-label="Layer z=1" data-x="0" data-y="-14.104166666666664" x="133.33333333333331" y="915.6388888888889" fill="black" font-size="9.333333333333332" font-family="sans-serif" text-anchor="end" dominant-baseline="text-before-edge">Layer z=1</text><g id="crosshair" style="display: none"><line id="crosshair-h" y1="0" y2="1652" stroke="#666" stroke-width="0.5"/><line id="crosshair-v" x1="0" x2="640" stroke="#666" stroke-width="0.5"/><text id="coordinates" font-family="monospace" font-size="12" fill="#666"></text></g><script><![CDATA[
2
2
  document.currentScript.parentElement.addEventListener('mousemove', (e) => {
3
3
  const svg = e.currentTarget;
4
4
  const rect = svg.getBoundingClientRect();
@@ -20,7 +20,7 @@
20
20
  v.setAttribute('y2', '1652');
21
21
 
22
22
  // Calculate real coordinates using inverse transformation
23
- const matrix = {"a":18.666666666666668,"c":0,"e":133.33333333333331,"b":0,"d":-18.666666666666668,"f":652.3611111111112};
23
+ const matrix = {"a":18.666666666666664,"c":0,"e":133.33333333333331,"b":0,"d":-18.666666666666664,"f":652.3611111111112};
24
24
  // Manually invert and apply the affine transform
25
25
  // Since we only use translate and scale, we can directly compute:
26
26
  // x' = (x - tx) / sx
package/tsconfig.json CHANGED
@@ -8,7 +8,11 @@
8
8
  "jsx": "react-jsx",
9
9
  "allowJs": true,
10
10
  "paths": {
11
- "lib/*": ["./lib/*"]
11
+ "lib/*": ["./lib/*"],
12
+ "components/*": ["./components/*"],
13
+ "tests/*": ["./tests/*"],
14
+ "pages/*": ["./pages/*"],
15
+ "utils/*": ["./utils/*"]
12
16
  },
13
17
  "baseUrl": ".",
14
18
 
package/vite.config.ts CHANGED
@@ -8,6 +8,10 @@ export default defineConfig({
8
8
  resolve: {
9
9
  alias: {
10
10
  lib: path.resolve(__dirname, "lib"),
11
+ components: path.resolve(__dirname, "components"),
12
+ tests: path.resolve(__dirname, "tests"),
13
+ pages: path.resolve(__dirname, "pages"),
14
+ utils: path.resolve(__dirname, "utils"),
11
15
  },
12
16
  },
13
17
  })
@@ -1,456 +0,0 @@
1
- import { BaseSolver } from "@tscircuit/solver-utils"
2
- import type { GraphicsObject } from "graphics-debug"
3
- import type { XYRect } from "lib/rectdiff-types"
4
- import type { CapacityMeshNode } from "lib/types/capacity-mesh-types"
5
- import type { SimpleRouteJson } from "lib/types/srj-types"
6
- import { getColorForZLayer } from "lib/utils/getColorForZLayer"
7
- import { EPS, overlaps, subtractRect2D } from "lib/utils/rectdiff-geometry"
8
-
9
- type AdjacentLayerContainmentMergeSolverInput = {
10
- meshNodes: CapacityMeshNode[]
11
- simpleRouteJson: SimpleRouteJson
12
- minFragmentArea?: number
13
- }
14
-
15
- const DEFAULT_MIN_FRAGMENT_AREA = 0.2 ** 2
16
-
17
- const nodeToRect = (node: CapacityMeshNode): XYRect => ({
18
- x: node.center.x - node.width / 2,
19
- y: node.center.y - node.height / 2,
20
- width: node.width,
21
- height: node.height,
22
- })
23
-
24
- const rectArea = (rect: XYRect) => rect.width * rect.height
25
-
26
- const cloneNode = (node: CapacityMeshNode): CapacityMeshNode => ({
27
- ...node,
28
- center: { ...node.center },
29
- availableZ: [...node.availableZ],
30
- })
31
-
32
- const cloneNodeWithRect = (
33
- node: CapacityMeshNode,
34
- rect: XYRect,
35
- capacityMeshNodeId: string,
36
- ): CapacityMeshNode => ({
37
- ...node,
38
- capacityMeshNodeId,
39
- center: {
40
- x: rect.x + rect.width / 2,
41
- y: rect.y + rect.height / 2,
42
- },
43
- width: rect.width,
44
- height: rect.height,
45
- availableZ: [...node.availableZ],
46
- layer: `z${node.availableZ.join(",")}`,
47
- })
48
-
49
- const clonePromotedNodeWithRect = (
50
- node: CapacityMeshNode,
51
- rect: XYRect,
52
- capacityMeshNodeId: string,
53
- availableZ: number[],
54
- ): CapacityMeshNode => ({
55
- ...node,
56
- capacityMeshNodeId,
57
- center: {
58
- x: rect.x + rect.width / 2,
59
- y: rect.y + rect.height / 2,
60
- },
61
- width: rect.width,
62
- height: rect.height,
63
- availableZ: [...availableZ],
64
- layer: `z${availableZ.join(",")}`,
65
- })
66
-
67
- const isFreeNode = (node: CapacityMeshNode) =>
68
- !node._containsObstacle && !node._containsTarget
69
-
70
- const isSingletonNodeOnLayer = (node: CapacityMeshNode, z: number) =>
71
- node.availableZ.length === 1 && node.availableZ[0] === z
72
-
73
- const sameRect = (a: XYRect, b: XYRect) =>
74
- Math.abs(a.x - b.x) <= EPS &&
75
- Math.abs(a.y - b.y) <= EPS &&
76
- Math.abs(a.width - b.width) <= EPS &&
77
- Math.abs(a.height - b.height) <= EPS
78
-
79
- const subtractRects = (target: XYRect, cutters: XYRect[]) => {
80
- let remaining: XYRect[] = [target]
81
-
82
- for (const cutter of cutters) {
83
- if (remaining.length === 0) return remaining
84
-
85
- const nextRemaining: XYRect[] = []
86
- for (const piece of remaining) {
87
- nextRemaining.push(...subtractRect2D(piece, cutter))
88
- }
89
- remaining = nextRemaining
90
- }
91
-
92
- return remaining
93
- }
94
-
95
- const isFullyCoveredByRects = (target: XYRect, coveringRects: XYRect[]) => {
96
- return subtractRects(target, coveringRects).length === 0
97
- }
98
-
99
- const sortAndDedupeCuts = (values: number[]) => {
100
- const sorted = [...values].sort((a, b) => a - b)
101
- const out: number[] = []
102
-
103
- for (const value of sorted) {
104
- const last = out[out.length - 1]
105
- if (last == null || Math.abs(last - value) > EPS) {
106
- out.push(value)
107
- }
108
- }
109
-
110
- return out
111
- }
112
-
113
- const partitionRectByRects = (target: XYRect, supportRects: XYRect[]) => {
114
- const xCuts = [target.x, target.x + target.width]
115
- const yCuts = [target.y, target.y + target.height]
116
- const targetMaxX = target.x + target.width
117
- const targetMaxY = target.y + target.height
118
-
119
- for (const rect of supportRects) {
120
- const x0 = Math.max(target.x, rect.x)
121
- const x1 = Math.min(targetMaxX, rect.x + rect.width)
122
- const y0 = Math.max(target.y, rect.y)
123
- const y1 = Math.min(targetMaxY, rect.y + rect.height)
124
-
125
- if (x1 <= x0 + EPS || y1 <= y0 + EPS) continue
126
-
127
- xCuts.push(x0, x1)
128
- yCuts.push(y0, y1)
129
- }
130
-
131
- const xs = sortAndDedupeCuts(xCuts)
132
- const ys = sortAndDedupeCuts(yCuts)
133
- const cells: XYRect[] = []
134
-
135
- for (let xi = 0; xi < xs.length - 1; xi++) {
136
- const x0 = xs[xi]!
137
- const x1 = xs[xi + 1]!
138
-
139
- if (x1 <= x0 + EPS) continue
140
-
141
- for (let yi = 0; yi < ys.length - 1; yi++) {
142
- const y0 = ys[yi]!
143
- const y1 = ys[yi + 1]!
144
-
145
- if (y1 <= y0 + EPS) continue
146
-
147
- cells.push({
148
- x: x0,
149
- y: y0,
150
- width: x1 - x0,
151
- height: y1 - y0,
152
- })
153
- }
154
- }
155
-
156
- return cells
157
- }
158
-
159
- const canMergeHorizontally = (a: XYRect, b: XYRect) =>
160
- Math.abs(a.y - b.y) <= EPS &&
161
- Math.abs(a.height - b.height) <= EPS &&
162
- Math.abs(a.x + a.width - b.x) <= EPS
163
-
164
- const canMergeVertically = (a: XYRect, b: XYRect) =>
165
- Math.abs(a.x - b.x) <= EPS &&
166
- Math.abs(a.width - b.width) <= EPS &&
167
- Math.abs(a.y + a.height - b.y) <= EPS
168
-
169
- const mergeTouchingRects = (rects: XYRect[]) => {
170
- const out = rects.map((rect) => ({ ...rect }))
171
- let changed = true
172
-
173
- while (changed) {
174
- changed = false
175
-
176
- outer: for (let i = 0; i < out.length; i++) {
177
- for (let j = i + 1; j < out.length; j++) {
178
- const a = out[i]!
179
- const b = out[j]!
180
-
181
- if (canMergeHorizontally(a, b) || canMergeHorizontally(b, a)) {
182
- const merged: XYRect = {
183
- x: Math.min(a.x, b.x),
184
- y: a.y,
185
- width: a.width + b.width,
186
- height: a.height,
187
- }
188
- out.splice(j, 1)
189
- out.splice(i, 1, merged)
190
- changed = true
191
- break outer
192
- }
193
-
194
- if (canMergeVertically(a, b) || canMergeVertically(b, a)) {
195
- const merged: XYRect = {
196
- x: a.x,
197
- y: Math.min(a.y, b.y),
198
- width: a.width,
199
- height: a.height + b.height,
200
- }
201
- out.splice(j, 1)
202
- out.splice(i, 1, merged)
203
- changed = true
204
- break outer
205
- }
206
- }
207
- }
208
- }
209
-
210
- return out
211
- }
212
-
213
- const isPromotableRect = (params: {
214
- rect: XYRect
215
- viaMinSize: number
216
- minFragmentArea: number
217
- }) => {
218
- const { rect, viaMinSize, minFragmentArea } = params
219
-
220
- return (
221
- rect.width > EPS &&
222
- rect.height > EPS &&
223
- rectArea(rect) + EPS >= minFragmentArea &&
224
- rect.width + EPS >= viaMinSize &&
225
- rect.height + EPS >= viaMinSize
226
- )
227
- }
228
-
229
- const isResidualRect = (rect: XYRect, minFragmentArea: number) =>
230
- rect.width > EPS &&
231
- rect.height > EPS &&
232
- rectArea(rect) + EPS >= minFragmentArea
233
-
234
- const computePromotablePieces = (params: {
235
- target: XYRect
236
- supportRects: XYRect[]
237
- viaMinSize: number
238
- minFragmentArea: number
239
- }) => {
240
- const { target, supportRects, viaMinSize, minFragmentArea } = params
241
- const overlappingSupports = supportRects.filter((rect) =>
242
- overlaps(rect, target),
243
- )
244
-
245
- if (overlappingSupports.length === 0) return []
246
-
247
- if (
248
- isFullyCoveredByRects(target, overlappingSupports) &&
249
- isPromotableRect({ rect: target, viaMinSize, minFragmentArea })
250
- ) {
251
- return [target]
252
- }
253
-
254
- const partitioned = partitionRectByRects(target, overlappingSupports)
255
- const coveredPieces = partitioned.filter((piece) =>
256
- isFullyCoveredByRects(piece, overlappingSupports),
257
- )
258
-
259
- if (coveredPieces.length === 0) return []
260
-
261
- const mergedCoveredPieces = mergeTouchingRects(coveredPieces)
262
-
263
- return mergedCoveredPieces.filter(
264
- (piece) =>
265
- isFullyCoveredByRects(piece, overlappingSupports) &&
266
- isPromotableRect({ rect: piece, viaMinSize, minFragmentArea }),
267
- )
268
- }
269
-
270
- export class AdjacentLayerContainmentMergeSolver extends BaseSolver {
271
- private outputNodes: CapacityMeshNode[] = []
272
- private promotedNodeIds = new Set<string>()
273
- private residualNodeIds = new Set<string>()
274
-
275
- constructor(private input: AdjacentLayerContainmentMergeSolverInput) {
276
- super()
277
- }
278
-
279
- override _setup() {
280
- this.outputNodes = this.input.meshNodes.map(cloneNode)
281
- this.promotedNodeIds.clear()
282
- this.residualNodeIds.clear()
283
- }
284
-
285
- override _step() {
286
- this.outputNodes = this.processAdjacentLayerContainmentMerges()
287
- this.solved = true
288
- }
289
-
290
- private processAdjacentLayerContainmentMerges(): CapacityMeshNode[] {
291
- const srj = this.input.simpleRouteJson
292
- const layerCount = Math.max(1, srj.layerCount || 1)
293
-
294
- if (layerCount < 2) {
295
- return this.input.meshNodes.map(cloneNode)
296
- }
297
-
298
- const viaMinSize = Math.max(srj.minViaDiameter ?? 0, srj.minTraceWidth || 0)
299
- const minFragmentArea = Math.max(
300
- EPS,
301
- this.input.minFragmentArea ?? DEFAULT_MIN_FRAGMENT_AREA,
302
- )
303
-
304
- let workingNodes = this.input.meshNodes.map(cloneNode)
305
- let nextResidualId = 0
306
- let nextPromotedId = 0
307
-
308
- for (let lowerZ = 0; lowerZ < layerCount - 1; lowerZ++) {
309
- const upperZ = lowerZ + 1
310
- const mutableNodes = workingNodes.filter(
311
- (node) =>
312
- isFreeNode(node) &&
313
- (isSingletonNodeOnLayer(node, lowerZ) ||
314
- isSingletonNodeOnLayer(node, upperZ)),
315
- )
316
-
317
- if (mutableNodes.length === 0) continue
318
-
319
- const immutableNodes = workingNodes.filter(
320
- (node) => !mutableNodes.includes(node),
321
- )
322
- const supportRectsByLayer = new Map<number, XYRect[]>()
323
-
324
- supportRectsByLayer.set(
325
- lowerZ,
326
- mutableNodes
327
- .filter((node) => isSingletonNodeOnLayer(node, lowerZ))
328
- .map(nodeToRect),
329
- )
330
- supportRectsByLayer.set(
331
- upperZ,
332
- mutableNodes
333
- .filter((node) => isSingletonNodeOnLayer(node, upperZ))
334
- .map(nodeToRect),
335
- )
336
-
337
- const promotedRects: XYRect[] = []
338
- const promotedNodes: CapacityMeshNode[] = []
339
- const candidateNodes = mutableNodes
340
- .filter((node) =>
341
- isPromotableRect({
342
- rect: nodeToRect(node),
343
- viaMinSize,
344
- minFragmentArea,
345
- }),
346
- )
347
- .sort((a, b) => rectArea(nodeToRect(b)) - rectArea(nodeToRect(a)))
348
-
349
- for (const candidate of candidateNodes) {
350
- const candidateRect = nodeToRect(candidate)
351
- const candidatePieces = subtractRects(
352
- candidateRect,
353
- promotedRects,
354
- ).filter((piece) => isResidualRect(piece, minFragmentArea))
355
- const candidateZ = candidate.availableZ[0]!
356
- const oppositeZ = candidateZ === lowerZ ? upperZ : lowerZ
357
- const supportRects = supportRectsByLayer.get(oppositeZ) ?? []
358
-
359
- for (const piece of candidatePieces) {
360
- const promotablePieces = computePromotablePieces({
361
- target: piece,
362
- supportRects,
363
- viaMinSize,
364
- minFragmentArea,
365
- })
366
-
367
- for (const promotablePiece of promotablePieces) {
368
- promotedRects.push(promotablePiece)
369
-
370
- const promotedNode = clonePromotedNodeWithRect(
371
- candidate,
372
- promotablePiece,
373
- `${candidate.capacityMeshNodeId}-adjacent-merge-${nextPromotedId++}`,
374
- [lowerZ, upperZ],
375
- )
376
- promotedNodes.push(promotedNode)
377
- this.promotedNodeIds.add(promotedNode.capacityMeshNodeId)
378
- }
379
- }
380
- }
381
-
382
- const residualNodes: CapacityMeshNode[] = []
383
-
384
- for (const node of mutableNodes) {
385
- const nodeRect = nodeToRect(node)
386
- const remainingPieces = subtractRects(nodeRect, promotedRects).filter(
387
- (piece) => isResidualRect(piece, minFragmentArea),
388
- )
389
-
390
- if (
391
- remainingPieces.length === 1 &&
392
- sameRect(remainingPieces[0]!, nodeRect)
393
- ) {
394
- residualNodes.push(node)
395
- continue
396
- }
397
-
398
- for (const piece of remainingPieces) {
399
- const residualNode = cloneNodeWithRect(
400
- node,
401
- piece,
402
- `${node.capacityMeshNodeId}-adjacent-residual-${nextResidualId++}`,
403
- )
404
- residualNodes.push(residualNode)
405
- this.residualNodeIds.add(residualNode.capacityMeshNodeId)
406
- }
407
- }
408
-
409
- workingNodes = [...immutableNodes, ...promotedNodes, ...residualNodes]
410
- }
411
-
412
- return workingNodes
413
- }
414
-
415
- override getOutput(): { outputNodes: CapacityMeshNode[] } {
416
- return { outputNodes: this.outputNodes }
417
- }
418
-
419
- override visualize(): GraphicsObject {
420
- return {
421
- title: "AdjacentLayerContainmentMergeSolver",
422
- coordinateSystem: "cartesian",
423
- rects: this.outputNodes.map((node) => {
424
- const colors = getColorForZLayer(node.availableZ)
425
- const isPromoted = this.promotedNodeIds.has(node.capacityMeshNodeId)
426
- const isResidual = this.residualNodeIds.has(node.capacityMeshNodeId)
427
-
428
- return {
429
- center: node.center,
430
- width: node.width,
431
- height: node.height,
432
- stroke: isPromoted
433
- ? "rgba(245, 158, 11, 0.95)"
434
- : isResidual
435
- ? "rgba(37, 99, 235, 0.95)"
436
- : colors.stroke,
437
- fill: node._containsObstacle
438
- ? "rgba(239, 68, 68, 0.35)"
439
- : isPromoted
440
- ? "rgba(251, 191, 36, 0.28)"
441
- : isResidual
442
- ? "rgba(59, 130, 246, 0.18)"
443
- : colors.fill,
444
- layer: `z${node.availableZ.join(",")}`,
445
- label: [
446
- `node ${node.capacityMeshNodeId}`,
447
- `z:${node.availableZ.join(",")}`,
448
- ].join("\n"),
449
- }
450
- }),
451
- points: [],
452
- lines: [],
453
- texts: [],
454
- }
455
- }
456
- }