/**
 * Card-measurement centroid solver — the inverse of the resolver's placement.
 *
 * Reference cards locate a terrain area by dimension lines: "this feature of the
 * area is D inches from a board edge". The feature referenced varies per card
 * and per piece, which is exactly why a single canonical anchor (the centroid)
 * is hard to read off a card directly. This solver lets a user transcribe the
 * card verbatim — pick the template, set the orientation shown, then enter one
 * horizontal and one vertical dimension line against whatever feature the card
 * happens to draw — and back-solves the centroid `position` the schema stores.
 *
 * Because the centroid is rotation- and mirror-invariant, orientation is fixed
 * first; each dimension line then pins one axis of the centroid in closed form.
 */
import { type BoardEdge, type FeatureRef, type Footprint, type Mirror, type Vec2 } from "./resolve.js";
export type { BoardEdge, FeatureRef } from "./resolve.js";
/** One card dimension line: `distance` inches from `edge` to `feature`. */
export interface DimensionLine {
    edge: BoardEdge;
    distance: number;
    feature: FeatureRef;
}
export interface SolveInput {
    footprint: Footprint;
    rotation: number;
    mirror: Mirror;
    /** Board extents in inches (40kdc standard is 60 × 44). */
    board: {
        width: number;
        height: number;
    };
    /** Two perpendicular dimension lines: exactly one must pin x, one must pin y. */
    lines: [DimensionLine, DimensionLine];
}
export declare class TerrainSolveError extends Error {
}
/**
 * Back-solve the centroid `position` from a template, its orientation, and two
 * perpendicular card dimension lines. Closed form — one x-line and one y-line
 * pin the two unknowns directly.
 */
export declare function solveCentroid(input: SolveInput): Vec2;
/**
 * One triangulation measurement: `distance` inches from board `edge` to a
 * specific footprint vertex (corner). Faces are intentionally excluded — an
 * arbitrarily-rotated piece has no axis-aligned face to measure to.
 */
export interface TriangulationLine {
    edge: BoardEdge;
    distance: number;
    vertex: number;
}
export interface TriangulateInput {
    footprint: Footprint;
    mirror: Mirror;
    board: {
        width: number;
        height: number;
    };
    /**
     * Three corner measurements. At least two must share an axis (left/right or
     * top/bottom) to fix the angle, and at least one must pin the other axis.
     */
    lines: [TriangulationLine, TriangulationLine, TriangulationLine];
    /** Current rotation in degrees, used to choose between the two angle roots. */
    rotationHint?: number;
}
/**
 * Back-solve a piece's centroid AND rotation from three card measurements to
 * specific footprint corners — the inverse needed for pieces at non-90° angles,
 * where the card pins three corner-to-edge distances rather than one per axis.
 *
 * Closed form: with the (unknown) rotation θ, each corner `v` resolves to
 * `centroid + R(θ)·v`. Subtracting two same-axis measurements cancels the
 * centroid and leaves `A·cosθ + B·sinθ = C`, solved as `θ = atan2(B,A) ±
 * acos(C/√(A²+B²))`; the root nearest `rotationHint` is chosen. One measurement
 * on each axis then pins the centroid.
 */
export declare function solveCentroidTriangulated(input: TriangulateInput): {
    x: number;
    y: number;
    rotation: number;
};
/**
 * One card dimension line in an attachment solve: `distance` inches from board
 * `edge` to the piece's lock vertex. No feature ref — both of a piece's lines
 * reach the same locked vertex (the card pattern this solver exists for).
 */
export interface AttachLine {
    edge: BoardEdge;
    distance: number;
}
/**
 * One piece of a two-body attachment solve. The card pins exactly ONE vertex
 * (the keystone anchor) with two perpendicular dimension lines; the piece is
 * otherwise free to rotate about that point. The `attach` feature is what
 * connects it to the other piece and removes that rotational freedom.
 */
export interface AttachPiece {
    footprint: Footprint;
    mirror: Mirror;
    /** The vertex pinned by `lines` — the piece's keystone anchor vertex. */
    lockVertex: number;
    /** Two perpendicular card lines pinning the lock vertex: one must pin x, one y. */
    lines: [AttachLine, AttachLine];
    /**
     * The attached feature: a specific vertex, or the footprint edge running
     * from vertex `index` to vertex `index + 1` (wrapping).
     */
    attach: {
        kind: "vertex" | "edge";
        index: number;
    };
    /** Current rotation in degrees, used to pick among the candidate roots. */
    rotationHint?: number;
}
export interface AttachInput {
    /** Board extents in inches (40kdc standard is 60 × 44). */
    board: {
        width: number;
        height: number;
    };
    /** The piece being placed. */
    a: AttachPiece;
    /** The piece it attaches to. */
    b: AttachPiece;
}
/**
 * Back-solve the centroid AND rotation of TWO pieces at once from the cluster
 * card pattern: each piece's card prints exactly two dimension lines, both to
 * one vertex — pinning that vertex's board position but not the rotation. The
 * rotations come from the pieces' attachment to each other: matched vertices
 * coincide (the pair pivots), or matched edges lie on one line (the contact
 * slides — each piece's position along the line is fixed by its lock vertex).
 *
 * Closed form: with each lock vertex pinned, one rotation per piece is the
 * only unknown. Vertex mode intersects the two circles the attach vertices
 * sweep; edge mode finds the common line via the rotation-invariant signed
 * offset of each lock vertex from its own edge. Both yield a small candidate
 * set; the pair nearest the pieces' current rotations is chosen — rough both
 * pieces in first.
 */
export declare function solveCentroidAttached(input: AttachInput): {
    a: {
        x: number;
        y: number;
        rotation: number;
    };
    b: {
        x: number;
        y: number;
        rotation: number;
    };
};
//# sourceMappingURL=solve.d.ts.map