sycan.svg_util¶
SVG glue used by sycan.autodraw.
This module is the only place that knows about SVG syntax: parsing
res/<kind>.svg glyph files (viewBox + <circle id="port-X"> port
markers) and serialising the final schematic. The autodraw layer
hands a list of placed components, the routed polylines, and the
loaded glyphs in, and gets a ready-to-write SVG string back.
Keeping this code in its own file means autodraw.py can stay
focused on the layout algorithm.
Functions
|
Return an inline SVG with stacked magnitude/phase Bode panels. |
|
Serialise a routed schematic to SVG. |
|
Compute the tight bounding box of all visible primitives plus port markers in a glyph's inner SVG content. |
|
|
|
Read a glyph SVG. Returns a dict with the keys::. |
|
Load every available |
|
Extract |
|
Generate an HTML inspector for the glyphs under |
- sycan.svg_util.parse_port_markers(inner)[source]¶
Extract
{port: (x, y)}from a glyph’s inner SVG content.Recognised forms (any tag, any glyph file):
<circle id="port-NAME" cx="X" cy="Y" r="0" /><rect id="port-NAME" x="X" y="Y" ... />any element with
id="port-NAME" data-x="X" data-y="Y"
Coordinates are in the glyph’s own viewBox space, with
(0, 0)being the top-left of the viewBox.- Parameters:
inner (str)
- Return type:
dict[str, tuple[float, float]]
- sycan.svg_util.geometric_bbox(inner)[source]¶
Compute the tight bounding box of all visible primitives plus port markers in a glyph’s inner SVG content.
Returns
(x_min, y_min, x_max, y_max)in the SVG’s own user units, orNoneif nothing was renderable. Port markers are included as their centre points (so wire-attachment positions always lie inside the box without inflating it by the marker radius). Curve commands and arcs are bounded by control points, which is a conservative super-set of the true extent.- Parameters:
inner (str)
- Return type:
Tuple[float, float, float, float] | None
- sycan.svg_util.load_glyph(path, default_w, default_h, *, snap_grid=10.0)[source]¶
Read a glyph SVG. Returns a dict with the keys:
{ "viewbox": "x y w h", # bbox in inner-svg coords "svg_viewbox": "x y w h", # original SVG viewBox attribute "inner": "<svg body>", "bbox_w": float, # bbox width on the canvas "bbox_h": float, # bbox height on the canvas "ports": {port: (x, y)}, # relative to the bbox origin }
or
Noneif the file is missing / malformed.default_w/default_hare last-resort fallbacks when neither a viewBox nor width/height attributes are present and the geometric scan finds nothing renderable.The reported bbox starts from the tight geometric bbox of the drawing primitives + port markers — not the SVG
viewBoxattribute, which is frequently the editor canvas and may not match the drawing. The geometric bbox is then shifted to align with the port grid so that every port coordinate becomes a multiple ofsnap_gridafter re-anchoring (see below).snap_grid(default10) is the routing-grid pitch that the autodraw layer uses. When non-zero, the bbox origin is snapped so that the topmost port (the natural “wiring terminal” for column layout) lands at a grid-aligned offset; provided the user designed every port at grid-multiple spacings from it, the rest follow. The bbox dimensions are also expanded out to grid multiples so that column edges stay on the grid.Pass
snap_grid=0to disable snapping entirely and get the raw geometric bbox — useful for diagnosing port-placement bugs.- Parameters:
path (Path)
default_w (float)
default_h (float)
snap_grid (float)
- Return type:
dict | None
- sycan.svg_util.load_glyphs(res_dir, default_w, default_h)[source]¶
Load every available
res/<kind>.svgglyph (seeload_glyph()).Returns
{kind: glyph_info}. Missing kinds are absent; those components fall back to the default rect with canonical pin positions in the autodraw layer.- Parameters:
res_dir (str | Path | None)
default_w (float)
default_h (float)
- Return type:
dict[str, dict]
- sycan.svg_util.emit_svg(placed, polylines, canvas_w, canvas_h, rail_top_y, rail_bot_y, *, label_fs=11, port_fs=9, glyphs=None, short_port=None, solder_dots=None, back_annotation=None, top_rail=None, bot_rail=None, group_boxes=None)[source]¶
Serialise a routed schematic to SVG.
placedis an iterable of_Placed-like objects (anything with.cx,.cy,.pin_pos,.pin_side, and a.descthat carrieslabel,kind,bbox_w,bbox_h,mirror,flip).polylinesis the list of routed wires/rails as(net_class, [(x, y), ...])pairs (a class starting with"rail"is drawn in the rail style).glyphsmaps a kind to the dict produced byload_glyph(); components whose kind is inglyphsrender as<use>references, the rest fall back to a labelled<rect>.short_portis an optional callable mapping a port name to its short label glyph (e.g.,"drain" → "D"); defaults to using the first two characters of the port name.- Parameters:
placed (Sequence)
polylines (Sequence[tuple[str, list[tuple[float, float]]]])
canvas_w (float)
canvas_h (float)
rail_top_y (float)
rail_bot_y (float)
label_fs (int)
port_fs (int)
glyphs (dict[str, dict] | None)
short_port (callable | None)
solder_dots (Sequence[tuple[float, float]] | None)
back_annotation (dict[str, Sequence[str]] | None)
top_rail (str | None)
bot_rail (str | None)
group_boxes (Sequence[tuple[str, float, float, float, float]] | None)
- Return type:
str
- sycan.svg_util.view_glyphs(res_dir=None, *, default_w=70.0, default_h=60.0, output=None, open_browser=True)[source]¶
Generate an HTML inspector for the glyphs under
res_dir.Each card shows the glyph rendered in a 0..bbox_w / 0..bbox_h frame, the parsed bounding box (translucent blue rectangle), and a labelled dot for every port marker that
load_glyph()found. This is exactly the data thatload_glyphs()returns to autodraw, so the page is the visual ground truth for what the placer is using.- Parameters:
res_dir (str | Path | None) – Directory of glyph SVGs. Defaults to
<repo>/res/relative to this file.default_w (float) – Fallback dimensions for SVGs with neither viewBox nor explicit width/height attributes (mirrors
load_glyph()).default_h (float) – Fallback dimensions for SVGs with neither viewBox nor explicit width/height attributes (mirrors
load_glyph()).output (str | Path | None) – Path to write the HTML to. If
None(default), a temp file is created.open_browser (bool) – Launch the system default browser on the generated file.
- Return type:
The path to the HTML file that was written.
- sycan.svg_util.bode_svg(omegas, mag_db, phase_deg, title='', *, width=720, height=460, mag_range=(-80.0, 10.0))[source]¶
Return an inline SVG with stacked magnitude/phase Bode panels.
omegasis the angular-frequency axis (assumed log-spaced and monotonically increasing).mag_dbandphase_degmust be the same length asomegas. The phase y-axis auto-ranges to the nearest 90° and a dashed -3 dB reference line is overlaid on the magnitude panel.- Parameters:
title (str)
width (int)
height (int)
mag_range (tuple[float, float])
- Return type:
str