Drawing and vertex editing
The editor’s drawing tools add geometry to the top cell, and the vertex-edit tool
reshapes a shape already there. As with the rest of the app, the interesting logic is
window-free and lives in reticle-app’s draw module, unit-tested without a GPU; the
egui layer only turns pixels into world points, calls in, and paints the live
preview.
Every one of these actions goes through the undo history, so drawing a shape or moving a vertex can be undone and redone like any other edit.
Tools
These tools sit on the toolbar next to Select, Pan, Measure, and Cross-section. They
are also in the command palette under Tool:.
- Rect draws an axis-aligned rectangle by dragging from one corner to the opposite one.
- Polygon draws a closed polygon by clicking to place each vertex.
- Path draws a wire: a polyline with a width and an end-cap style.
- Bus draws several parallel wires at once: click a centerline the way the path tool does, and finishing commits N wires on a fixed pitch (see Buses).
- Vertices edits the vertices of the selected shape.
Switching to any non-drawing tool discards a half-drawn shape so nothing leaks between tools. The path width and end cap you pick survive the switch.
Rectangle constraints
A plain drag spans the two corners. Two modifiers refine it, and they combine:
- Shift constrains the rectangle to a square, growing the shorter side to match the longer one while keeping the far corner in the direction you dragged.
- Alt treats the drag’s start point as the rectangle’s center rather than a corner, so the box grows symmetrically. Held together with shift, a centered square uses the larger half-extent on both axes.
Ctrl and Cmd used to be a second from-center chord and no longer are: they are the
app-wide snap-bypass modifier, and the rectangle tool now honours it like every other
placement site (see Snapping). The from-center gesture itself is
unchanged; only the second chord that reached it is gone. Check:
cargo nextest run -p reticle-app -E 'binary(rect_snap)'.
The start and end points go through the same snap seam every other placement site uses, so the committed rectangle lands wherever the status bar and the snap indicator said the cursor was.
Placing polygons and paths
Both tools accumulate vertices click by click, drawing a live preview of the edges placed so far plus a faint segment out to the cursor. An immediate repeat of the last point is ignored, so a closing double-click never leaves a zero-length edge.
- A double-click, or Enter, finishes the shape. A polygon needs at least three distinct vertices; a path needs at least two points. A finish gesture with too few points is declined rather than committing a degenerate shape.
- Escape cancels the shape in progress.
A path carries a width in database units and one of three end caps, both set on the toolbar while the path tool is active:
- Flat ends the wire exactly at its endpoints.
- Square extends each end by half the width.
- Round rounds each end by a half-width radius.
Buses
The Bus tool places several parallel wires in one gesture. Its centerline is placed exactly the way the path tool’s polyline is (it uses the same builder, so Escape cancels a half-drawn bus and the angle constraint anchors on it), and the toolbar carries two extra settings while the tool is active: how many wires, and the centerline-to-centerline pitch in database units. The wires take their width and end cap from the path settings beside them.
Finishing (double-click, or Enter) commits every wire as one undo step, so a bus undoes as a bus rather than one wire at a time. The wires are centered on the centerline: an odd count puts the middle wire on it, an even count runs it between the two middle wires, and consecutive wires are exactly one pitch apart either way. A polyline centerline is offset with mitered corners, so every wire keeps the centerline’s vertex structure.
If the document’s technology declares a spacing rule for the layer being drawn on, the status line after a commit says so when the chosen pitch is below the smallest spacing-clean pitch for that layer, which is the wire width plus that spacing minimum. That is a report, not a correction: the tool places the pitch you asked for.
What the bus tool does not do: it does not route. There is no obstacle avoidance, no auto-jogging around existing geometry, no per-wire length matching, and no connection to a netlist. It is a constant-pitch parallel offset of one centerline. At a corner sharper than the miter guard allows, the inner wires clip rather than fan out.
Check: cargo nextest run -p reticle-app -E 'binary(bus)' drives the real tool and
asserts the pitch, and runs the committed SKY130 rule subset over the geometry the tool
produced at a compliant pitch (zero spacing violations) and at a tightened one (an
m1.2 spacing violation naming two of the wires).
Editing vertices
Select a single shape you drew, then switch to the Vertices tool. It ticks every vertex of the shape so you can see what is grabbable. Only shapes owned directly by the top cell are editable; geometry that comes from a placed instance is not.
- Drag a vertex to move it. The new position goes through the same snap seam every other placement site uses (see Snapping), so a vertex can be dropped exactly onto existing geometry or a guide.
- Click on an edge to insert a vertex there. The new vertex lands on the point of the segment nearest the click.
- Alt-click (or ctrl-click) a vertex to delete it. A polygon keeps at least three vertices and a path at least two, so a deletion that would collapse the shape is refused.
A rectangle promotes to a polygon the moment one of its corners is edited off the axis, since a rectangle can no longer describe the result. A path keeps its width and end cap through an edit. Each move, insert, or delete is one undoable step, applied as a remove-then-add of the reshaped shape.
Snapping
Every placed point and moved vertex goes through one shared snap seam before it is committed, so drawn geometry lands exactly where the status bar and the on-canvas snap indicator said the cursor was. That seam tries nearby existing geometry and user guides first, then falls back to the grid; turning grid snapping off (the Snap toggle) places points at the exact cursor position when nothing else catches them. Holding ctrl or cmd drops snapping entirely for as long as it is held.
All six placement sites use it: the polygon, path, and bus centerlines, the vertex-move
commit, and both the anchor and the cursor of a rectangle drag. The rectangle was the
last one added; before that it read the grid directly, so object snap, guide snap and
the bypass modifier moved the indicator without moving the committed corner. Check:
cargo nextest run -p reticle-app -E 'binary(rect_snap) or binary(allangle)'.
Testing
The module’s geometry is unit-tested in isolation: the rectangle-from-drag math for
each modifier combination, the polygon and path builders’ finish thresholds and
deduplication, the bus offset run and its mitered polyline offset, vertex hit-testing
by exact squared distance, edge projection for insertion, and the insert, delete, and
move operations against their vertex-count floors. Because this logic is pure, the
tests need no window and run with the rest of the reticle-app suite.
On top of that, three GPU-free integration suites drive the real editor through
egui_kittest and assert against the committed document rather than against the
geometry helpers: binary(allangle) for the polygon tool’s placement and the angle
constraint, binary(rect_snap) for the rectangle tool’s snap seam and its modifiers,
and binary(bus) for the bus tool’s pitch and its DRC spacing behaviour.