GeomSolver Docs

Features

47+ constraint types, 10 entity types, multi-start solving, priority weights, verification, and more.

Features

Entity Types (10)

EntityParametersDescription
Pointx, y2D point
Linex1, y1, x2, y2Line segment
Circlecx, cy, rFull circle
Arccx, cy, r, start, endCircular arc
Ellipsecx, cy, a, b, angleFull ellipse
ArcOfEllipsecx, cy, a, b, angle, start, endElliptical arc
Hyperbolacx, cy, a, b, angleHyperbola
Parabolavertex_x, vertex_y, focal, angleParabola
ArcOfHyperbolaHyperbola + arc boundsHyperbolic arc
ArcOfParabolaParabola + arc boundsParabolic arc

Constraint Types (47+)

Point Constraints

Distance, HorizontalDistance, VerticalDistance, PointOnLine, PointOnCircle, PointOnEllipse, Midpoint, Coincident, SymmetricHorizontal, SymmetricVertical, SymmetricPoint

Line Constraints

Horizontal, Vertical, Perpendicular, Parallel, Angle, Colinear, EqualLength, LengthRatio

Circle/Arc Constraints

TangentLineCircle, TangentCircleCircle, TangentArcCircle, Radius, Diameter, EqualRadius, Concentric, ArcAngle, ArcLength

Ellipse Constraints

TangentLineEllipse, TangentEllipseEllipse, EqualMinorAxes, EqualMajorAxes, EllipseAngle

Hyperbola/Parabola Constraints

TangentLineHyperbola, PointOnHyperbola, TangentLineParabola, PointOnParabola

General Constraints

FixPoint, FixLine, FixCircle, FixAngle, FixRadius, InternalAlignment

Multi-Start Solving

The solver can run multiple solves from different starting points to find the global minimum:

Basic Multi-Start

Random perturbation restarts: solve from x₀, then from x₀ + ε₁, x₀ + ε₂, etc. The best solution (lowest residual) is returned.

Intelligent Multi-Start (4 Phases)

  1. Unperturbed — solve from the initial guess directly
  2. Branch-aware — perturb toward detected alternative branches
  3. Geometric sampling — perturb along eigenvectors of JᵀJ
  4. Adaptive random — increasing perturbation magnitude with decreasing success

Each phase runs up to N attempts before moving to the next. The total budget is configurable (default: 20 attempts).

Branch Detection and Exploration

Some constraints have multiple solutions (branches). For example, a circle-line tangent can have the line on either side of the circle:

detect_branch_ambiguity() → Vec<Branch>
generate_branch_perturbations() → Vec<Vec<f64>>
solve_with_branch_detection() → Vec<SolveResult>

The solver detects ambiguities, generates perturbations toward each branch, and returns all found solutions.

Priority-Based Constraint Weights

Constraints have five priority levels that control their weight in the least-squares objective:

PriorityWeightUse Case
Disabled0Temporarily ignored constraints
Soft0.1Preferences, not hard requirements
Normal1.0Standard constraints (default)
Important10.0Critical dimensions
Critical100.0Must-satisfy constraints

Weight Schedules

  • Fixed — constant weight throughout the solve
  • Graduated — weight increases from soft to target over iterations
  • PriorityEscalation — soft constraints escalate to normal after initial convergence

Solution Verification (P5.2)

After solving, the verification module checks:

  1. Residual check‖r(x*)‖ < tol for all constraints
  2. Geometry validation — radii > 0, angles in valid ranges, no degenerate entities
  3. Wrong-branch detection — angular constraints on the expected branch
let result = sys.solve();
let verification = verify_solution(&sys);
assert!(verification.all_satisfied());

Cross-Validation Harness

The cross-validation module runs the same problem with different solver algorithms and compares results:

let results = cross_validate(&mut sys);
// Returns: { lm: Ok(sol), dogleg: Ok(sol), bfgs: Ok(sol) }

Discrepancies between algorithms indicate potential numerical issues.

Undo/Redo

The undo.rs module provides full undo/redo support for interactive CAD:

  • sys.undo() — revert the last constraint or entity addition
  • sys.redo() — re-apply a reverted action
  • Implemented as a command stack with parameter snapshots

Performance Optimizations

OptimizationDescription
Dirty flagSkips Jacobian recomputation when parameters haven't changed
Cached Jacobian structureCSC sparsity pattern cached between iterations
Stagnation detectionEarly termination when residual stops improving
Buffered residualsPre-allocated residual vector avoids per-iteration allocation

Tracing and Observability

Enable tracing to inspect the solve process:

sys.set_tracing(true);
let result = sys.solve();
for event in result.trace {
    println!("{:?}: ‖r‖ = {:.6}", event.iteration, event.residual_norm);
}

Tracing records iteration count, residual norm, step size, algorithm used, and convergence reason at each iteration.