From 347f569968c7a25ebd8c576df15665b3ba30e021 Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Sun, 1 Mar 2026 23:30:57 -0700 Subject: [PATCH] Fix title parser and feedback component routing in schematics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Title parser: always use line 0 as title per SPICE convention instead of skipping * comment lines (which consumed component definitions). Layout engine: pass growing placed set to path tracing to prevent feedback components (e.g. col→base cap) from being double-traced. Route feedback paths from the output terminal horizontally right instead of defaulting to "down" through the transistor body. --- backend/src/spicebook/engine/schematic.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/backend/src/spicebook/engine/schematic.py b/backend/src/spicebook/engine/schematic.py index 3acd216..7a4a0f7 100644 --- a/backend/src/spicebook/engine/schematic.py +++ b/backend/src/spicebook/engine/schematic.py @@ -122,15 +122,12 @@ def parse_netlist(text: str) -> ParsedNetlist: if not lines: return ParsedNetlist() - # First non-blank, non-directive line is the title (SPICE convention) - title = "" - first_content = 0 - for i, line in enumerate(lines): - stripped = line.strip() - if stripped and not stripped.startswith(("*", ";", ".")): - title = stripped - first_content = i + 1 - break + # SPICE convention: line 1 is always the title, regardless of content. + # Strip leading * or ; (common title prefix) for display purposes. + title = lines[0].strip() + if title.startswith(("*", ";")): + title = title[1:].strip() + first_content = 1 # Pre-scan for .model statements to determine BJT/MOSFET polarity models: dict[str, str] = {} @@ -503,7 +500,7 @@ def _plan_active_layout( placed = set(exclude) for tname, tnode in terminals.items(): - tpaths = _trace_paths_from_terminal(tnode, tname, node_map, exclude) + tpaths = _trace_paths_from_terminal(tnode, tname, node_map, placed) paths[tname] = tpaths for p in tpaths: for c in p.components: @@ -557,6 +554,11 @@ def _path_style( return "output" if path.end_type == "ground": return "down" + # Feedback / coupling paths ending at non-supply, non-ground nodes + # (e.g., collector→base feedback cap): route horizontally outward + # from the output terminal to avoid crossing through the body. + if term_name == output_term: + return "output" return "down"