spacr.ops_solve

Absolute tile positions from the pairwise displacements one well produced.

THE THIRD VERB. spacr.ops_layout says which tiles touch, spacr.ops_register says how far apart a touching pair is, and this says where every tile ends up. Kept separate from both because ops_layout is pure geometry that imports only math and should stay importable anywhere, and ops_register’s whole subject is two tiles and one shift.

Functions

solve_placements(→ Dict[int, Tuple[float, float]])

Absolute tile positions from the pairwise displacements.

Module Contents

spacr.ops_solve.solve_placements(edges: Dict[Tuple[int, int], Tuple[float, float]], sites: List[int]) → Dict[int, Tuple[float, float]][source]

Absolute tile positions from the pairwise displacements.

A LEAST-SQUARES SOLVE, NOT A WALK. Chaining placements from a seed gives every tile the accumulated error of whatever path reached it, and on a round well the paths are long; solving all the edges at once spreads the residual instead and gives one answer no matter which tile is called the origin.

The origin is pinned to the lowest-numbered site of each connected component, so a well that registers in two pieces still returns both rather than failing – the caller can see the components in the result and say so.

Parameters:
  • edges – (a, b) -> (dy, dx), b’s position minus a’s.

  • sites – every site to place, including any with no edge.

Returns:

site -> (y, x) in pixels, one component pinned at the origin and the others pinned at their own lowest site.

Nested helpers

solve_placements.find(node: int) → int

The representative of node’s component, path-compressed.

Parameters:

node – a tile index.

Returns:

the index that stands for its connected component.

Halving as it walks – parent[node] = parent[parent[node]] – so a long chain costs its length once rather than on every later lookup. The components are what decide where the pins go, and a component that is found twice under two names puts two pins in one place and leaves another with none.

spacr/ops_solve.py:59