@tscircuit/rectdiff 0.0.39 → 0.0.40

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 (53) hide show
  1. package/.github/workflows/bun-test.yml +1 -1
  2. package/lib/RectDiffPipeline.ts +0 -27
  3. package/lib/solvers/OuterLayerContainmentMergeSolver/OuterLayerContainmentMergeSolver.ts +4 -108
  4. package/package.json +1 -1
  5. package/tests/solver/__snapshots__/rectDiffGridSolverPipeline.snap.svg +3 -3
  6. package/tests/solver/arduino-uno-inner2-ground-bottom-power/__snapshots__/arduino-uno-inner2-ground-bottom-power.snap.svg +3 -3
  7. package/tests/solver/arduino-uno-inner2-ground-inner1-power/__snapshots__/arduino-uno-inner2-ground-inner1-power.snap.svg +1 -1
  8. package/tests/solver/both-points-equivalent/__snapshots__/both-points-equivalent.snap.svg +1 -1
  9. package/tests/solver/bugreport02-bc4361/__snapshots__/bugreport02-bc4361.snap.svg +3 -3
  10. package/tests/solver/bugreport03-fe4a17/__snapshots__/bugreport03-fe4a17.snap.svg +1 -1
  11. package/tests/solver/bugreport08-e3ec95/__snapshots__/bugreport08-e3ec95.snap.svg +1 -1
  12. package/tests/solver/bugreport09-618e09/__snapshots__/bugreport09-618e09.snap.svg +1 -1
  13. package/tests/solver/bugreport10-71239a/__snapshots__/bugreport10-71239a.snap.svg +3 -3
  14. package/tests/solver/bugreport11-b2de3c/__snapshots__/bugreport11-b2de3c.snap.svg +3 -3
  15. package/tests/solver/bugreport13-b9a758/__snapshots__/bugreport13-b9a758.snap.svg +2 -2
  16. package/tests/solver/bugreport16-d95f38/__snapshots__/bugreport16-d95f38.snap.svg +1 -1
  17. package/tests/solver/bugreport18-1b2d06/__snapshots__/bugreport18-1b2d06.snap.svg +3 -3
  18. package/tests/solver/bugreport19/__snapshots__/bugreport19.snap.svg +1 -1
  19. package/tests/solver/bugreport22-2a75ce/__snapshots__/bugreport22-2a75ce.snap.svg +1 -1
  20. package/tests/solver/bugreport23-LGA15x4/__snapshots__/bugreport23-LGA15x4.snap.svg +2 -2
  21. package/tests/solver/bugreport24-05597c/__snapshots__/bugreport24-05597c.snap.svg +1 -1
  22. package/tests/solver/bugreport25-4b1d55/__snapshots__/bugreport25-4b1d55.snap.svg +3 -3
  23. package/tests/solver/bugreport36-bf8303/__snapshots__/bugreport36-bf8303.snap.svg +2 -2
  24. package/tests/solver/interaction/__snapshots__/interaction.snap.svg +3 -3
  25. package/tests/solver/multi-point/__snapshots__/multi-point.snap.svg +1 -1
  26. package/tests/solver/no-better-path/__snapshots__/no-better-path.snap.svg +1 -1
  27. package/tests/solver/offboardconnects01/__snapshots__/offboardconnects01.snap.svg +1 -1
  28. package/tests/solver/pcb_trace_id-should-return-root-connection-name/__snapshots__/pcb_trace_id-should-return-root-connection-name.snap.svg +3 -3
  29. package/tests/solver/repros/merge-single-layer-node/__snapshots__/merge-single-layer-node.snap.svg +3 -3
  30. package/tests/solver/transitivity/__snapshots__/transitivity.snap.svg +2 -2
  31. package/lib/math/layers/getUnionZ.ts +0 -6
  32. package/lib/math/layers/getZLayerName.ts +0 -6
  33. package/lib/math/layers/getZSpanMask.ts +0 -6
  34. package/lib/math/layers/hasContiguousZSpan.ts +0 -11
  35. package/lib/math/rects/intersectRects.ts +0 -28
  36. package/lib/math/rects/mergeRects.ts +0 -12
  37. package/lib/math/rects/rectArea.ts +0 -7
  38. package/lib/math/rects/rectContainsRect.ts +0 -18
  39. package/lib/math/rects/rectsTouchOrOverlap.ts +0 -12
  40. package/lib/math/rects/subtractRects.ts +0 -23
  41. package/lib/solvers/SparseMultilayerPromotionSolver/SparseMultilayerPromotionSolver.ts +0 -134
  42. package/lib/solvers/SparseMultilayerPromotionSolver/cloneNode.ts +0 -15
  43. package/lib/solvers/SparseMultilayerPromotionSolver/cloneNodeWithRect.ts +0 -34
  44. package/lib/solvers/SparseMultilayerPromotionSolver/createResidualNodes.ts +0 -42
  45. package/lib/solvers/SparseMultilayerPromotionSolver/findBestCoalesceCandidate.ts +0 -98
  46. package/lib/solvers/SparseMultilayerPromotionSolver/findBestPromotionCandidate.ts +0 -72
  47. package/lib/solvers/SparseMultilayerPromotionSolver/getUsableMultilayerVolumeShare.ts +0 -34
  48. package/lib/solvers/SparseMultilayerPromotionSolver/isFreeNode.ts +0 -8
  49. package/lib/solvers/SparseMultilayerPromotionSolver/nodeToRect.ts +0 -13
  50. package/lib/solvers/SparseMultilayerPromotionSolver/solvers/CoalesceMultilayerTilesSolver.ts +0 -104
  51. package/lib/solvers/SparseMultilayerPromotionSolver/solvers/PromoteSparseMultilayerCoverageSolver.ts +0 -148
  52. package/lib/solvers/SparseMultilayerPromotionSolver/solvers/TrimContainedSingleLayerCoverageSolver.ts +0 -137
  53. package/lib/solvers/SparseMultilayerPromotionSolver/types.ts +0 -23
