CECOLOR now reads "BYLAYER", "BYBLOCK", the index as text ("1" after
"red") or "RGB:r,g,b" for a true colour, from getvar, LISP and the
SETVAR ? list, where it was the ACI number (256, 0, 1, or the nearest
index of a true colour). The header still keeps the index and
CECOLOR_RGB, so DXF output and new objects are unchanged.
SETVAR CECOLOR takes "RGB:r,g,b" too, so a value saved with getvar
can be set back, true colour included.
Tools > Express Tools > Break-line Symbol draws one polyline from the first point to the second with a zigzag break symbol at a picked location (the midpoint on Enter), as AutoCAD's Express Tool does. Size scales the symbol (times DIMSCALE), Extension runs the line past both points, and Block takes a block of the drawing whose two points on the Defpoints layer mark where the line meets the symbol. The built-in symbol is our own geometry. One undo step; the options are remembered for the session.
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* AutoLISP: load and run .lsp routines (#758)
CADCraft runs AutoLISP routines. `.lsp` files load with APPLOAD, (load)
or by dropping them on the window, and at startup from the support folder
(acad.lsp once per session or per drawing with ACADLSPASDOC, acaddoc.lsp
per drawing, then S::STARTUP; never from a drawing's own folder).
(defun c:NAME …) defines commands, (autoload) defers loading to first
use, and (expression) and !variable work at the command line and at
prompts. docs/autolisp.md lists what is supported.
The interpreter (crates/engine/src/lisp) reads source with its own
stack and evaluates on an explicit-stack machine, so a routine can stop
for input (getpoint, pause in command) and carry on later on one thread,
deep recursion is an error rather than a crash, and long loops run a
slice per frame (Esc stops them). It follows AutoLISP: 32-bit wrapping
integers, dynamic scope, *error*, vl-catch-all-apply, AutoLISP's error
wording. About 200 built-ins cover the language, command (with pause and
commands left open), entity lists (entget/entmake/entmod/entdel/entlast/
entnext/handent, through the DXF reader and writer's groups, exposed by
cadcraft-io and handed to the engine through a hook), ssget with modes
and filters, tables, system variables, get… input with initget, and
units. A routine is one undo step; each drawing has its own symbols.
Also: keywords typed as _KEYWORD match at prompts; TEXT run by a
routine's command takes one line; DIMENSION records carry their
measurement (42); Prompt::raw shows a get… prompt as written; the
interface asks Session::prompting() (a command's or a routine's prompt)
where it asked whether a command runs, so clicks, right-click and Delete
work at a routine's prompts; getcorner and based get… prompts drag a
rubber band.
Tests: the language, errors, startup files, interactive input, hostile
input (lisp/tests.rs); the #648 corpus, 18/18, when CADCRAFT_LISP_CORPUS
points at it (tests/lisp_corpus.rs); drop, frames and canvas clicks in
the app (ui-egui/tests/lisp_files.rs).
* AutoLISP: bound memory, drop nested values iteratively, guard the per-frame tick
- Cons cells drop with a work list over both car and cdr (and function
bodies), so a list nested a million deep in its car no longer overflows
the stack when it goes away.
- Memory caps so a runaway routine fails with a LISP error instead of an
uncatchable out-of-memory abort: at most 5,000,000 live cons cells
(counted in Value::cons / Drop, checked every step; cells the drawing's
variables already held at the run's start don't count against it), no
string a built-in makes longer than 8 MiB (strcat checks before joining,
printed text is cut), and a 2 GiB per-run budget for new strings,
printed text and files read.
- Session::lisp_tick runs under catch_unwind, and so does every slice of
the LISP machine: a panic ends the routine with "internal error", puts
the drawing back and leaves the session usable.
- Regression tests for each (deep car nesting, nested functions, the cell
cap, string length and budget, a panicking built-in in a blocking run
and in a ticked one).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* REFEDIT, REFSET and REFCLOSE: edit block references in place (#813)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* Move REFEDIT translation lines into the middle of the catalogs (avoids PR merge conflicts)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
* MLEADEREDIT, MLEADERALIGN and MLEADERCOLLECT (#812)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* Move MLEADER translation lines away from the end of the catalogs (avoids PR merge conflicts)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
GROUP makes named or unnamed (*A1, *A2…) groups from the selection, typed
("Select objects or [Name/Description]") or as JSON. UNGROUP removes a group
picked by one of its objects or by name. GROUPEDIT adds and removes objects and
renames a group; removing the last object deletes it. groups.list reports them.
After every command, members that no longer exist leave their groups and empty
groups are deleted (undo restores both). The drawing model and the ACAD_GROUP
DXF round trip already existed.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
MLEADER's Options answered "not available yet" for Leader type sPline and
None and for Content type Block. Spline leaders now draw as smooth curves
through their points (DXF LEADER path type 72 = 1); None places only the
content at one picked point; Block asks for a block name and how it
attaches (Center extents or Insertion point) and inserts it at the end of
the landing. MLeader gains `spline` and `block` (serde defaults); DXF stays
LEADER + MTEXT/INSERT. PURGE, RENAME, copy/paste, FLATTEN, grips and
extents follow the block content. The choices are remembered like the
other MLEADER options. docs/gaps.md: top-10 row 5, F1 and F10 narrowed.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
SPLINE's Knots, Object, start/end Tangency and toLerance options printed
"not available yet". Fit-point splines now take a knot parametrisation
(chord, square root, uniform), end tangents (clamped cubic with derivative
constraints) and a fit tolerance (least-squares approximation with the
fewest control points that stay within it). The spline keeps these options
so grip and SPLINEDIT edits refit the same way; DXF writes the tolerance
(44) and tangents (12/13) and recovers the parametrisation from the knots.
Object turns 2D/3D polylines with straight segments (PEDIT Spline output)
into splines through their vertices.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The options at MTEXT's "Specify opposite corner" prompt printed "not
available yet". Each now asks its question and returns to the corner
prompt: Height (also sets TEXTSIZE), Justify (TL..BR, the insertion point
is the box's attachment point), Line spacing (At least/Exactly, then a
factor such as 1.5x or a distance), Rotation (picked, or typed through the
drawing's angle settings; the box turns with it), Style (? lists them),
Width (replaces the opposite corner) and Columns (No; Dynamic and Static
say columns are not available yet). MText stores the line spacing style
(DXF group 73) so Exactly round-trips.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
AUDIT checks for missing layers, linetypes, styles and block definitions,
current-style variables naming missing entries, invalid geometry (NaN or
infinite numbers, zero-length lines, zero-radius circles and arcs),
block definitions that contain themselves, duplicate handles, and
references to missing objects (dimension associations, groups,
constraints, viewport layer lists). It asks "Fix any errors detected?
[Yes/No] <N>:"; the JSON form `audit {fix?}` returns a structured
report. RECOVER opens a file through the read hook and applies AUDIT's
fixes. A question prompt now shows its answers without "or".
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
PLINE arc mode answered "not available yet" for Angle, CEnter, Direction,
Radius and Second pt, and line mode for Length. Each now asks its questions
(included angles and directions read the drawing's angle settings) and adds
the segment. XLINE's options were already in draw2's XlineM2; the dead
keyword stub in draw.rs's RAY machine goes, and Offset/Reference use the
polyline segment picked rather than the first one.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The options TRIM and EXTEND list at their prompt all printed "not available
yet". Quick and Standard modes follow TRIMEXTENDMODE, Edge extends lines and
arcs virtually (EDGEMODE), Project is kept in PROJMODE. The JSON forms take
fence, crossing, edgeMode and (TRIM) mode.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Copying in one drawing and pasting in another lost what the objects
refer to: a line on a layer the target lacked landed on a new default
layer (colour and linetype gone), and a block reference pointed at a
block the target didn't have. Cmd/Ctrl+C, X and V did nothing on the
desktop, because egui delivers them as clipboard events, not key
presses. PASTEORIG had no checks, and the canvas had no right-click
menu.
- Engine (cmd/clipboard.rs): the session clipboard keeps, with the
copied objects, the layers, linetypes, text/dimension/multileader/
table styles and blocks (nested too) they use. Pasting adds the ones
the target lacks; names it has keep the target's definitions, as in
AutoCAD; generated (*U, *D) blocks whose name is taken get a fresh
one; objects get new handles.
- PASTEORIG pastes at the original coordinates, only into a drawing
other than the one copied from (greyed and refused there, as in
AutoCAD). PASTECLIP and PASTEBLOCK are greyed with an empty clipboard.
- PASTEBLOCK (Edit > Paste as Block, Cmd+Shift+V): the clipboard
becomes an A$C… block inserted at a point. AI_DESELECT.
- UI: Cut/Copy/Paste events run the clipboard commands (Shift: Copy
with Base Point / Paste as Block). Each copy is also put on the system
clipboard as DXF text, and pasted DXF text that isn't our own last
copy becomes the clipboard, so another CADCraft window can paste it.
- Right-click on the canvas with no command running opens a shortcut
menu: Repeat <last>, Clipboard (Cut, Copy, Copy with Base Point,
Paste, Paste as Block, Paste to Original Coordinates), the
selection's editing commands and Deselect All, Undo/Redo, Pan/Zoom,
Quick Select, Find. During a command it is still Enter.
- Ukrainian labels for the new items.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
CIRCLE/ARC no longer make a negative radius positive; POLYGON refuses a
non-integer sides count and a zero/negative radius or zero-length edge;
DONUT, RECTANG, PLINE, HATCH and TABLE refuse negative or zero sizes
instead of clamping them; LINE drops repeated points like the interactive
command; SPLINE needs two different fit points; DIMRADIUS/DIMDIAMETER/
DIMANGULAR refuse coincident points; DDPTYPE refuses an invalid PDMODE;
DIMSTYLE/DIMOVERRIDE list a non-positive DIMTXT/DIMTFAC or a negative
DIMASZ/DIMSCALE/DIMTSZ as ignored.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
targets() fell back to the current selection when `handle` wasn't a hex
handle or `handles` wasn't an array, and dropped unreadable entries from
`handles`. A typo such as {"handle": "#101"} made ERASE, MOVE and the other
~70 commands that take objects act on whatever was selected (in a bridged
MCP session: the user's selection in the window). Such values are now an
error naming the bad value; the selection is used only when neither key is
given (or it is null).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Array commands: ARRAY, and the edit-array option loops for ARRAYRECT/ARRAYPOLAR (#230)
ARRAY (alias AR) selects objects, asks for the array type and continues as
ARRAYRECT, ARRAYPATH or ARRAYPOLAR. ARRAYRECT no longer creates a fixed 4x3
grid right after selection: it previews the array and loops on
ASsociative/Base point/COUnt/Spacing/COLumns/Rows/Levels/eXit. ARRAYPOLAR
asks for the center (or Base point), then loops on Items/Angle between/
Fill angle/ROTate items/eXit. The copies are created on eXit or Enter.
Associative arrays, levels and polar rows report "not available yet" and
return to the loop without consuming the next input.
The array commands move to cmd/array.rs. Arrays stay non-associative
copies, and the JSON forms are unchanged. A full clockwise polar fill
(-360) no longer puts the last item on top of the source.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs/gaps.md: narrow F5 (array option loops, #230)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Arrays: refuse arrays over MAXARRAY instead of hanging or shrinking them (#230)
`arrayrect {"rows":1000000,"cols":1000000}` was clamped to 1000x1000 and
then created a million copies of every selected object, which hangs the
app. ARRAYRECT, ARRAYPOLAR and ARRAYPATH (JSON and interactive, also via
ARRAY) now count items x selected objects and refuse an array over the
new MAXARRAY session variable (default 100000, settable 100..10000000)
with a message naming the limit, instead of clamping the counts and
silently creating fewer copies. The interactive count prompts accept at
most what still fits under MAXARRAY.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- Layer Properties Manager: filter tree (All / All Used Layers) with search, sortable table
(Status, Name, On, Freeze, Lock, Plot, Color, Linetype, Lineweight, Transparency,
New VP Freeze, Description; VP Freeze / VP Color inside an MSPACE viewport), inline
rename and description, ACI + true-colour picker, linetype picker with Load from the
library, lineweight picker, layer states save/restore/delete.
- Engine: qselect rewritten ({type, property, operator =,!=,>,<,*, value, mode new|append|
exclude, applyTo}) + qselect.info; layerstate.list/delete/rename; layer list reports
used layers and states; Layer.vp_freeze_new (DXF flag 2, applied by MVIEW) and
layer.set newVpFreeze; per-viewport layer colours (Viewport.layer_colors, vplayer
colors, honoured by the renderer); vplayer defaults to the active viewport; QPMODE
setting/sysvar/toggle; properties.set length/angle for lines.
- Canvas: constraint bars with code-drawn glyphs and coincident markers, dynamic
dimensional constraints (aligned/horizontal/vertical/radius/diameter/angular) with
name=value labels and lock icon, honouring CONSTRAINTBAR/DCDISPLAY; cached per
drawing revision; double-click a label to edit its expression (parameters).
- Quick Properties palette near the selection (status-bar toggle), Quick Select dialog,
Parameters Manager (edit, add user parameter, delete).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Annotation (M4):
- TrueType text from system fonts (filled/outlined), shared placement for all text
- MTEXT formatting codes: fonts, heights, colours, under/overline, stacks, wrapping
- Full DIMSTYLE variables, per-dimension overrides, all arrowheads and ticks,
unit formats, tolerances, limits, alternate units, colours by role
- Associative dimensions that follow geometry; DIMREASSOCIATE/DIMDISASSOCIATE
- STYLE/DIMSTYLE management commands, DIMTEDIT, DIMSPACE, TABLE create/edit/merge
Parametric (M9):
- New cadcraft-constraints crate: weighted damped Gauss-Newton solver, conflict
and redundancy detection, expressions, AutoConstrain inference
- All GC*/DC* commands, GEOMCONSTRAINT/DIMCONSTRAINT, PARAMETERS, DELCONSTRAINT,
constraint bar / display settings; re-solve after every edit
Also: MODEL/PAPER status bar toggle, cargo xtask alias, roadmap update
(233/491 menu items, 290 commands).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DIMLINEAR/ALIGNED/RADIUS/DIAMETER/ANGULAR/ARC/ORDINATE/CONTINUE/BASELINE, QDIM, MLEADER, LEADER;
HATCH/GRADIENT/BOUNDARY/REGION with pick-point boundary tracing (planar face walk with islands);
BLOCK/INSERT/ATTDEF/ATTEDIT/WBLOCK/PURGE/BATTMAN; dimension text gaps and horizontal text;
DXF header writer whitelist (correct group codes).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>