Skip to content

Commit a59a06d

Browse files
authored
feat: Add RectDiffPipeline with BasePipelineSolver (#30)
update to use BasePipelineSolver
1 parent 972e706 commit a59a06d

16 files changed

+291
-233
lines changed

components/SolverDebugger3d.tsx

Lines changed: 92 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@ export const SolverDebugger3d: React.FC<SolverDebugger3dProps> = ({
560560
defaultWireframeOutput = false,
561561
style,
562562
}) => {
563-
const [show3d, setShow3d] = useState(false)
563+
const [renderMode, setRenderMode] = useState<"2d" | "3d">("2d")
564564
const [rebuildKey, setRebuildKey] = useState(0)
565565

566566
const [showRoot, setShowRoot] = useState(defaultShowRoot)
@@ -610,204 +610,134 @@ export const SolverDebugger3d: React.FC<SolverDebugger3dProps> = ({
610610
return () => clearInterval(interval)
611611
}, [updateMeshNodes, solver])
612612

613-
const toggle3d = useCallback(() => setShow3d((s) => !s), [])
614613
const rebuild = useCallback(() => setRebuildKey((k) => k + 1), [])
615614

616615
return (
617616
<>
618617
<div style={{ display: "grid", gap: 12, ...style }}>
619-
<GenericSolverDebugger
620-
solver={solver as any}
621-
onSolverCompleted={handleSolverCompleted}
622-
/>
623-
618+
{/* Topbar with Render dropdown */}
624619
<div
625620
style={{
626621
display: "flex",
627-
gap: 8,
622+
gap: 12,
628623
alignItems: "center",
629-
flexWrap: "wrap",
624+
padding: "12px 16px",
625+
background: "#f8fafc",
626+
borderRadius: 8,
627+
border: "1px solid #e2e8f0",
630628
}}
631629
>
632-
<button
633-
onClick={toggle3d}
634-
style={{
635-
padding: "8px 10px",
636-
borderRadius: 6,
637-
border: "1px solid #cbd5e1",
638-
background: show3d ? "#1e293b" : "#2563eb",
639-
color: "white",
640-
cursor: "pointer",
641-
}}
642-
>
643-
{show3d ? "Hide 3D" : "Show 3D"}
644-
</button>
645-
{show3d && (
646-
<button
647-
onClick={rebuild}
630+
<label style={{ display: "flex", gap: 8, alignItems: "center" }}>
631+
<span style={{ fontWeight: 600, fontSize: 14 }}>Render:</span>
632+
<select
633+
value={renderMode}
634+
onChange={(e) => setRenderMode(e.target.value as "2d" | "3d")}
648635
style={{
649-
padding: "8px 10px",
636+
padding: "6px 12px",
650637
borderRadius: 6,
651638
border: "1px solid #cbd5e1",
652-
background: "#0f766e",
653-
color: "white",
639+
background: "white",
654640
cursor: "pointer",
641+
fontSize: 14,
655642
}}
656-
title="Rebuild 3D scene (use after changing solver params)"
657643
>
658-
Rebuild 3D
659-
</button>
660-
)}
661-
662-
{/* experiment-like toggles */}
663-
<label
664-
style={{
665-
display: "inline-flex",
666-
gap: 6,
667-
alignItems: "center",
668-
marginLeft: 8,
669-
}}
670-
>
671-
<input
672-
type="checkbox"
673-
checked={showRoot}
674-
onChange={(e) => setShowRoot(e.target.checked)}
675-
/>
676-
Root
677-
</label>
678-
<label
679-
style={{ display: "inline-flex", gap: 6, alignItems: "center" }}
680-
>
681-
<input
682-
type="checkbox"
683-
checked={showObstacles}
684-
onChange={(e) => setShowObstacles(e.target.checked)}
685-
/>
686-
Obstacles
644+
<option value="2d">2D (Normal)</option>
645+
<option value="3d">3D View</option>
646+
</select>
687647
</label>
688-
<label
689-
style={{ display: "inline-flex", gap: 6, alignItems: "center" }}
690-
>
691-
<input
692-
type="checkbox"
693-
checked={showOutput}
694-
onChange={(e) => setShowOutput(e.target.checked)}
695-
/>
696-
Output
697-
</label>
698-
<label
699-
style={{ display: "inline-flex", gap: 6, alignItems: "center" }}
700-
>
701-
<input
702-
type="checkbox"
703-
checked={wireframeOutput}
704-
onChange={(e) => setWireframeOutput(e.target.checked)}
705-
/>
706-
Wireframe Output
707-
</label>
708-
709-
{/* Mesh opacity slider */}
710-
{show3d && (
711-
<label
712-
style={{
713-
display: "inline-flex",
714-
alignItems: "center",
715-
gap: 6,
716-
marginLeft: 8,
717-
fontSize: 12,
718-
}}
719-
>
720-
Opacity
721-
<input
722-
type="range"
723-
min={0}
724-
max={1}
725-
step={0.05}
726-
value={meshOpacity}
727-
onChange={(e) => setMeshOpacity(parseFloat(e.target.value))}
728-
/>
729-
<span style={{ width: 32, textAlign: "right" }}>
730-
{meshOpacity.toFixed(2)}
731-
</span>
732-
</label>
733-
)}
734648

735-
{/* Shrink boxes option */}
736-
{show3d && (
649+
{renderMode === "3d" && (
737650
<>
651+
<button
652+
onClick={rebuild}
653+
style={{
654+
padding: "6px 12px",
655+
borderRadius: 6,
656+
border: "1px solid #cbd5e1",
657+
background: "#0f766e",
658+
color: "white",
659+
cursor: "pointer",
660+
fontSize: 14,
661+
}}
662+
title="Rebuild 3D scene"
663+
>
664+
Rebuild
665+
</button>
666+
738667
<label
739668
style={{
740669
display: "inline-flex",
741670
gap: 6,
742671
alignItems: "center",
743-
fontSize: 12,
672+
fontSize: 13,
744673
}}
745674
>
746675
<input
747676
type="checkbox"
748-
checked={shrinkBoxes}
749-
onChange={(e) => setShrinkBoxes(e.target.checked)}
677+
checked={showRoot}
678+
onChange={(e) => setShowRoot(e.target.checked)}
750679
/>
751-
Shrink boxes
680+
Root
752681
</label>
753-
{shrinkBoxes && (
754-
<label
755-
style={{
756-
display: "inline-flex",
757-
gap: 4,
758-
alignItems: "center",
759-
fontSize: 12,
760-
}}
761-
>
762-
amt
763-
<input
764-
type="number"
765-
value={boxShrinkAmount}
766-
step={0.05}
767-
style={{ width: 60 }}
768-
onChange={(e) => {
769-
const v = parseFloat(e.target.value)
770-
if (Number.isNaN(v)) return
771-
setBoxShrinkAmount(Math.max(0, v))
772-
}}
773-
/>
774-
</label>
775-
)}
776-
</>
777-
)}
778-
779-
{/* Show borders option */}
780-
{show3d && (
781-
<label
782-
style={{
783-
display: "inline-flex",
784-
gap: 6,
785-
alignItems: "center",
786-
fontSize: 12,
787-
}}
788-
>
789-
<input
790-
type="checkbox"
791-
checked={showBorders}
792-
disabled={wireframeOutput}
793-
onChange={(e) => setShowBorders(e.target.checked)}
794-
/>
795-
<span
682+
<label
683+
style={{
684+
display: "inline-flex",
685+
gap: 6,
686+
alignItems: "center",
687+
fontSize: 13,
688+
}}
689+
>
690+
<input
691+
type="checkbox"
692+
checked={showObstacles}
693+
onChange={(e) => setShowObstacles(e.target.checked)}
694+
/>
695+
Obstacles
696+
</label>
697+
<label
698+
style={{
699+
display: "inline-flex",
700+
gap: 6,
701+
alignItems: "center",
702+
fontSize: 13,
703+
}}
704+
>
705+
<input
706+
type="checkbox"
707+
checked={showOutput}
708+
onChange={(e) => setShowOutput(e.target.checked)}
709+
/>
710+
Output
711+
</label>
712+
<label
796713
style={{
797-
opacity: wireframeOutput ? 0.5 : 1,
714+
display: "inline-flex",
715+
gap: 6,
716+
alignItems: "center",
717+
fontSize: 13,
798718
}}
799719
>
800-
Show borders
801-
</span>
802-
</label>
720+
<input
721+
type="checkbox"
722+
checked={wireframeOutput}
723+
onChange={(e) => setWireframeOutput(e.target.checked)}
724+
/>
725+
Wireframe
726+
</label>
727+
</>
803728
)}
804-
805-
<div style={{ fontSize: 12, color: "#334155", marginLeft: 6 }}>
806-
Drag to orbit · Wheel to zoom · Right-drag to pan
807-
</div>
808729
</div>
809730

810-
{show3d && (
731+
{/* Render 2D view */}
732+
{renderMode === "2d" && (
733+
<GenericSolverDebugger
734+
solver={solver as any}
735+
onSolverCompleted={handleSolverCompleted}
736+
/>
737+
)}
738+
739+
{/* Render 3D view */}
740+
{renderMode === "3d" && (
811741
<ThreeBoardView
812742
key={rebuildKey}
813743
nodes={meshNodes}

lib/RectDiffPipeline.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { BasePipelineSolver, definePipelineStep } from "@tscircuit/solver-utils"
2+
import type { SimpleRouteJson } from "./types/srj-types"
3+
import type { GridFill3DOptions } from "./solvers/rectdiff/types"
4+
import { RectDiffSolver } from "./solvers/RectDiffSolver"
5+
import type { CapacityMeshNode } from "./types/capacity-mesh-types"
6+
import type { GraphicsObject } from "graphics-debug"
7+
import { createBaseVisualization } from "./solvers/rectdiff/visualization"
8+
9+
export interface RectDiffPipelineInput {
10+
simpleRouteJson: SimpleRouteJson
11+
gridOptions?: Partial<GridFill3DOptions>
12+
}
13+
14+
export class RectDiffPipeline extends BasePipelineSolver<RectDiffPipelineInput> {
15+
rectDiffSolver?: RectDiffSolver
16+
17+
override pipelineDef = [
18+
definePipelineStep(
19+
"rectDiffSolver",
20+
RectDiffSolver,
21+
(instance) => [
22+
{
23+
simpleRouteJson: instance.inputProblem.simpleRouteJson,
24+
gridOptions: instance.inputProblem.gridOptions,
25+
},
26+
],
27+
{
28+
onSolved: () => {
29+
// RectDiff mesh generation completed
30+
},
31+
},
32+
),
33+
]
34+
35+
override getConstructorParams() {
36+
return [this.inputProblem]
37+
}
38+
39+
override getOutput(): { meshNodes: CapacityMeshNode[] } {
40+
return this.getSolver<RectDiffSolver>("rectDiffSolver")!.getOutput()
41+
}
42+
43+
override visualize(): GraphicsObject {
44+
const solver = this.getSolver<RectDiffSolver>("rectDiffSolver")
45+
if (solver) {
46+
return solver.visualize()
47+
}
48+
49+
// Show board and obstacles even before solver is initialized
50+
return createBaseVisualization(
51+
this.inputProblem.simpleRouteJson,
52+
"RectDiff Pipeline (not started)",
53+
)
54+
}
55+
}

lib/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export * from "./solvers/RectDiffSolver"
1+
export * from "./RectDiffPipeline"

lib/solvers/RectDiffSolver.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// lib/solvers/RectDiffSolver.ts
2-
import { BaseSolver } from "@tscircuit/solver-utils"
2+
import { BaseSolver, BasePipelineSolver } from "@tscircuit/solver-utils"
33
import type { SimpleRouteJson } from "../types/srj-types"
44
import type { GraphicsObject } from "graphics-debug"
55
import type { CapacityMeshNode } from "../types/capacity-mesh-types"

0 commit comments

Comments
 (0)