Sync current main and companion codec changes before preserving unsupported frame rows, rendering in the entity plane, and sharing final layout metrics with placement preview.
INSERT enumerated all block names in a single prompt string, causing unbounded overlay growth and full-screen occlusion in drawings with many blocks. Replace prompt enumeration with a ranked, incrementally filtered suggestion model: BlockPicker maintains precomputed lower/upper caches and usage ranks (MRU/frequency), filters via O(n) substring scan and partial sorting (select_nth_unstable) to O(k), bounded to CLIPROMPTLINES.
Introduce CLIPROMPTLINES (Integer 0-50, Registry, default 3) for the number of temporary prompt lines above the command window; persist in UserSettings, expose via SETVAR and direct entry, enforce in CommandLine::view. Suggestion count is in direct relation to CLIPROMPTLINES (limit = clip, capped to 50).
Make search live without requiring Enter: add CadCommand::on_live_input, implement for INSERT/MINSERT via picker.set_needle, and wire to command-line input paths (Message::CommandInput, on_command_append_char, on_command_backspace). Updates use upper/lower caches and partial sort for <0.2ms per keystroke on 10k blocks, with debounced block-usage persistence (MRU cap 20, freq cap 200) to avoid I/O thrash. Correct tri_count test helper to use display_from_solid.
Implement the AutoCAD compatible HATCHTOBACK (HB) command and enhance the interactive DRAWORDER command pipeline with comprehensive verb selection and viewport entity picking.
Key implementations and architectural details:
1. HATCHTOBACK command execution
* Isolates entities belonging to the active layout block record or global space.
* Filters out entities residing on locked layers using an efficient hash set lookup.
* Records targeted delta undo operations on SortEntitiesTable objects (~100 bytes) rather than snapshotting full document structures.
* Performs granular draw depth cache invalidation via Scene::invalidate_draw_depth, preserving existing geometry tessellations and spatial indices.
* Emits localized user notifications when no qualifying hatch entities are found.
2. Interactive DrawOrderCommand state machine
* Supports preselected entities as well as interactive on demand selection gathering.
* Implements subverb selection supporting single character shortcuts (A for Above, U for Under, F for Front, B for Back) and case insensitive keyword parsing.
* Enables interactive reference object picking directly in the viewport via needs_entity_pick and on_entity_pick callbacks.
* Supports hexadecimal handle specification directly from the command line interface.
3. Ecosystem and system integration
* Bumps DEFAULT_ALIASES_VERSION from 2 to 3 to register the HB alias while preserving existing user overrides.
* Integrates HATCHTOBACK and HB into dynamic autocomplete registries.
* Adds localized message strings across all 20 Fluent translation catalogs.
* Corrects hatch boundary serialization flags to ensure outermost boundary rings consistently carry the external attribute.
The last four truck crates are gone from the manifest. What they were doing
falls into three parts, and each now has one answer instead of two.
NURBS evaluation. truck was carrying B-spline curves and surfaces for the
SPLINE entity, hatch boundaries, BLEND's endpoint frames, the spline preview
and ACIS spline-surface faces. The kernel now has both, over one de Boor
written across however many coordinates a control point holds — so a plane
curve and a space curve cannot drift apart, and a surface is the same
algorithm applied twice. The rational and the polynomial cases stop being
separate types: weights absent means polynomial.
The entity conversion. Every LINE, ARC, ELLIPSE, SPLINE and polyline was
built into truck topology purely so it could be sampled back into points.
They are sampled through `entities::curve` now, which is where each one's
geometry is already defined once and what EXTRUDE and REVOLVE read — so a
circle drawn on screen and a circle handed to the Model tab come from the
same definition. That retires four of TruckObject's variants and the module
is renamed for what it does.
SWEEP and LOFT. Both only ever produced a mesh, so both are built from point
lists: a band of quads per span, and a lid where a profile closes. Lofting
profiles of different densities resamples them by distance rather than by
index, so a circle lofted to a square no longer twists.
Two things worth noting for anyone reading the old comments. The tolerance
globals that lived in the tessellation module were never about truck at all —
they are the per-frame chord height, and they move to `curve_tol`. And the
rule that a profile handed over as `Lines` silently broke EXTRUDE and REVOLVE
no longer holds: those read the curve directly and never look at this channel.
The two `automation` test failures are unchanged from before this and are not
caused by it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every 3-D solid OCS makes or opens now goes through cadkernel, which holds
analytic surfaces — a cylinder is a cylinder record, not a spline that looks
like one. That is what lets a solid built here be written back out as exact
ACIS instead of a triangulation, and a facetted export is a one-way door: the
next application to open the file would have no way back to the circle.
The Model tab's seven primitives, the Design-group booleans, 3DROTATE,
3DMIRROR, 3DALIGN, SLICE, SECTION, POLYSOLID and PYRAMID all come from the
kernel now, and `scene.solid_models` holds a `Body`. A mirrored solid needed
its own care before; the kernel reverses the loops on the way through, so it
comes back the right way out rather than lighting black.
EXTRUDE and REVOLVE sweep the profile `entities::curve` already defines, so a
circle, an arc-bulged polyline and a closed spline arrive as the same thing.
A circle extrudes into four cylinder patches rather than a run of chords, and
a profile turned about an axis becomes a cone, a sphere or a torus. A spline
profile has no analytic side wall and is refused rather than approximated.
ACIS goes both ways through the codec's own bridge: `lift` to read and
`append` to write. That drops the 679-line truck conversion and the planar-
only exporter, and the tessellator keeps its bespoke sampler as a fallback for
whatever the kernel cannot yet express — reported rather than passed off as
whole, since a mesh missing a wall looks finished.
truck-shapeops is no longer used and is gone from the manifest. truck-modeling
stays for now: fourteen files use it as a 3-D NURBS evaluator, which the
kernel has no answer for yet, and SWEEP and LOFT have no kernel operation
behind them either.
The two `automation` test failures are unchanged from before this and are not
caused by it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The placement options arrived with their prompts and messages written as
plain Rust strings, so they were the only command left speaking English
whatever the interface was set to.
They go through t! / tf! now like every other prompt, and the strings are
registered so the call actually reaches a translation: a source string
only resolves if the generated lookup knows it, and t! on an unknown
string just hands the source back. Keys follow what the table already
uses — the slug of the source, cut to forty-six characters, and the first
ten hex digits of its SHA-1 — which reproduces 2978 of the 3161 entries
exactly; the rest are hand-written ones predating the generator.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Only Previous and Last were on offer, so Window, Crossing, Fence, the two
polygons and All could not be reached at all -- and with no keyboard to
type them into, the buttons were the only way in.
Window and Crossing fix the sense of the next box. Dragging derives that
from the direction the corner travels and would overwrite it the moment
the corner moved, so the derivation stands down while a keyword holds it.
Add and Remove decide what a pick does for the rest of the round: Remove
subtracts the way Shift already does, rather than through PICKADD, which
decides whether a pick *replaces* the set and so would have wiped
everything gathered so far. Both are dropped when the next command
starts, since neither outlives the selection that asked for them.
Fence and the polygons are picked point by point, which TRIM and EXTEND
already ask for. That gesture -- the points, the rubber-banded dashed
preview, whether the path closes -- moves into one place both bind to,
and the two preview builders duplicated in trim.rs go with it.
A fence is not the polygon test with crossing set: that closes the point
list and counts whatever lies inside, so a line drawn past a row of
objects would take everything behind it too. It gets a hit test that only
counts a real intersection, and skips the area-based geometry entirely.
The lasso gathered its hits from wires, hatches, block hatches, meshes and
block meshes inline; the new modes need the same list, and a second copy
would drift. Both now come through `Scene::path_hit_handles`.
Closes#596
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Cancel stale interaction state across space changes and keep live previews and zoom extents in their active paper/model context.\n\nRefs #539\nRefs #540\nRefs #541
Avoid full document, cache, and GPU rebuilds for entity deltas so add, delete, history, selection, and live polyline edits stay responsive on large drawings.
PLAN acted like a ViewCube TOP click the moment it ran — already on Top
meant an immediate flip to Bottom, and the options never appeared. It
now prompts "[Current ucs / Ucs / World] <Current>:" right on
activation and only changes the view once an option runs: Current =
plan of the active UCS, World = world XY, Ucs = prompts for a named UCS
(case-insensitive lookup). The new plan_snap goes straight to the plan
view with no flip-to-opposite cube behaviour.
KeywordCommand gains with_default(): a bare Enter at the verb step
dispatches the default verb (PLAN's <Current>) instead of cancelling.
Closes#326
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Grip drags mutated the document without ever pushing history — dragging
a polyline vertex (or any grip) could not be undone. The release-commit
now swaps the pre-drag backup in, snapshots that PRE state as a "GRIP"
entry, swaps the dragged result back and clears the redo stack; the
Esc-cancel path is unchanged and a no-move engaging click records
nothing.
Ctrl+Z during a drawing command steps the command instead of the
document undo swallowing the in-progress object (which also killed the
active command): new CadCommand::on_undo_step hook, consulted before
undo_active_tab. PLINE pops its last vertex (shared with the U option),
LINE reverts the last committed segment and keeps drawing from the
previous point (rides its existing U/UndoDocument path), and ARC
Continue reverts the last arc and resumes from the prior anchor with
the correct tangent via a new anchor history. With nothing placed yet
each falls through to the document undo.
Also drops the two warnings the #336 work left behind (unused Entity
import, dead Snapper::override_active).
Closes#332
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both commands gain a shared option mode machine:
- Cutting/Boundary edges (T/B): pick which objects act as the boundary
(picked edges highlight yellow, the hovered candidate half-strength);
Enter rebuilds the boundary set, empty = everything (quick mode).
- Fence (F): draw a dashed fence; every object crossing it is trimmed /
extended at each crossing, re-applied to the surviving pieces so a
fence across both overhanging ends clears both. Live red/cyan result
preview while placing points.
- Crossing (C): crossing-selection semantics — the dashed green window
picks objects crossing its edges AND wholly inside; runs through the
fence machinery with a synthesized inside click.
- Edge (E): boundaries extrapolate (lines run past their ends, arcs
close to full circles). Cuts that land on an implied extension draw a
dashed yellow guide from the boundary's drawn end to the cut point,
so the user sees which edge causes the cut. Extend previews also show
the added tail as a bright dashed slice of the true curve.
- Erase (R, TRIM): picks delete without needing an intersection, with a
red hover preview.
- Shift+click swaps trim<->extend per pick (new set_shift plumbing into
the entity-pick and hover paths); the hover preview follows the held
state. Project is out of scope for the 2D pipeline.
The per-type pick bodies moved to shared free fns (pick_trim_at /
pick_extend_at) used by direct picks, hover previews and the fence
pass; EXTEND's snapshot bookkeeping unified with TRIM's placeholder
flow. Option keywords now take precedence over the hex-handle reading
in feed_active_cmd ("F"/"C"/"E" are valid hex), and fence geos carry
sentinel handles — probing with NULL against NULL-handle geos excluded
the whole fence. Regression test: fence_trims_x_arm.
Closes#336
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
U / UNDO (typed or via the prompt button) pops the last placed vertex
without ending the command, repeatably down to and past the start
point. The exit tangent of the remaining last segment is recomputed
from its bulge so a following Arc segment stays tangent-continuous.
New CmdResult::RemoveLiveEntity takes the live polyline out of the
document when Undo drops it below two vertices; the next point
re-creates it under the same undo unit.
Closes#352
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- RENAME gains the BLOCK type (stepped button + inline arm) via the
shared Scene::rename_block.
- Stepped command front-ends (Rename, UserReg, Keyword, TwoValue,
SelectThenTwoValue) returned None after consuming a typed token, and
the driver treats None as "not consumed" — the same text was offered
again and advanced two steps at once (RENAME dispatched old==new,
SETVAR "X" became "SETVAR X X"). Consumed-but-prompting inputs now
return NeedPoint.
- Symbol renames re-key the name-keyed Table (remove -> rename -> add)
instead of mutating .name in place, which left the map keyed by the
old name so later lookups silently failed. References (entity
layer/linetype/style fields, layer linetypes, header current-* names,
dim style refs on Dimension/Leader/Tolerance) are chased
case-insensitively; layer 0/Defpoints and the built-in linetypes are
protected; the undo snapshot is taken before the mutation so undo
actually restores the old name.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>