@tscircuit/rectdiff 0.0.16 → 0.0.17
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/package.json
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import fixture from "../test-assets/gap-fill-h-shape-should-expand-node.json"
|
|
2
|
+
import { GapFillSolverPipeline } from "../lib/solvers/GapFillSolver/GapFillSolverPipeline"
|
|
3
|
+
import type { CapacityMeshNode } from "../lib/types/capacity-mesh-types"
|
|
4
|
+
import { useMemo } from "react"
|
|
5
|
+
import { SolverDebugger3d } from "../components/SolverDebugger3d"
|
|
6
|
+
|
|
7
|
+
export default () => {
|
|
8
|
+
const solver = useMemo(
|
|
9
|
+
() =>
|
|
10
|
+
new GapFillSolverPipeline({
|
|
11
|
+
meshNodes: fixture.meshNodes as CapacityMeshNode[],
|
|
12
|
+
}),
|
|
13
|
+
[],
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<SolverDebugger3d
|
|
18
|
+
solver={solver}
|
|
19
|
+
defaultShowOutput={true}
|
|
20
|
+
defaultShowRoot={true}
|
|
21
|
+
/>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "H-shaped configuration - two vertical nodes with a horizontal connector in the middle",
|
|
3
|
+
"expectedBehavior": "Should detect segments on all exposed edges and expand into empty spaces around the H shape",
|
|
4
|
+
"meshNodes": [
|
|
5
|
+
{
|
|
6
|
+
"capacityMeshNodeId": "node-left-vertical",
|
|
7
|
+
"center": { "x": -3, "y": 0 },
|
|
8
|
+
"width": 1,
|
|
9
|
+
"height": 6,
|
|
10
|
+
"layer": "top",
|
|
11
|
+
"availableZ": [0]
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"capacityMeshNodeId": "node-right-vertical",
|
|
15
|
+
"center": { "x": 3, "y": 0 },
|
|
16
|
+
"width": 1,
|
|
17
|
+
"height": 6,
|
|
18
|
+
"layer": "top",
|
|
19
|
+
"availableZ": [0]
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"capacityMeshNodeId": "node-middle-horizontal",
|
|
23
|
+
"center": { "x": 0, "y": 0 },
|
|
24
|
+
"width": 2,
|
|
25
|
+
"height": 1,
|
|
26
|
+
"layer": "top",
|
|
27
|
+
"availableZ": [0]
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"expectedSegments": [
|
|
31
|
+
{
|
|
32
|
+
"description": "Left vertical - left edge",
|
|
33
|
+
"parentNodeId": "node-left-vertical",
|
|
34
|
+
"facingDirection": "x-"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"description": "Left vertical - top edge (above horizontal)",
|
|
38
|
+
"parentNodeId": "node-left-vertical",
|
|
39
|
+
"facingDirection": "y+"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"description": "Left vertical - bottom edge (below horizontal)",
|
|
43
|
+
"parentNodeId": "node-left-vertical",
|
|
44
|
+
"facingDirection": "y-"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"description": "Right vertical - right edge",
|
|
48
|
+
"parentNodeId": "node-right-vertical",
|
|
49
|
+
"facingDirection": "x+"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"description": "Right vertical - top edge (above horizontal)",
|
|
53
|
+
"parentNodeId": "node-right-vertical",
|
|
54
|
+
"facingDirection": "y+"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"description": "Right vertical - bottom edge (below horizontal)",
|
|
58
|
+
"parentNodeId": "node-right-vertical",
|
|
59
|
+
"facingDirection": "y-"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"description": "Middle horizontal - top edge",
|
|
63
|
+
"parentNodeId": "node-middle-horizontal",
|
|
64
|
+
"facingDirection": "y+"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"description": "Middle horizontal - bottom edge",
|
|
68
|
+
"parentNodeId": "node-middle-horizontal",
|
|
69
|
+
"facingDirection": "y-"
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<svg width="640" height="480" viewBox="0 0 640 480" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="white"/><g><rect data-type="rect" data-label="node" data-x="-3" data-y="0" x="86.66666666666666" y="40" width="66.66666666666666" height="400" fill="#dbeafe" stroke="black" stroke-width="0.015"/></g><g><rect data-type="rect" data-label="node" data-x="3" data-y="0" x="486.6666666666667" y="40" width="66.66666666666669" height="400" fill="#dbeafe" stroke="black" stroke-width="0.015"/></g><g><rect data-type="rect" data-label="node" data-x="0" data-y="0" x="253.33333333333331" y="206.66666666666666" width="133.33333333333337" height="66.66666666666666" fill="#dbeafe" stroke="black" stroke-width="0.015"/></g><g><rect data-type="rect" data-label="node" data-x="-1.75" data-y="0" x="153.33333333333331" y="40" width="100" height="400" fill="#dbeafe" stroke="black" stroke-width="0.015"/></g><g><rect data-type="rect" data-label="node" data-x="1.75" data-y="0" x="386.6666666666667" y="40" width="100" height="400" fill="#dbeafe" stroke="black" stroke-width="0.015"/></g><g id="crosshair" style="display: none"><line id="crosshair-h" y1="0" y2="480" 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
|
+
document.currentScript.parentElement.addEventListener('mousemove', (e) => {
|
|
3
|
+
const svg = e.currentTarget;
|
|
4
|
+
const rect = svg.getBoundingClientRect();
|
|
5
|
+
const x = e.clientX - rect.left;
|
|
6
|
+
const y = e.clientY - rect.top;
|
|
7
|
+
const crosshair = svg.getElementById('crosshair');
|
|
8
|
+
const h = svg.getElementById('crosshair-h');
|
|
9
|
+
const v = svg.getElementById('crosshair-v');
|
|
10
|
+
const coords = svg.getElementById('coordinates');
|
|
11
|
+
|
|
12
|
+
crosshair.style.display = 'block';
|
|
13
|
+
h.setAttribute('x1', '0');
|
|
14
|
+
h.setAttribute('x2', '640');
|
|
15
|
+
h.setAttribute('y1', y);
|
|
16
|
+
h.setAttribute('y2', y);
|
|
17
|
+
v.setAttribute('x1', x);
|
|
18
|
+
v.setAttribute('x2', x);
|
|
19
|
+
v.setAttribute('y1', '0');
|
|
20
|
+
v.setAttribute('y2', '480');
|
|
21
|
+
|
|
22
|
+
// Calculate real coordinates using inverse transformation
|
|
23
|
+
const matrix = {"a":66.66666666666667,"c":0,"e":320,"b":0,"d":-66.66666666666667,"f":240};
|
|
24
|
+
// Manually invert and apply the affine transform
|
|
25
|
+
// Since we only use translate and scale, we can directly compute:
|
|
26
|
+
// x' = (x - tx) / sx
|
|
27
|
+
// y' = (y - ty) / sy
|
|
28
|
+
const sx = matrix.a;
|
|
29
|
+
const sy = matrix.d;
|
|
30
|
+
const tx = matrix.e;
|
|
31
|
+
const ty = matrix.f;
|
|
32
|
+
const realPoint = {
|
|
33
|
+
x: (x - tx) / sx,
|
|
34
|
+
y: (y - ty) / sy // Flip y back since we used negative scale
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
coords.textContent = `(${realPoint.x.toFixed(2)}, ${realPoint.y.toFixed(2)})`;
|
|
38
|
+
coords.setAttribute('x', (x + 5).toString());
|
|
39
|
+
coords.setAttribute('y', (y - 5).toString());
|
|
40
|
+
});
|
|
41
|
+
document.currentScript.parentElement.addEventListener('mouseleave', () => {
|
|
42
|
+
document.currentScript.parentElement.getElementById('crosshair').style.display = 'none';
|
|
43
|
+
});
|
|
44
|
+
]]></script></svg>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import middleGapFixture from "test-assets/gap-fill-h-shape-should-expand-node.json"
|
|
3
|
+
import { getSvgFromGraphicsObject } from "graphics-debug"
|
|
4
|
+
import { GapFillSolverPipeline } from "lib/solvers/GapFillSolver/GapFillSolverPipeline"
|
|
5
|
+
import type { CapacityMeshNode } from "lib/types/capacity-mesh-types"
|
|
6
|
+
import { makeCapacityMeshNodeWithLayerInfo } from "./fixtures/makeCapacityMeshNodeWithLayerInfo"
|
|
7
|
+
|
|
8
|
+
test("should expand capacityMeshNode to fill the gap", async () => {
|
|
9
|
+
const solver = new GapFillSolverPipeline({
|
|
10
|
+
meshNodes: middleGapFixture.meshNodes as CapacityMeshNode[],
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
solver.solve()
|
|
14
|
+
|
|
15
|
+
const { outputNodes } = solver.getOutput()
|
|
16
|
+
|
|
17
|
+
expect(outputNodes.length).toBeGreaterThanOrEqual(
|
|
18
|
+
middleGapFixture.meshNodes.length,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
const finalGraphics = makeCapacityMeshNodeWithLayerInfo(outputNodes)
|
|
22
|
+
const svg = getSvgFromGraphicsObject(
|
|
23
|
+
{ rects: finalGraphics.values().toArray().flat() },
|
|
24
|
+
{
|
|
25
|
+
svgWidth: 640,
|
|
26
|
+
svgHeight: 480,
|
|
27
|
+
},
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
// More means we have added new nodes to fill the gap
|
|
31
|
+
// expect(outputNodes.length).toEqual(3)
|
|
32
|
+
|
|
33
|
+
await expect(svg).toMatchSvgSnapshot(import.meta.path)
|
|
34
|
+
})
|