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>
Avoid full document, cache, and GPU rebuilds for entity deltas so add, delete, history, selection, and live polyline edits stay responsive on large drawings.
ZOOM alone used to jump straight into window zoom. It now offers
Window / Extents / All / In / Out / Scale as clickable keywords
(Scale collects the factor in a second step); ZW/ZE/… shortcuts and
the spelled sub-forms still run directly.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bare STRETCH used to need a separate object-selection round before the
crossing window. Now the window itself picks the objects: with no prior
selection the command emits StretchWindow, the host gathers entities
whose world AABB touches the window (locked layers excluded) and
restarts at the base-point step. Over-selection is harmless since only
points inside the window move. The noun-verb flow (select first, then
STRETCH) is unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
OFFSET now follows the pick-first flow of MOVE / COPY (#422): with
offsettable objects already selected it skips the pick step and goes
straight to the distance / side step, offsetting every selected object
toward the clicked side — each through the cursor point in through
mode, all by the typed magnitude once one is locked. Preview covers
every target and a multi-object result commits as one undo step; with
nothing selected the command gathers a pick exactly as before.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add SelectThenValueCommand (gather selection, then one value) and convert:
- SelectThenValueCommand: HYPERLINK (url), ARCTEXT (text), TEXTFIT (width),
SCALETEXT (factor), TCOUNT (start), TEXTMASK (Enter to apply).
- SelectThenKeywordCommand: JUSTIFYTEXT (Left/Center/Right/Middle/Aligned/Fit),
TCASE (Upper/Lower/Sentence/Title).
Each bare form gathers a selection when none is set, prompts, and delegates to
the inline handler. OBJECTSCALE already opens its dialog; TABLE CELL takes three
values (row/col/text) and stays typeable — TABLE bare already builds a table
interactively.
Typed values were quantized to the f32 grid before reaching the
entity (e.g. a length of 2000.8 committed as 2000.8020), worsening
with magnitude. The interaction point layer was all glam::Vec3 (f32).
Two-layer fix:
1. Coordinate backbone -> f64. last_point, last_cursor_world,
dyn_anchor, dyn_ref become DVec3; UcsXform transforms, parse_coord,
the ucs helper fns, dyn_resolve_point, the OTRACK typed-distance
paths, command-line coordinate entry and the coordinate readout all
compute in f64. Screen/GPU/alignment stays f32 (snap engine, render
geometry, projection, UCS-icon/viewcube drawing) with casts only at
those boundaries.
2. Per-command committed storage -> DVec3. on_point already received a
DVec3, but many command impls narrowed it back to f32 (let pt =
pt.as_vec3(); Vec<Vec3> fields) and re-widened at build, quantizing
the committed coordinate. Migrated PLINE, SPLINE, MLINE, LENGTHEN,
INSERT, 3D primitives, every dimension/leader/mleader, ray, revcloud,
wipeout, attdef, table, tolerance, array center, mview, plot_window,
plus the QDIM_PLACE handler and qdim_collect_points. Preview,
hit-test and rubber-band paths keep f32 at the boundary.
Hatch manual boundaries are left for a follow-up: HatchModel.boundary
is structurally Arc<Vec<[f32;2]>> and needs a model-level widen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Command aliases (L→LINE, CC→COPYCLIP) were scattered across dispatch match
arms and CommandRegistration name arrays. Move them all into a single
user-editable file:
- assets/ocad.pgp: shipped default alias table (ALIAS,*COMMAND format),
embedded and copied to config/ocad.pgp on first launch; only that user
copy is read after. AA→AREA default closes#286.
- resolve_alias() rewrites the leading command token at the top of
dispatch_command_inner, so aliases resolve for every path (families,
plugins, Repeat menu). Args after the first space are untouched.
- Autocomplete hides alias keys and, when the whole input is an alias,
surfaces its target command as the top (highlighted) suggestion so the
highlight matches what Enter runs (AA→AREA, L→LINE).
- ALIASEDIT opens a new editor modal (add/edit/delete rows) with an Apply
button; Apply persists to ocad.pgp, closing discards unapplied edits.
- Strip alias tokens from all 8 dispatch match-arm files and 71 module
CommandRegistration arrays, keeping canonical/synonym/distinct-command
names. ocad.pgp is now the sole source: deleting or remapping an alias
there takes effect. CUI stays on the keyboard-shortcut panel.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Run EXTRIM, pick a cutting boundary (line/arc/circle/ellipse/spline/
polyline), then click a side: every object crossing the boundary is
trimmed on that side and objects wholly on it are erased. Side is decided
by a parity crossing count (a segment to the pick point crossing the
boundary an even number of times is on the pick side), reusing the trim
intersection machinery; line boundaries extend to infinity. Line/arc/
circle are trimmed exactly; polyline/ellipse/spline via dense sampling.
Live preview while choosing the side: boundary in yellow, surviving parts
in blue, the removed parts in red.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Run QUICKPRINT (or QP), select objects, then Enter: the selection's
bounding box becomes the plot window and a PDF is written next to the
drawing (<name>_<timestamp>.pdf) using the active page setup, with no
dialog. Model space.
Implemented as a selection-gathering CadCommand (src/modules/view/
quick_print.rs) returning CmdResult::QuickPrint(handles); the host
(on_quick_print_handles) unions the picked entities' AABBs, sets the
plot window, and reuses the tested clipped window-export path.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Text branch only set horizontal_alignment, so TL/BL/MC etc. never
moved the text box vertically. Map the T*/M*/B* codes to Top/Middle/Bottom
and re-sync the alignment point. (#246)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Integrate a large batch of standard CAD commands and fix several
name/behaviour mismatches, with no product references in code.
3D solids (reusing the truck B-rep pipeline):
- SLICE, INTERFERE, PRESSPULL, POLYSOLID, PYRAMID, SECTION
- 3DROTATE, 3DMIRROR, 3DALIGN (cached-solid transforms)
Annotation / text:
- ARCTEXT, SPLINEFIT (Catmull-Rom to Bezier), DIMJOGGED, OBJECTSCALE
(XData markers honoured by the existing geometry-gen / tessellator)
Blocks / misc:
- NCOPY (block-content extraction via explode_entity)
- OPTIONS, SYNCPVIEWPORTS, THICKEN, plus earlier toggles, aliases,
system variables, and layer/style/view commands
POINTCLOUD/RECAP and UNDERLAYLAYERS/UOSNAP are intentionally left out:
they require a proprietary binary / PDF-layer parser, a GPU point
renderer, and real test files.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Broad pass over the command set: integrate missing commands, wire
previously-unreachable ribbon/menu buttons, and correct name/behaviour
mismatches. Every UI command token now resolves (real handler where the
infrastructure exists, an honest "not yet implemented" status otherwise).
New commands:
- Draw: 3DPOLY, 2D solid (SO/SOLID2D), HELIX, TRACE, SKETCH, DIMCENTER
(DCE/CENTERMARK)
- Modify/inquiry: REVERSE, MEASUREGEOM (MEA), DBLIST
- Data/manage: BASE, OVERKILL (exact-duplicate removal), AUDIT (read-only
integrity report), SETVAR (system-variable get/set), SCRIPT (.scr runner),
FINDNONPURGEABLE
Behaviour fixes:
- LINE and SPLINE gain Close/Undo; AREA computes area/perimeter in f64
(correct at large coordinates)
- ATTEDIT/ATE unified so the alias and the ribbon button open the
interactive editor; -ATTEDIT is the command-line form
- Linear/aligned/radius/diameter dimensions gain a text override (Text) and
text angle (Angle) option
- INSERT gains Scale/Rotate options; COPY gains an Array option
- LINETYPE SET sets the current entity linetype; SETBYLAYER resets overrides
- UNDO accepts a step count
Integrations: standard dimension/block aliases (DLI/DRA/DAN, BMAKE,
EXPORTPDF, DDIM), drafting-aid and screen toggles (GRID/SNAP/POLAR/OSNAP/
DSETTINGS/CLEANSCREEN/QUICKPROPERTIES), viewport tiling
(CASCADE/HORIZONTAL/VERTICAL/VPJOIN), and customization entry points
(CUI/ALIASEDIT).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bare `ZOOM` had no dispatch arm — only the sub-keyword forms (ZOOM
EXTENTS/IN/OUT/WINDOW/…) were handled, so typing `ZOOM` fell through to
an unknown-command error. It now starts the interactive window zoom.
Add the missing Zoom Window ribbon button: the command existed but had no
tool()/icon, so it was reachable only by typing. Wire it into View ▸
Navigate with a new dashed-rectangle magnifier icon.
Closes#210
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Batch 4 of the dimension audit (command features).
- QDIM now works: the relaunched QDIM_PLACE stage decomposes the selected
geometry into endpoints, picks the axis from their spread (not Z), and
builds a continuous chain of linear dimensions at the picked line. Was a
no-op that errored with 'Unknown command'. (DIM-007/008/032)
- DIMSPACE steps parallel dimensions along the in-plane perpendicular
instead of Z (which never moved the dim line). (DIM-021)
- DIMBREAK / DIMJOGLINE no longer report success while doing nothing — they
state honestly that they are not yet implemented (need a break-gap / jog
field on the dimension model). (DIM-019/020)
Refs #181.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Batch 1-3 of the dimension audit (19 issues). The dominant class was the
baked *D block diverging from the live render: a reloaded dimension renders
from that block, so on save+reopen it silently changed.
Bake now matches the live render:
- text value/format via the shared style-resolved path (DIMDEC/DIMLFAC/
DIMPOST/units/<>), correct height + rotation ladder, suppression
- angular dims bake their swept arc (no longer collapse to a V)
- diameter draws edge-to-edge through the centre (live + bake), centre mark
- radius/linear/aligned bake arrowheads
- group-10 (base.definition_point) synced from the edited geometry so an
edited dim no longer shifts on reload
Editing / properties:
- aligned no longer corrupts ext_line_rotation when a coordinate is edited
- DIMTEDIT pins the moved text (text_user_positioned)
- angle properties shown/edited in degrees
- non-linear text respects the user-positioned gate
Commands / geometry:
- DIMBASELINE stacks outward (not toward the points) and its preview no
longer tilts over non-level points
- DIMCONTINUE/DIMBASELINE inherit the base dim's text rotation (UCS chains)
- angular extension lines reach the arc (no gap)
- text grip sits on the text for auto-placed dims instead of the origin
Refs #181. (acadrust DXF round-trip + QDIM/DIMBREAK/DIMJOGLINE/DIMSPACE/
DIMEDIT to follow.)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Break up the four giant files (~29k lines total) into focused submodule
directories, one concern per file. Pure mechanical moves — behavior is
unchanged.
- app/update.rs (9650) -> app/update/{mod,viewport,command,style,file,
dynamic,dialog,util}. The 384-arm update_inner match stays in mod.rs
with thin delegating arms; the 66 fattest arm bodies move to topic
methods. Arm set preserved exactly (384 -> 384).
- scene/mod.rs (9017) -> scene/{mod,entity,tess,hittest,layout,paper,
mspace,project,selection,modify,group_layer,preview}. The impl Scene
body is split across files via inherent-impl-per-file; struct, ctor,
fields and load-time helpers stay in the root. fn count 123 -> 123.
- app/commands.rs (6082) -> app/commands/* grouped by command family.
The 233-arm dispatch match becomes source-ordered per-family
dispatch_* handlers, preserving first-match precedence (233 -> 233).
- app/view.rs (4686) -> app/view/{mod,overlay,modal,viewcube,controls}.
Largest file drops from 9650 to 3343. Builds clean; app launches and
loads plugins with no panic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>