@@ -1,148 +0,0 @@
1
- import { BaseSolver } from "@tscircuit/solver-utils"
2
- import type { GraphicsObject } from "graphics-debug"
3
- import type {
4
- CapacityMeshNode,
5
- CapacityMeshNodeId,
6
- } from "../../../types/capacity-mesh-types"
7
- import { getZLayerName } from "../../../math/layers/getZLayerName"
8
- import { getColorForZLayer } from "../../../utils/getColorForZLayer"
9
- import { cloneNode } from "../cloneNode"
10
- import { cloneNodeWithRect } from "../cloneNodeWithRect"
11
- import { createResidualNodes } from "../createResidualNodes"
12
- import { findBestPromotionCandidate } from "../findBestPromotionCandidate"
13
- import { getUsableMultilayerVolumeShare } from "../getUsableMultilayerVolumeShare"
14
-
15
- type PromoteSparseMultilayerCoverageSolverInput = {
16
- meshNodes: CapacityMeshNode[]
17
- minRectSize: number
18
- promotionTargetShare: number
19
- }
20
-
21
- /**
22
- * Turn overlapping single-layer space into shared space.
23
- * It runs until the configured shared-space threshold is reached.
24
- */
25
- export class PromoteSparseMultilayerCoverageSolver extends BaseSolver {
26
- private nextMergedId = 0
27
- private nextResidualId = 0
28
- private outputNodes: CapacityMeshNode[] = []
29
- private promotedNodeIds = new Set<CapacityMeshNodeId>()
30
- private residualNodeIds = new Set<CapacityMeshNodeId>()
31
- private workingNodes: CapacityMeshNode[] = []
32
-
33
- constructor(private input: PromoteSparseMultilayerCoverageSolverInput) {
34
- super()
35
- }
36
-
37
- override _setup() {
38
- this.nextMergedId = 0
39
- this.nextResidualId = 0
40
- this.promotedNodeIds.clear()
41
- this.residualNodeIds.clear()
42
- this.workingNodes = this.input.meshNodes.map((node) => cloneNode({ node }))
43
- this.outputNodes = [...this.workingNodes]
44
- }
45
-
46
- override _step() {
47
- if (
48
- getUsableMultilayerVolumeShare({ nodes: this.workingNodes }) >=
49
- this.input.promotionTargetShare
50
- ) {
51
- this.outputNodes = [...this.workingNodes]
52
- this.solved = true
53
- return
54
- }
55
-
56
- const candidate = findBestPromotionCandidate({
57
- minRectSize: this.input.minRectSize,
58
- nodes: this.workingNodes,
59
- })
60
- if (!candidate) {
61
- this.outputNodes = [...this.workingNodes]
62
- this.solved = true
63
- return
64
- }
65
-
66
- const { sourceNode, targetNode } = candidate
67
- if (!sourceNode || !targetNode) {
68
- this.outputNodes = [...this.workingNodes]
69
- this.solved = true
70
- return
71
- }
72
-
73
- const mergedNode = cloneNodeWithRect({
74
- templateNode: sourceNode,
75
- rect: candidate.rect,
76
- capacityMeshNodeId: `sparse-multilayer-merge-${this.nextMergedId++}`,
77
- availableZ: candidate.unionZ,
78
- })
79
- this.promotedNodeIds.add(mergedNode.capacityMeshNodeId)
80
-
81
- this.workingNodes = [
82
- ...this.workingNodes.filter(
83
- (node) =>
84
- node.capacityMeshNodeId !== sourceNode.capacityMeshNodeId &&
85
- node.capacityMeshNodeId !== targetNode.capacityMeshNodeId,
86
- ),
87
- mergedNode,
88
- ...createResidualNodes({
89
- cutRect: candidate.rect,
90
- getNextResidualId: () => this.nextResidualId++,
91
- idPrefix: `${sourceNode.capacityMeshNodeId}-sparse-residual`,
92
- node: sourceNode,
93
- onResidualNodeIdCreated: (nodeId) => this.residualNodeIds.add(nodeId),
94
- }),
95
- ...createResidualNodes({
96
- cutRect: candidate.rect,
97
- getNextResidualId: () => this.nextResidualId++,
98
- idPrefix: `${targetNode.capacityMeshNodeId}-sparse-residual`,
99
- node: targetNode,
100
- onResidualNodeIdCreated: (nodeId) => this.residualNodeIds.add(nodeId),
101
- }),
102
- ]
103
-
104
- this.outputNodes = [...this.workingNodes]
105
- }
106
-
107
- override getOutput() {
108
- return {
109
- outputNodes: this.outputNodes,
110
- promotedNodeIds: this.promotedNodeIds,
111
- residualNodeIds: this.residualNodeIds,
112
- }
113
- }
114
-
115
- override visualize(): GraphicsObject {
116
- return {
117
- title: "PromoteSparseMultilayerCoverageSolver",
118
- coordinateSystem: "cartesian",
119
- rects: this.outputNodes.map((node) => {
120
- const colors = getColorForZLayer(node.availableZ)
121
- const isPromoted = this.promotedNodeIds.has(node.capacityMeshNodeId)
122
- const isResidual = this.residualNodeIds.has(node.capacityMeshNodeId)
123
-
124
- return {
125
- center: node.center,
126
- width: node.width,
127
- height: node.height,
128
- stroke: isPromoted
129
- ? "rgba(168, 85, 247, 0.95)"
130
- : isResidual
131
- ? "rgba(14, 116, 144, 0.95)"
132
- : colors.stroke,
133
- fill: node._containsObstacle
134
- ? "rgba(239, 68, 68, 0.35)"
135
- : isPromoted
136
- ? "rgba(192, 132, 252, 0.28)"
137
- : isResidual
138
- ? "rgba(34, 211, 238, 0.18)"
139
- : colors.fill,
140
- layer: getZLayerName({ availableZ: node.availableZ }),
141
- }
142
- }),
143
- points: [],
144
- lines: [],
145
- texts: [],
146
- }
147
- }
148
- }
@@ -1,137 +0,0 @@
1
- import { BaseSolver } from "@tscircuit/solver-utils"
2
- import type { GraphicsObject } from "graphics-debug"
3
- import type {
4
- CapacityMeshNode,
5
- CapacityMeshNodeId,
6
- } from "../../../types/capacity-mesh-types"
7
- import { getZLayerName } from "../../../math/layers/getZLayerName"
8
- import { EPS } from "../../../utils/rectdiff-geometry"
9
- import { cloneNode } from "../cloneNode"
10
- import { cloneNodeWithRect } from "../cloneNodeWithRect"
11
- import { getUsableMultilayerVolumeShare } from "../getUsableMultilayerVolumeShare"
12
- import { isFreeNode } from "../isFreeNode"
13
- import { nodeToRect } from "../nodeToRect"
14
- import { getColorForZLayer } from "../../../utils/getColorForZLayer"
15
- import { subtractRects } from "../../../math/rects/subtractRects"
16
-
17
- type TrimContainedSingleLayerCoverageSolverInput = {
18
- meshNodes: CapacityMeshNode[]
19
- minRectSize: number
20
- promotionTargetShare: number
21
- }
22
-
23
- /**
24
- * Remove single-layer pieces that are already covered by shared space.
25
- * This keeps the result smaller and simpler.
26
- */
27
- export class TrimContainedSingleLayerCoverageSolver extends BaseSolver {
28
- private nextResidualId = 0
29
- private outputNodes: CapacityMeshNode[] = []
30
- private residualNodeIds = new Set<CapacityMeshNodeId>()
31
-
32
- constructor(private input: TrimContainedSingleLayerCoverageSolverInput) {
33
- super()
34
- }
35
-
36
- override _setup() {
37
- this.nextResidualId = 0
38
- this.residualNodeIds.clear()
39
- this.outputNodes = this.input.meshNodes.map((node) => cloneNode({ node }))
40
- }
41
-
42
- override _step() {
43
- if (
44
- getUsableMultilayerVolumeShare({ nodes: this.outputNodes }) >=
45
- this.input.promotionTargetShare
46
- ) {
47
- this.solved = true
48
- return
49
- }
50
-
51
- const freeMultilayerNodes = this.outputNodes.filter(
52
- (node) => isFreeNode({ node }) && node.availableZ.length > 1,
53
- )
54
- const nextNodes: CapacityMeshNode[] = []
55
-
56
- for (const node of this.outputNodes) {
57
- if (!isFreeNode({ node }) || node.availableZ.length !== 1) {
58
- nextNodes.push(node)
59
- continue
60
- }
61
-
62
- const z = node.availableZ[0]!
63
- const coveringRects = freeMultilayerNodes
64
- .filter((candidate) => candidate.availableZ.includes(z))
65
- .map((candidate) => nodeToRect({ node: candidate }))
66
-
67
- if (coveringRects.length === 0) {
68
- nextNodes.push(node)
69
- continue
70
- }
71
-
72
- const nodeRect = nodeToRect({ node })
73
- const residuals = subtractRects({
74
- target: nodeRect,
75
- cutters: coveringRects,
76
- }).filter(
77
- (rect) =>
78
- rect.width + EPS >= this.input.minRectSize &&
79
- rect.height + EPS >= this.input.minRectSize,
80
- )
81
-
82
- if (
83
- residuals.length === 1 &&
84
- Math.abs(residuals[0]!.x - nodeRect.x) <= EPS &&
85
- Math.abs(residuals[0]!.y - nodeRect.y) <= EPS &&
86
- Math.abs(residuals[0]!.width - nodeRect.width) <= EPS &&
87
- Math.abs(residuals[0]!.height - nodeRect.height) <= EPS
88
- ) {
89
- nextNodes.push(node)
90
- continue
91
- }
92
-
93
- for (const rect of residuals) {
94
- const residualNode = cloneNodeWithRect({
95
- templateNode: node,
96
- rect,
97
- capacityMeshNodeId: `${node.capacityMeshNodeId}-contained-residual-${this.nextResidualId++}`,
98
- })
99
- this.residualNodeIds.add(residualNode.capacityMeshNodeId)
100
- nextNodes.push(residualNode)
101
- }
102
- }
103
-
104
- this.outputNodes = nextNodes
105
- this.solved = true
106
- }
107
-
108
- override getOutput() {
109
- return {
110
- outputNodes: this.outputNodes,
111
- residualNodeIds: this.residualNodeIds,
112
- }
113
- }
114
-
115
- override visualize(): GraphicsObject {
116
- return {
117
- title: "TrimContainedSingleLayerCoverageSolver",
118
- coordinateSystem: "cartesian",
119
- rects: this.outputNodes.map((node) => {
120
- const colors = getColorForZLayer(node.availableZ)
121
- const isResidual = this.residualNodeIds.has(node.capacityMeshNodeId)
122
-
123
- return {
124
- center: node.center,
125
- width: node.width,
126
- height: node.height,
127
- stroke: isResidual ? "rgba(14, 116, 144, 0.95)" : colors.stroke,
128
- fill: isResidual ? "rgba(34, 211, 238, 0.18)" : colors.fill,
129
- layer: getZLayerName({ availableZ: node.availableZ }),
130
- }
131
- }),
132
- points: [],
133
- lines: [],
134
- texts: [],
135
- }
136
- }
137
- }
@@ -1,23 +0,0 @@
1
- import type { CapacityMeshNode } from "../../types/capacity-mesh-types"
2
- import type { XYRect } from "../../rectdiff-types"
3
- import type { SimpleRouteJson } from "../../types/srj-types"
4
-
5
- export type SparseMultilayerPromotionInput = {
6
- meshNodes: CapacityMeshNode[]
7
- promotionTargetShare: number
8
- simpleRouteJson: SimpleRouteJson
9
- }
10
-
11
- export type PromotionCandidate = {
12
- rect: XYRect
13
- sourceNode: CapacityMeshNode
14
- targetNode: CapacityMeshNode
15
- unionZ: number[]
16
- area: number
17
- }
18
-
19
- export type CoalesceCandidate = {
20
- rect: XYRect
21
- absorbedNodes: CapacityMeshNode[]
22
- score: number
23
- }