spacr.qt.screens.align

Align & Stitch — see the layout, spot what did not register, then write.

Stitching is one of the few operations where the failure is invisible in the output. A tile that did not register is placed at its nominal stage position; the result still looks like a mosaic, still has the right dimensions, and is still wrong by however far the stage was off. If the first time anyone finds out is when a downstream hit fails to reproduce, the tool has failed.

So this screen puts the plan before the write:

  • pick a folder of tiles, press Plan — nothing is written, no canvas is allocated, and only tile headers plus overlap strips are read;

  • the layout is drawn tile by tile, coloured by registration confidence, with anything that fell back to the stage position drawn in the warning colour and hatched. Those tiles are countable at a glance;

  • the estimated canvas size and the RAM the write would use are stated before the button that writes 700 MB is enabled;

  • Write stack then composites incrementally, and optionally records the coordinates into measurements.db.

Every long operation runs on a worker thread and reports back through a bound method, never a closure — see AlignScreen._run_job(). Errors land in the inline status label; a QMessageBox here would hang a headless run, so there are none.

Classes

AlignScreen

The Align & Stitch tool.

TileLayoutWidget

The stitch layout: one rectangle per tile, coloured by confidence.

Functions

confidence_colour(→ PySide6.QtGui.QColor)

Colour for one tile in the layout view.

Module Contents

class spacr.qt.screens.align.AlignScreen(parent=None, threaded: bool = True)[source]

Bases: PySide6.QtWidgets.QWidget

The Align & Stitch tool.

Parameters:
  • parent – parent widget.

  • threaded – run the scan/plan/write on a worker thread (the default). Tests pass False for deterministic, synchronous behaviour — both paths emit the same signals.

Variables:

last_error – text of the most recent failure, "" when the last operation succeeded. Errors are only reported here and in the inline status label, never in a modal dialog.

Build the Align screen with nothing planned or written yet.

active_jobs() → int[source]

How many worker threads are still winding down.

apply_settings(settings: Dict[str, Any]) → None[source]

Load a settings dict back into the controls.

Parameters:

settings – partial or full Align settings; missing keys are filled from spacr.align.default_settings() before the controls are set.

build_plan() → bool[source]

Scan the source and solve the layout. Writes nothing.

Returns:

True when the job was started (or, unthreaded, when it succeeded).

is_busy() → bool[source]

True while a job is in flight.

plan()[source]

The current spacr.align.AlignPlan, or None.

report_text() → str[source]

The rendered plan (test/introspection helper).

result()[source]

The last spacr.align.AlignResult, or None.

settings() → Dict[str, Any][source]

Return the controls as a spacr.align.default_settings() dict.

Kept public so the Batch Runner and the Queue can snapshot this screen the way they snapshot every other one.

status_text() → str[source]

Current inline status message (test/introspection helper).

tile_info_text() → str[source]

The per-tile readout line (test/introspection helper).

write_stack() → bool[source]

Composite the current plan to disk, and optionally to the database.

class spacr.qt.screens.align.TileLayoutWidget(parent=None)[source]

Bases: PySide6.QtWidgets.QWidget

The stitch layout: one rectangle per tile, coloured by confidence.

Draws the plan, not the pixels — it never opens an image, so showing the layout of a 700 MB stitch costs nothing. Hovering is not wired; the per-tile detail lives in the report pane beside it, where it can be read and copied.

Parameters:

parent – parent widget.

Build an empty layout view, sized to expand with its pane.

mousePressEvent(event) → None[source]

Emit tile_clicked for whatever was under the cursor.

Parameters:

event – the mouse press event; only its position is read. A press outside every tile emits -1.

paintEvent(event) → None[source]

Draw the tile rectangles, or the empty-state hint.

Parameters:

event – the paint event; not read, the whole widget is redrawn.

plan()[source]

The plan currently drawn.

set_plan(plan) → None[source]

Show plan (an spacr.align.AlignPlan), or None.

Parameters:

plan – the plan whose placements are drawn; None shows the empty-state hint.

tile_rects() → List[Tuple[int, QRectF]][source]

Return (tile_index, rect) in widget coordinates.

Public so a test can assert the layout without screen-scraping pixels.

spacr.qt.screens.align.confidence_colour(confidence: float, method: str) → PySide6.QtGui.QColor[source]

Colour for one tile in the layout view.

A tile placed by stage position alone is drawn in the warning colour whatever its (zero) confidence, because “we guessed” is a different kind of fact from “we matched, weakly”. Registered tiles ramp from the muted surface at confidence 0.3 to full accent at 1.0, so a weak match reads as pale rather than as a different category.

Parameters:
  • confidence – registration confidence from 0 to 1; values outside 0.3-1.0 are clamped to the ends of the ramp.

  • method – placement method, one of the spacr.align.METHOD_* values; "nominal" gives the warning colour and "unreadable" the error colour regardless of confidence.

Nested helpers

AlignScreen._run_job._job(payload: Dict[str, Any]) → None

Call the wrapped function, stashing its result in the payload.

The payload is how a value crosses back from the worker: a return would be swallowed by the runner.

spacr/qt/screens/align.py:753

AlignScreen.build_plan._work()

Scan the tiles and build the stitch plan. Off the GUI thread.

spacr/qt/screens/align.py:616

AlignScreen.write_stack._work()

Write the stitched stack. Off the GUI thread.

spacr/qt/screens/align.py:692