API reference
Every name symdef exports, in the order of symdef.__all__.
DEFAULT_MODULE_MM
constant
Value: 2.5
GRID_DIVISION
constant
Value: 0.125
LIBRARY_VERSION
constant
Value: '0.16.0'
Allow
class
Allow(rule: str, reason: str) -> None
A lint exemption with its reason.
Anchor
class
Anchor(id: str, position: symdef.geometry.Point, direction: symdef.geometry.Direction) -> None
An attachment point for composition.
Attributes:
position: In module units.
direction: The way the anchor faces; two anchors join when they face each other.
Arc
class
Arc(center: symdef.geometry.Point, radius: float, start_deg: float, end_deg: float, weight: symdef.geometry.Weight = <Weight.NORMAL: 0.1>, style: symdef.geometry.Style = <Style.SOLID: 'solid'>) -> None
A circular arc swept clockwise on screen from start_deg to end_deg.
Angles are in degrees, measured clockwise on screen from +x (so 90 points down). Equal
angles make a full circle.
Box
class
Box(min: symdef.geometry.Point, max: symdef.geometry.Point) -> None
An axis-aligned rectangle in module units, from its min corner to its max corner.
Centre
class
Centre(*values)
The slot side `C`: the text centres on the slot point, along and across its reading line.
It is not a `Direction`: a slot side says where text sits, a port side says where a wire
leaves, and keeping `C` out of `Direction` means a port can never be `C`.
Circle
class
Circle(center: symdef.geometry.Point, radius: float, fill: symdef.geometry.Fill = <Fill.NONE: 'none'>, weight: symdef.geometry.Weight = <Weight.NORMAL: 0.1>) -> None
A circle, optionally filled; the radius is in module units.
Direction
class
Direction(*values)
Compass direction, with the unit vector as its value.
The axes are SVG's, so N is (0, -1) (up on screen) and S is (0, 1).
Element
constant
Value: symdef.geometry.Line | symdef.geometry.Polyline | symdef.geometry.Circle | symdef.geometry.Arc | symdef.geometry.Text
Fill
class
Fill(*values)
Whether a closed shape is filled: not at all, solid black, or with a tint the renderer takes.
A tint is filled with the colour the caller passes to the renderer.
Finding
class
Finding(rule: str, severity: symdef.model.Severity, message: str, location: str | None = None, orientation: symdef.geometry.Orientation | None = None) -> None
One lint or load problem.
Attributes:
rule: The id of the rule that reported it.
message: Human-readable text.
location: Where it is, such as `elements[2]` or `slots.tag`, or None if it is about the
whole symbol.
orientation: The orientation it was found in, or None if the rule does not depend on
orientation.
FontMetrics
class
FontMetrics(name: str, units_per_em: float, cap_height: float, ascent: float, descent: float, advances: collections.abc.Mapping[symdef.geometry.Weight, collections.abc.Mapping[str, float]], default_advance: float, heights: collections.abc.Mapping[str, float] = <factory>, family: str = '') -> None
The measures of one font, in the font's own units; `units_per_em` is one em.
Attributes:
name: The font's name, for the record; it changes no measure.
units_per_em: How many font units make one em, the text height.
cap_height: Height of a capital letter above the baseline, in font units.
ascent: Height of the tallest glyph above the baseline, in font units.
descent: Depth of the lowest glyph below the baseline, in font units.
advances: One table per `Weight`: the advance width of each character, in font units.
default_advance: The advance of a character a table does not list.
heights: Capital heights in millimetres by name, such as `smallest` or `body`. The
names are the library's own; symdef does not interpret them. Empty when none.
family: The family name a renderer resolves the font by. Empty at construction means the
same as `name`, so it is never empty. `measure_font` reads it from the face.
Grid
class
Grid(module_mm: float = 2.5, divisions_per_module: int = 8, wire_pitch: int = 8, wire_pitch_fine: int = 4) -> None
The drawing grid of a library: the size of the module and how many divisions it has.
Attributes:
module_mm: One module in millimetres.
divisions_per_module: How many grid divisions make one module; a power of two, so a
division is exact in floating point.
wire_pitch: The standard wire pitch in divisions; every port sits on it.
wire_pitch_fine: The fine wire pitch in divisions, for a dense page; it divides
`wire_pitch`. A library has these two pitches and no third.
GridBox
class
GridBox(min: symdef.gridtypes.GridPoint, max: symdef.gridtypes.GridPoint) -> None
An axis-aligned rectangle in whole grid divisions, from its min corner to its max corner.
GridPoint
class
GridPoint(x: int, y: int) -> None
A position in whole grid divisions.
GridPort
class
GridPort(id: str, x: int, y: int, direction: symdef.geometry.Direction) -> None
A connection point in whole grid divisions, with the direction it leaves the symbol.
InvalidValueError
class
InvalidValueError(...)
An argument or data is unusable; the message names the value, what is valid and the fix.
Library
class
Library(standard: str, title: str, number_pattern: str, symbols: collections.abc.Mapping[str, symdef.model.Symbol], vocabulary: symdef.model.Vocabulary = Vocabulary(path_kinds=(), potentials=(), links=()), required_slots: tuple[str, ...] = (), wires: tuple[symdef.model.WireStyle, ...] = (), font: symdef.font.FontMetrics | None = None, grid: symdef.units.Grid = Grid(module_mm=2.5, divisions_per_module=8, wire_pitch=8, wire_pitch_fine=4), lines: collections.abc.Mapping[symdef.geometry.Weight, float] = mappingproxy({})) -> None
The symbols of one standard, keyed by reference number.
Iterating yields the symbols sorted by reference number; `len` is their count. `font` is the
metrics text is measured with, or None, which measures 0.6 em per character; `grid` is the
drawing grid; `lines` is the stroke width in millimetres of each `Weight`, empty when the
library declares none.
LibraryError
class
LibraryError(findings: tuple[ForwardRef('Finding', owner=<function LibraryError.__init__ at 0x7f35d110cca0>), ...]) -> None
A library failed to load; `findings` says why.
Line
class
Line(start: symdef.geometry.Point, end: symdef.geometry.Point, weight: symdef.geometry.Weight = <Weight.NORMAL: 0.1>, style: symdef.geometry.Style = <Style.SOLID: 'solid'>, port: str | None = None, between: bool = False) -> None
A straight segment, optionally the lead of a port.
Attributes:
port: The id of the port this line is the lead of, or None for an ordinary line.
between: True for a tick that `table` draws in every row but the last; outside a table
it is drawn as authored.
Measure
class
Measure(body: symdef.gridtypes.GridBox, keepout: symdef.gridtypes.GridBox, slots: collections.abc.Mapping[str, symdef.gridtypes.GridBox], ports: collections.abc.Mapping[str, symdef.gridtypes.GridPort]) -> None
What a symbol takes up and where its ports are, in whole grid divisions.
Attributes:
body: The body box. A box's `max` is the extent rounded up, its `min` rounded down.
keepout: The body united with every slot box.
slots: Slot id to its box, with the text measured when `measure` was given one.
ports: Port id to its position and its direction after the turn.
Node
class
Node(ports: tuple[str, ...], potential: str | None = None) -> None
Ports that are the same electrical point inside the symbol.
Attributes:
ports: Port ids.
potential: A word from the symbol set's `potentials` for the fixed potential the node
stands for, or None for an ordinary node.
Orientation
class
Orientation(*values)
One of the 8 orientations: an optional mirror (flip x), then a clockwise turn by n.
`R<n>` turns by n degrees; `MR<n>` mirrors first, then turns. R0 is the symbol as defined.
Path
class
Path(from_port: str, to_port: str, kind: str, through: bool = False) -> None
A two-terminal relation between the ports of two different nodes.
Attributes:
from_port: Id of the port at one end.
to_port: Id of the port at the other end.
kind: A word from the symbol set's `path_kinds`: the meaning of the relation.
through: Whether this is the symbol's through path, the one `repeat` requires and
keeps on pole 1 only.
Point
class
Point(x: float, y: float) -> None
A position in module units, x to the right and y downwards.
Polyline
class
Polyline(points: tuple[symdef.geometry.Point, ...], closed: bool = False, fill: symdef.geometry.Fill = <Fill.NONE: 'none'>, weight: symdef.geometry.Weight = <Weight.NORMAL: 0.1>, style: symdef.geometry.Style = <Style.SOLID: 'solid'>, between: bool = False) -> None
A chain of segments through `points`, optionally closed and filled.
Attributes:
closed: Whether the last point joins back to the first.
fill: Whether a closed polyline is filled.
between: True for a tick that `table` draws in every row but the last; outside a table
it is drawn as authored.
Port
class
Port(id: str, position: symdef.geometry.Point, direction: symdef.geometry.Direction, description: str = '') -> None
A connection point on a symbol; the id is the only pin identity.
Attributes:
position: Where a wire meets the symbol, in module units.
direction: The outward normal: the side of the body box the port sits on.
description: Free text, empty if none.
Reference
class
Reference(standard: str, number: str, edition: str | None = None, form: str | None = None) -> None
Where a symbol is defined in its standard.
Severity
class
Severity(*values)
How serious a finding is; a data repo gate rejects both.
Slot
class
Slot(id: str, position: symdef.geometry.Point, side: SlotSide, box: tuple[float, float], turn: bool = False) -> None
Room reserved for text the consumer draws; `box` is (width, height).
Attributes:
position: The point the box grows from, in module units.
side: The direction the box grows towards from `position`, or `Centre.C` for a box centred
on it; see `slot_box`.
box: Width and height in module units, never rotated: the footprint as drawn.
turn: True when a string in the slot is drawn turned, reading bottom-up, along the height
of `box`. It is fixed to the page: `orient` never changes it.
Status
class
Status(*values)
Whether a symbol's geometry was checked against the standard's own drawing.
Stretch
class
Stretch(axis: Literal['x', 'y'], at: float, weight: float = 1) -> None
A cut line across the body: `stretch` moves every point beyond it.
Attributes:
axis: The axis the symbol grows along.
at: The cut's coordinate on that axis, in module units.
weight: The cut's share of the growth against the other cuts on its axis; positive.
Style
class
Style(*values)
Line style; dashed is drawn with a dash of 0.5 M and a gap of 0.25 M.
Dash-dot is a dash of 1 M, a gap of 0.25 M, a dot of 0.0625 M and a gap of 0.25 M.
Symbol
class
Symbol(name: str, kind: symdef.model.SymbolKind, status: symdef.model.Status, reference: symdef.model.Reference, elements: tuple[symdef.geometry.Line | symdef.geometry.Polyline | symdef.geometry.Circle | symdef.geometry.Arc | symdef.geometry.Text, ...], ports: tuple[symdef.model.Port, ...] = (), nodes: tuple[symdef.model.Node, ...] = (), paths: tuple[symdef.model.Path, ...] = (), anchors: tuple[symdef.model.Anchor, ...] = (), slots: tuple[symdef.model.Slot, ...] = (), pole_pitch: int | None = None, lint_allow: tuple[symdef.model.Allow, ...] = (), stretch: tuple[symdef.model.Stretch, ...] = ()) -> None
A symbol definition, not a placement: it has no label, tag or position.
Attributes:
name: The symbol's name.
reference: Where the standard defines it.
elements: The drawing, in module units.
pole_pitch: Spacing between poles for `repeat`, in module units; None means 4.
stretch: Cut lines for `stretch`, one or more per axis.
lint_allow: Lint exemptions the symbol claims.
SymbolKind
class
SymbolKind(*values)
Whether a symbol is placeable on its own or exists to be used as a part.
SymdefError
class
SymdefError(...)
Base class for every error this package raises.
Text
class
Text(content: str, position: symdef.geometry.Point, height: float = 1.0, weight: symdef.geometry.Weight = <Weight.NORMAL: 0.1>) -> None
A text label, always middle-anchored and upright; height is in module units.
Attributes:
position: The middle of the label.
TextPlacement
class
TextPlacement(point: symdef.geometry.Point, anchor: Anchor, turned: bool) -> None
Where a slot's string is drawn.
Attributes:
point: The baseline point the text is anchored at, in module units.
anchor: Which end of the text sits on `point`: `start`, `middle` or `end`.
turned: True when the text reads bottom-up, rotated a quarter turn counter-clockwise about
`point`.
UnknownNameError
class
UnknownNameError(...)
A name is not in the set it was looked up in; the message lists the valid names.
UnknownSymbolError
class
UnknownSymbolError(...)
A library lookup found no symbol with the requested reference number.
Vocabulary
class
Vocabulary(path_kinds: tuple[str, ...] = (), potentials: tuple[str, ...] = (), links: tuple[str, ...] = ()) -> None
The words a symbol set declares in `library.toml [vocabulary]`; empty lists by default.
Weight
class
Weight(*values)
Line weight; the value is the stroke width in module units.
WireStyle
class
WireStyle(id: str, weight: symdef.geometry.Weight, style: symdef.geometry.Style) -> None
A named line style for `wire`: one `[[wire]]` table of `library.toml`, or a bundle entry.
Attributes:
id: The name a caller passes to `wire`.
weight: The line weight of the wire.
style: Whether the wire is solid or dashed.
body_box
function
body_box(symbol: symdef.model.Symbol, font: symdef.font.FontMetrics | None = None) -> symdef.geometry.Box
Return the union of the element extents, in module units, ignoring stroke width.
Extents are as for text (`text_width` with `font`; with no font `0.6 * height` per character),
arcs (the true swept extent) and the other elements. A symbol without elements has the box
(0, 0) to (0, 0). Ports, anchors and slots do not count.
ceil_divisions
function
ceil_divisions(grid: symdef.units.Grid, v: float) -> int
Round a value in module units up to whole grid divisions.
A value within the tolerance above a multiple counts as that multiple, so float noise
does not add a division.
from_divisions
function
from_divisions(grid: symdef.units.Grid, n: int) -> float
Return the value in module units of `n` grid divisions.
keepout_box
function
keepout_box(symbol: symdef.model.Symbol, font: symdef.font.FontMetrics | None = None) -> symdef.geometry.Box
Return the body box united with every slot box: the room the symbol needs kept clear.
`font` measures the body's text as `body_box` does.
leads
function
leads(symbol: symdef.model.Symbol, ports: collections.abc.Iterable[str]) -> symdef.model.Symbol
Return the symbol without the bound leads of every port not in `ports`.
A `Line` whose `port` is None, a `Line` bound to a listed port and every other element stay,
in order. The caller names the wired ports; ids are those the symbol holds, so `1.a` after
`table` or `repeat`.
Raises:
UnknownNameError: A listed id is not a port of the symbol; the key names it.
load_bundle
function
load_bundle(json_path: pathlib.Path) -> symdef.model.Library
Read a resolved bundle (`bundle.json`) into a library.
The library has the bundle's standard for both `standard` and `title`, and no number pattern
(D7). Symbols are checked like a source file, plus the resolved form (`validate_bundle`).
Args:
json_path: The bundle file.
Returns:
The library, its symbols keyed by the bundle's keys.
Raises:
LibraryError: If the file cannot be read, is not JSON or is not a valid bundle. Every
finding is a `schema` finding, its message prefixed with the file name.
load_library
function
load_library(root: pathlib.Path) -> symdef.model.Library
Read `library.toml` and `symbols/*.toml` under `root`, validate, resolve and flatten them.
Args:
root: The data repo's directory.
Returns:
The library, its symbols keyed by reference number.
Raises:
LibraryError: If a file cannot be read or fails any check. `findings` holds every
finding, `library.toml` first and then the symbol files in name order, each message
prefixed with its file name.
measure
function
measure(symbol: symdef.model.Symbol, orientation: symdef.geometry.Orientation, library: symdef.model.Library, texts: collections.abc.Mapping[str, str] | None = None, text_height: float | None = None, *, attach: collections.abc.Mapping[str, symdef.model.Symbol] | None = None) -> symdef.gridmeasure.Measure
Return the symbol turned to `orientation`, measured in divisions of `library.grid`.
The symbol is oriented first. Extents (the body and every slot box) round outward, so a
caller never rounds; ports are positions and must sit on the grid. Text is measured with
`library.font`: the body's own text, and a slot's string when `texts` has one for its id
(at `text_height`). A slot with no string is its reserved box. A symbol in `attach` under a
slot id has its keep-out box placed at the turned slot's point and side, as a slot's reserved
box is, and united with that slot's box, so `slots[id]` and `keepout` hold it. The attached
box is never rotated, as a slot's box is not.
Raises:
InvalidValueError: If `texts` is given without `text_height`, or a port is off the grid.
UnknownNameError: If a key of `texts` or `attach` is not a slot id of the symbol.
measure_font
function
measure_font(regular: bytes, bold: bytes) -> symdef.font.FontMetrics
Measure a regular and a bold TrueType face into font metrics.
The normal advances come from the regular face, the thick ones from the bold face, each for
ASCII, Latin-1 and a few symbols. The cap height is the top of the glyph `H`, the descent the
depth of the glyph `p` and the ascent the OS/2 typographic ascender, all from the regular face.
Args:
regular: The bytes of the regular `.ttf` file.
bold: The bytes of the bold `.ttf` file.
Returns:
The metrics: named by the regular face (name ID 1) and with its typographic family (name ID
16, else ID 1) as `family`, with the largest regular advance as the default advance and no
heights.
Raises:
InvalidValueError: If either argument is not a TrueType font, the faces differ in units
per em, or a face has no glyph `H` or `p`.
nodes_of
function
nodes_of(symbol: symdef.model.Symbol) -> tuple[symdef.model.Node, ...]
Return every node of a symbol: the declared ones, then one per port in no declared node.
Ports named twice, or named by a node but absent from `ports`, are kept as declared; the
linter reports them.
on_grid
function
on_grid(v: float, tol: float = 1e-09, grid: symdef.units.Grid = Grid(module_mm=2.5, divisions_per_module=8, wire_pitch=8, wire_pitch_fine=4)) -> bool
Return whether a value in module units is within `tol` of a division of `grid`.
With no grid it is the default grid, as for `snap`.
orient
function
orient(symbol: symdef.model.Symbol, orientation: symdef.geometry.Orientation) -> symdef.model.Symbol
Return the symbol mirrored first if the orientation is an MR, then turned clockwise.
Ports, anchors and slots move as points and turn as directions; circle and arc centres move
as points and radii stay. Arc angles are normalised into [0, 360): a turn adds its degrees,
and a mirror maps t to 180 - t and swaps start with end, so the arc is still swept clockwise.
Text elements and slot boxes stay upright and unchanged; only their position moves.
Args:
symbol: The symbol in its own orientation.
orientation: One of the 8 orientations.
Returns:
A new symbol; nodes, paths and all non-geometric fields are unchanged.
orient_box
function
orient_box(box: symdef.geometry.Box, orientation: symdef.geometry.Orientation) -> symdef.geometry.Box
Return a box mirrored (if the orientation is an MR) and then turned about the origin.
It is the box of its two corners turned as points, so it matches `body_box` of the oriented
symbol, whose extents turn the same way.
orient_direction
function
orient_direction(direction: symdef.geometry.Direction, orientation: symdef.geometry.Orientation) -> symdef.geometry.Direction
Return a direction (or slot side) transformed as a vector by an orientation.
orient_point
function
orient_point(point: symdef.geometry.Point, orientation: symdef.geometry.Orientation) -> symdef.geometry.Point
Return a point mirrored (if the orientation is an MR) and then turned clockwise.
Adding 0.0 turns -0.0 into 0.0, so the result never contains a negative zero.
pole_pitch
function
pole_pitch(symbol: symdef.model.Symbol) -> float
Return the spacing between poles in module units: the symbol's `pole_pitch`, else 4.
pole_port
function
pole_port(k: int, port_id: str) -> str
Return the id port `port_id` takes in pole `k` (counted from 1) of a repeated symbol.
repeat
function
repeat(symbol: symdef.model.Symbol, n: int) -> symdef.model.Symbol
Return `n` copies of a symbol placed along +x, as an ordinary symbol.
Pole k (from 1) is the symbol translated by `((k - 1) * pitch, 0)`, where the pitch is the
symbol's `pole_pitch`, default 4. Ports, and the paths, nodes and bound leads that name them,
are prefixed `<k>.`; every node is listed explicitly, `potential` kept. Marking slots
(`marking.in` becomes
`marking.<k>.in`) repeat per pole; `tag`, `value` and any other slot come from pole 1 only.
Only pole 1's path keeps `through`. Pole 1's anchors become the result's anchors, and if one
is `link` and `n > 1` a dashed line joins pole 1's `link` to pole n's. `pole_pitch` becomes
`n * pitch`; everything else is carried over.
Args:
symbol: A symbol in base orientation with a through path.
n: The pole count, at least 1.
Returns:
The repeated symbol; with `n = 1` it is the symbol with renamed ports and slots.
Raises:
InvalidValueError: If `n` is below 1, or no path of the symbol has `through`.
slot_box
function
slot_box(slot: symdef.model.Slot, text: str | None = None, height: float | None = None, font: symdef.font.FontMetrics | None = None) -> symdef.geometry.Box
Return the box a slot reserves: it grows from the slot point towards its side.
E and W grow horizontally and are vertically centred; N grows up and S grows down and both
are horizontally centred; C is centred on the point both ways. The box is never rotated; only
the point and side are.
With a `text` the box also holds that string drawn at text height `height` (`slot_text`
places it, `font` measures it, 0.6 em per character with no font): the union of the reserved
box and the string's extent. Without a text it is the reserved box.
Raises:
InvalidValueError: If a text is given without a height.
slot_text
function
slot_text(slot: symdef.model.Slot, text: str, height: float, font: symdef.font.FontMetrics | None) -> symdef.slottext.TextPlacement
Return where a string of text height `height` is drawn in a slot.
The side picks the anchor and the baseline from `SIDE_ALIGN`, or from `TURNED_ALIGN` when the
slot is turned; the shifts are in cap heights, which `font` gives (0.72 em with no font). The
point does not depend on the string, because the anchor does the aligning.
slots_box
function
slots_box(symbol: symdef.model.Symbol) -> symdef.geometry.Box
Return the union of the boxes the slots reserve, without the body.
A symbol without slots has the box (0, 0) to (0, 0).
snap
function
snap(v: float, grid: symdef.units.Grid = Grid(module_mm=2.5, divisions_per_module=8, wire_pitch=8, wire_pitch_fine=4)) -> float
Round a value in module units to the nearest division of `grid`.
With no grid it is the default grid, `GRID_DIVISION` (0.125 M), so a call without one gives
the output it always gave.
stretch
function
stretch(symbol: symdef.model.Symbol, axis: Axis, length: float, offsets: collections.abc.Mapping[str, float] | None = None) -> symdef.model.Symbol
Return the symbol grown along an axis to a body extent of `length`.
The growth, `length` minus the natural extent, is shared among the axis's cuts in proportion
to their weights. A point moves by the shares of the cuts it lies beyond: element points,
ports, anchors and slot corners. A line or polyline segment across a cut gets longer by that
cut's share; a slot box across one grows the same way. `offsets` then places each named port
at its coordinate along the axis, with its bound lead and its `marking.<port>` slot; the port
must stand on an edge parallel to the axis, on the 1 M wiring grid, inside the stretched body.
The result has no stretch on that axis.
Args:
symbol: A symbol in base orientation with a stretch on `axis`.
axis: "x" or "y".
length: The new body extent along the axis, in module units; the natural extent at least.
offsets: Port id to coordinate along the axis, or None.
Returns:
An ordinary symbol; orient it afterwards.
Raises:
InvalidValueError: If the symbol has no stretch on the axis, `length` is below the natural
extent, a circle, arc or text crosses a cut, an offset names no port or a port on
another edge, or an offset lies outside the stretched body or off the grid.
table
function
table(row: symdef.model.Symbol, n: int, axis: Axis, head: symdef.model.Symbol | None = None) -> symdef.model.Symbol
Return `n` rows placed one after another along an axis, as an ordinary symbol.
Row k (from 1) is the row translated by `k - 1` times its body extent along the axis. Ports,
paths, nodes and bound leads are prefixed `<k>.`, as `repeat` does. Every slot of every row is
kept: `marking.<port>` becomes `marking.<k>.<port>`, any other `<id>` becomes `<k>.<id>`. Row
1's anchors become the result's anchors. The head keeps its own ids and comes first; if it has
a stretch on the axis, it is stretched to span all `n` rows. The head is placed as authored,
in the row's frame: author it before the first row on the axis or, with a stretch on the axis,
spanning the rows. A `between` element is drawn in rows 1 to n-1 and left out of row n; a
single row draws none, and the head is unaffected. The result has no stretch and the row's
`pole_pitch`.
Args:
row: A symbol in base orientation.
n: The row count, from 1 to `MAX_REPEAT`.
axis: "x" or "y".
head: A symbol placed once before the rows, or None.
Returns:
The table, carrying the row's name, kind, status, reference and lint allowances.
Raises:
InvalidValueError: If `n` is outside 1 to `MAX_REPEAT`, or the head's stretch cannot span
`n` rows.
text_width
function
text_width(font: symdef.font.FontMetrics | None, text: str, height: float, weight: symdef.geometry.Weight = <Weight.NORMAL: 0.1>) -> float
Return the width of a text in module units when set at `height` (one em).
With a font it is the sum of the advances of the weight's table, in ems, times `height`. With
no font it is 0.6 em per character.
to_divisions
function
to_divisions(grid: symdef.units.Grid, v: float) -> int
Return how many grid divisions a value in module units spans; the value must sit on the grid.
Off-grid values raise, so a drawing never gets a half division by accident.
to_fragment
function
to_fragment(symbol: symdef.model.Symbol, *, tint: str | None = None, muted: str | None = None, texts: collections.abc.Mapping[str, str] | None = None, required_slots: collections.abc.Sequence[str] = ()) -> str
Render a symbol as a placeable SVG fragment: a `<g>` of its plain elements only.
For embedding one placed symbol inside a larger document the caller assembles. The caller
wraps the result in its own `<g transform="...">` to position, orient and scale it; this
function applies none of its own. No title and no annotations. Elements are drawn exactly as
in `to_svg`'s plain mode, in module units. The strings in `texts` follow them (D63).
Args:
symbol: The symbol to render, already oriented and repeated by the caller (via
`orient`/`repeat`), exactly as `to_svg` expects its own `symbol` argument.
tint: Fill colour of the tinted closed polylines, as in `to_svg`.
muted: The colour a muted symbol is drawn in, or None. Muted draws every stroke, every
text and every solid or tint fill in that colour, and every line style as a dash and
a gap each as long as the normal stroke width. An unfilled shape stays unfilled.
texts: The string to draw in each slot, by slot id, or None to draw none. A slot without
a string, or with an empty one, draws nothing. A string is aligned by the slot side
(E start, W end, N and S middle, as the sample texts of `to_svg`), sized to fit the
slot box (at most 1 M), black or in the muted colour, with no class. It is never
wrapped.
required_slots: The slots the symbol must have a string for, shaped as `lint`'s argument
(`marking.<port>` means one per port). Checked only when `texts` is given; an empty
string satisfies it. The default checks nothing.
Returns:
The `<g>...</g>` fragment text, ending with a single newline.
Raises:
UnknownNameError: A key of `texts` is not a slot id of the symbol; the key names it. Checked
before anything is drawn, also for an empty string.
InvalidValueError: The tint or the muted colour is not a hex colour or a colour name, or
`texts` is given and misses a required slot; the message names it and the symbol.
to_fragment_mm
function
to_fragment_mm(symbol: symdef.model.Symbol, *, module_mm: float, weights_mm: collections.abc.Mapping[symdef.geometry.Weight, float], dash_mm: tuple[float, float], dash_dot_mm: tuple[float, float, float, float] | None = None, font_family: str, font_mm: float, cap_ratio: float, tint: str | None = None, muted: str | None = None, texts: collections.abc.Mapping[str, str] | None = None, required_slots: collections.abc.Sequence[str] = ()) -> str
Render a symbol as a `<g>` fragment in millimetres, with no `scale(`.
The one transform is the `rotate(-90)` on the text element of a turned slot's string.
A different output from `to_fragment`, whose contract is module units with the caller
scaling. Here every coordinate and radius is multiplied by `module_mm`, and the stroke widths,
the dash pattern and the font size are the caller's absolute millimetres, so they do not
change with the module. Elements and their order are those of `to_fragment`. A text element
ignores its `height`: it is drawn at `font_mm`, middle-anchored, with its capitals centred on
its position.
Args:
symbol: The symbol to render, already oriented and repeated by the caller.
module_mm: Millimetres per module unit.
weights_mm: Stroke width in mm for each `Weight` the symbol uses.
dash_mm: Dash and gap lengths in mm of a dashed element.
dash_dot_mm: Dash, gap, dot and gap lengths in mm of a dash-dot element; None when the
symbol has none.
font_family: CSS font family of the text, escaped here for the attribute.
font_mm: Font size in mm of every text element.
cap_ratio: Capital height as a fraction of the font size; the baseline sits half of it
below the text position.
tint: Fill colour of the tinted closed polylines: `#rgb`, `#rrggbb` or a colour name.
None draws them unfilled. Checked even when no element is tinted.
muted: The colour a muted symbol is drawn in, or None. As in `to_fragment`, with the dash
and gap of the normal stroke width taken from `weights_mm`; `dash_mm` and
`dash_dot_mm` are then not used.
texts: The string to draw in each slot, by slot id, or None to draw none. A slot without
a string, or with an empty one, draws nothing. Each string follows the elements, in
slot id order, at `font_mm` in `font_family`, aligned by the slot side (E start, W
end, N and S middle; the baseline is half a capital below the slot point for E and W,
on it for N and one capital below it for S). A turned slot (`turn`) reads bottom-up:
N starts at the slot point, S ends there, E and W centre the text on it, and the text
element carries `rotate(-90)` about its baseline point. It is never measured, shrunk
or wrapped.
required_slots: The slots the symbol must have a string for, as in `to_fragment`.
Returns:
The `<g>...</g>` fragment text, ending with a single newline.
Raises:
UnknownNameError: A weight an element uses, or `Weight.NORMAL` when muted, is missing from
`weights_mm`; the key names it. Also a key of `texts` that is not a slot id of the
symbol, checked before anything is drawn, also for an empty string.
InvalidValueError: The tint or the muted colour is not a hex colour or a colour name, a
dash-dot element is drawn and `dash_dot_mm` is None, or `texts` is given and misses a
required slot; the message names it and the symbol.
to_placed_fragment
function
to_placed_fragment(symbol: symdef.model.Symbol, orientation: symdef.geometry.Orientation, at: symdef.gridtypes.GridPoint, library: symdef.model.Library, *, tint: str | None = None, muted: str | None = None, texts: collections.abc.Mapping[str, str] | None = None, required_slots: collections.abc.Sequence[str] = ()) -> str
Return the symbol turned to `orientation` and drawn with its origin at `at`.
It is `to_fragment` of the oriented symbol inside one `<g transform="translate(X Y)">`, where
X and Y are `at` turned into module units by `library.grid`. The options are those of
`to_fragment`. The float forms (`to_fragment`, `to_fragment_mm`, `to_svg`) are unchanged.
Raises:
UnknownNameError: A key of `texts` is not a slot id of the symbol.
InvalidValueError: As `to_fragment`.
to_svg
function
to_svg(symbol: symdef.model.Symbol, *, module_mm: float = 2.5, annotate: bool = False, texts: collections.abc.Mapping[str, str] | None = None, tint: str | None = None) -> str
Render a symbol as an SVG document.
The viewBox is in module units, the extent grown by a margin of 1 on every side; width and
height are the viewBox size times module_mm, in mm. Plain, the extent is the body box; with
annotate it is the keep-out box, every port label box, every anchor and its label, every slot
label and the start of every lane, so no annotation is clipped. The elements are drawn first,
then the annotations, then the sample texts. The output is deterministic.
Args:
symbol: The symbol to render.
module_mm: Millimetres per module unit.
annotate: Draw the grid, the body and keep-out boxes, the slot boxes, the anchors and the
ports with their ids and wire lanes.
texts: Sample text per slot id. Each is drawn upright in its slot box (class
`sample-text`) in the largest font of at most 1 M that fits the box; an id that is
not a slot of the symbol is ignored. Drawn in both modes.
tint: Fill colour of the tinted closed polylines: `#rgb`, `#rrggbb` or a colour name.
None draws them unfilled. Checked even when no element is tinted.
Returns:
The SVG text, ending with a single newline.
Raises:
InvalidValueError: The tint is not a hex colour or a colour name.
translate
function
translate(symbol: symdef.model.Symbol, dx: float, dy: float) -> symdef.model.Symbol
Return the symbol shifted by (dx, dy).
Args:
symbol: The symbol to shift.
dx: Horizontal shift, positive to the right.
dy: Vertical shift, positive downwards.
Returns:
A new symbol; arc angles, directions and slot boxes are unchanged.
wire
function
wire(library: symdef.model.Library, style_id: str, points: collections.abc.Sequence[symdef.geometry.Point] | collections.abc.Sequence[tuple[float, float]]) -> symdef.model.Symbol
Return an element symbol that draws one open polyline through `points` in a wire style.
Args:
library: The library whose `wires` name the style.
style_id: The id of one of its wire styles.
points: The corners in module units, as `Point`s or (x, y) pairs.
Returns:
An unverified element symbol with one open polyline and no ports, slots, nodes or paths.
Raises:
UnknownNameError: If the library has no wire style with this id.
InvalidValueError: If fewer than two points are given.