@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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/rectdiff",
3
- "version": "0.0.16",
3
+ "version": "0.0.17",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -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
+ })