//! Constructive seed for the solver.
//!
//! Before Levenberg–Marquardt runs, every point the constraints pin down relative to the given
//! points is placed exactly (Owen 1991, §3 and §5; Fudos and Hoffmann 1997), in two
//! interleaved steps repeated until neither places anything:
//!
//! - **propagation**: a point with two loci anchored on already placed points goes to their
//! intersection;
//! - **decomposition** ([`crate::decompose`]): points no point-by-point order reaches but that
//! are rigid relative to the placed ones (Owen's articulation-pair reduction) are placed by
//! cluster merging, with the placed points as the ground.
//!
//! Then a rigid cluster that is free or pinned at a single placed point (nothing decides its
//! pose, and LM alone may land it mirrored) is placed by its reference pose
//! ([`Decomposition::floats`]). That is a guess at free motion ([`Placement::Float`]): the
//! solver starts from it, nothing is built on it.
//!
//! Of two mirror-image intersections, the one keeping the orientation the points had before
//! the solve is kept, so a dimension edit keeps each triangle's orientation, each arc on its
//! side of its tangent lines and each line's direction instead of letting the iteration fall
//! into a mirrored solution.
//!
//! The seed gives the iteration its start. Constructed values the constraints pin down one
//! after another, and whose constraints hold there, stay constants while LM solves the rest
//! (`solver::pinned`); every constraint is still verified, and the rank analysis of the solved
//! Jacobian still decides the degrees of freedom. A point with only one locus on placed points keeps its own position (projecting
//! it onto that locus would freeze a point that still has a degree of freedom). What neither
//! step places (triconnected remainders, under-constrained freedom, constraints read by
//! neither) is left to LM.
//!
//! What the constraints say about a point, and where two of them put it, is read by
//! [`crate::loci`] (the same reading drives the decomposition): coincident points; circles
//! (distances, line lengths, arc radii, points on circles of known radius, tangent circles);
//! rows and columns (horizontal and vertical lines and points, and offsets from them on the
//! side the point was on); lines through placed points along a known direction (a point on a
//! line, a line at a known angle, parallel or perpendicular to a placed line); lines at a
//! distance from a placed line (a point at a distance, a tangent circle's centre), on the side
//! the point was on; the radius to a touch point, normal to the line; midpoints and mirrored
//! points. A circle's radius set by its dimensions is seeded too.
use std::collections::{BTreeMap, BTreeSet, VecDeque};
use solidcraft_geom::Vec2;
use crate::decompose::{Budget, Decomposition, enqueue};
use crate::loci::{MAX_LOCI, Reading, Rel, View, place, radii, read};
use crate::model::{Sketch, in_range};
/// Rounds of decomposition then propagation per seed. Each round after the first must follow a
/// propagation that placed something, so on real sketches the loop ends after a few; this
/// bounds a hostile chain that alternates.
const MAX_ROUNDS: usize = 16;
/// Start positions for the solver: `pos[i]` is the position of point `i` when it is given or
/// constructed, `placed_by[i]` how it was placed; `radius[k]` the radius of circle or arc `k`
/// when its dimensions set it.
#[derive(Clone, Debug, PartialEq)]
pub(crate) struct Seed {
pub pos: Vec