Features
47+ constraint types, 10 entity types, multi-start solving, priority weights, verification, and more.
Features
Entity Types (10)
| Entity | Parameters | Description |
|---|---|---|
Point | x, y | 2D point |
Line | x1, y1, x2, y2 | Line segment |
Circle | cx, cy, r | Full circle |
Arc | cx, cy, r, start, end | Circular arc |
Ellipse | cx, cy, a, b, angle | Full ellipse |
ArcOfEllipse | cx, cy, a, b, angle, start, end | Elliptical arc |
Hyperbola | cx, cy, a, b, angle | Hyperbola |
Parabola | vertex_x, vertex_y, focal, angle | Parabola |
ArcOfHyperbola | Hyperbola + arc bounds | Hyperbolic arc |
ArcOfParabola | Parabola + arc bounds | Parabolic 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)
- Unperturbed — solve from the initial guess directly
- Branch-aware — perturb toward detected alternative branches
- Geometric sampling — perturb along eigenvectors of
JᵀJ - 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:
| Priority | Weight | Use Case |
|---|---|---|
Disabled | 0 | Temporarily ignored constraints |
Soft | 0.1 | Preferences, not hard requirements |
Normal | 1.0 | Standard constraints (default) |
Important | 10.0 | Critical dimensions |
Critical | 100.0 | Must-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:
- Residual check —
‖r(x*)‖ < tolfor all constraints - Geometry validation — radii > 0, angles in valid ranges, no degenerate entities
- 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 additionsys.redo()— re-apply a reverted action- Implemented as a command stack with parameter snapshots
Performance Optimizations
| Optimization | Description |
|---|---|
| Dirty flag | Skips Jacobian recomputation when parameters haven't changed |
| Cached Jacobian structure | CSC sparsity pattern cached between iterations |
| Stagnation detection | Early termination when residual stops improving |
| Buffered residuals | Pre-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.