* Sketch: the first dimension scales a sketch drawn by eye (#1365)
Lines drawn by eye have no size of their own until a dimension gives them one, but the first
dimension kept every other drawn length and distorted the sketch to fit (a free construction
line through the origin turned instead of the shape moving). The dimension tool now scales
the whole sketch about its origin to the first length dimension, as long as nothing in the
sketch fixes a size yet: no other driving length dimension, nothing fixed, projected or
patterned. Every geometric constraint and angle holds on the scaled sketch. Later
dimensions size what they measure as before; sketch.dimension does this only with
scale_sketch: true, so scripts are unchanged.
Fixes#1365
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Scenario s01: dimension the box's height too, now that the first dimension scales the sketch
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A dimension to a line, or between two parallel lines, drew its extension lines from the
measured end point and its foot on the other line, so they ran the whole length of the
lines to wherever that end happened to be. They now start from the nearest point of each
line to the dimension line, and disappear where the dimension line already crosses it.
Fixes#1361
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A clover of same-size rectangles drawn around a shared corner was refused as over-constrained.
Constraints that remove no degree of freedom but still hold (zero residual) are now kept and shown dimmed as redundant. Conflicting ones are still refused. A redundant driving dimension is refused with "already determined by ...". Typed sizes become driven (reference) dimensions. Drawing no longer adds Horizontal/Vertical to a side that is already implied through two coincident corners. The solver reports redundant constraints using a Jacobian row-dependence test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
As soon as a pick settles the dimension (one line, circle or arc, or the second point or line of a distance or angle), its value box takes the keyboard with the measured value selected. The text follows the cursor while typing and Enter places it there (or in its default place), as one undo step. A click before typing pins the text and keeps the box focused, a click on another entity makes a distance or angle, Tab hands back to placing first, Esc cancels. Letters go into the box, not to tool shortcuts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sketch Dimension refused a dimension the sketch couldn't take, with
"that dimension would over-constrain the sketch; add it as a driven
(reference) dimension with driven: true", which the tool gave no way to
do. It now places it as a driven dimension instead: while placing, the
preview shows it in parentheses in the driven colour, and the click adds
it at once (it has no parameter and no value to edit), with a status line
saying why. Other refusals, such as an unsupported pick, are reported as
before, since the driven dimension is refused too.
Refs #320
Co-authored-by: Vitali M. <6042958+vitalibr@users.noreply.github.com>
* feat(sketch): constructive solving ahead of the numeric solver
Part 1 of splitting #251: the sketch crate only. A graph-constructive front
end (Owen 1991; Fudos & Hoffmann 1997) places what it can by ruler-and-compass
loci and cluster decomposition, Levenberg-Marquardt finishes and verifies the
rest, and the rank analysis stays authoritative for degrees of freedom. Solves
can follow a reference (the previous solution), so edits and drags keep their
branch instead of flipping.
New API: solve_with (hold, reference, analysis, budget) and
solve_after_value_edit; solve and solve_holding keep their signatures as
wrappers, so no caller changes here.
When the seed moves an arc's centre, the arc's unconstructed ends start carried
along (the arc translates) instead of left behind for LM to turn; found by the
reference test 20-slot-constrained.
Refs #203
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TWc1smHYwTSVrVc8SNvS44
* feat(doc): keep a sketch's solved state across value edits
Part 2 of splitting #251 (builds on part 1, the sketch crate):
- Sketch edits solve for the document's values continuing from the stored
solved state (Document::solve_sketch), so a dimension edit keeps the
sketch's branch instead of re-solving from scratch.
- A value edit (parameters, a configuration, the units) that would make a
sketch that solved before fail or turn over is refused with the
conflicting constraints named; otherwise the solved sketches are written
back into the document (Model::adopt_solved_sketches), which changes what
saved designs store.
- Later features are keyed by a sketch's solved geometry (to a 1e-6 mm
quantum), so setting a value back reuses their earlier results.
- Solved sketches in a model state are shared (Arc) between states.
Refs #203
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TWc1smHYwTSVrVc8SNvS44
* feat(sketch): live drag that keeps its solution, ended by sketch.drag_end
Part 3 of splitting #251 (builds on part 2):
- sketch.drag follows a long move in short held steps, so the geometry keeps
its branch, and reports how far it got (reached, at).
- live: true runs one frame of an interactive drag: the sketch is solved
once and shown, later features keep their last result (marked stale)
until sketch.drag_end or any command that reads the model evaluates it
(CommandSpec::live, reads_model, doc_only).
- sketch.drag_end adds the constraint the drag let go on and evaluates the
model once.
- Undo and redo evaluate a new document once (execute does) instead of
twice.
- The viewport drives drags through live frames and drag_end; dimension
text drags start only off sketch geometry.
Refs #203
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TWc1smHYwTSVrVc8SNvS44
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Honor design units in sketch dimensions and measurements
* fix: apply document units to specialized length controls
* Accept explicit units in length fields; document design-unit dimension values
Length fields in a design-unit control now evaluate what is typed as a
length expression: a bare number stays in the design's units, while an
explicit unit ("10 mm", "0.5 in", "1 in + 5 mm") is converted.
Document that a bare numeric sketch.dimension value from scripts, the
control channel or MCP is read in the design's units.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT
---------
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Use egui pointer ownership for viewport navigation and picking, view-cube
interaction, and sketch-dimension hover. Cover scrolling, model selection,
and cube interaction under floating dialogs, including after they close.
Shield constraint glyph and move-gizmo highlights from overlapping UI too.
Clear strict Clippy warnings and use the same saved path in the recent-file
scenario on Windows and Unix.
Fixes#87
The old ids live only in crates/engine/src/legacy_ids.rs (the legacy migration table): find_command maps them, so old scripts, recipes and control calls keep working, and saved shortcuts, recent and pinned commands are migrated on load (designs store no command ids). Parity maps the observed catalog ids to ours through xtask/data/fusion-ids.tsv. The agent rule now reads: our own dotted id, never another product's. Cargo.toml's repository points at github.com/bherbruck/solvecraft.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What a component holds moves with its occurrence, and picks in the world land in the
component's frame:
- Sketches and construction planes show where their component is placed (free move, joint
drive, Capture Position); sketch.inspect reports sketch points in the world.
- frames.rs maps a command's world picks into the frame of the body they lie on (through the
inverse of its placement: a moved component or a pasted instance), points that make new
geometry into the active component's frame, and directions with them; instance body names
("Body1 (Pin:2)") become the component's body. Fillet/chamfer edges, shell/offset/draft
faces, face extrude/revolve, sketch on face, holes, sheet metal and plastic picks, primitives,
appearance faces, analyses. Once per command (not again for commands run by commands); the
active-frame fallback stays for commands without a table. Nothing changes while every
placement is the identity.
- component.move_bodies keeps a body where it is in the world (Document.body_offsets: from the
new component's frame to the one it was made in; renames and deleted components follow).
- The UI reads the placed model (Session::world_state) for display, picking, sketch editing and
dialogs; live previews use it once anything is placed.
Tests (engine): sketches and construction planes move (and turn) with the component; world
picks fillet, sketch, hole and make boxes in a moved component; a pick on a pasted instance;
move_bodies keeps the world place there and back; a sketch on a face follows a Move feature.
QA's s34 now runs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL