A new drawing (#1441) recorded ISO-25 as the current dimension style by
name only. Every other place that changes it sets the header's handle as
well, and a DWG carries the current style by handle alone, so a saved new
drawing reopened on Standard. The style's handle now comes back from the
helper that adds it.
A radius constraint (#1443) anchored the circle's centre from the shape of
its references — one whole entity — but a single whole reference is also a
line's length, whose start is what stays. The entity decides now.
The two tests that encoded the replaced rules follow them: a negative
radius validates by its magnitude, as a negative distance already did, and
only zero is refused; a new drawing's dimension text reads at ISO-25's
comma separator.
Co-Authored-By: Claude Opus 5 <[email protected]>
`bool::then_some` evaluates its argument eagerly, so starting SHELL or
SOLIDEDIT with nothing selected indexed an empty vector and aborted the
application. The single-solid target now comes from a slice match.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Three doc paragraphs had stacked above one helper, so each described the
function after the one it sits on.
Co-Authored-By: Claude Opus 5 <[email protected]>
Direct distance entry (#1429) turned every bare number at a point prompt
into a distance, so ROTATE's angle and the values automation types were
read as coordinates. The step reads the token first now — `feed_command`
reports whether it claimed it — and only an unclaimed one becomes a
distance. That also puts the token back on the unified step driver, which
owns the P / L selection keywords and the dimension-snap bookkeeping, and
stops `on_text_input` running twice for the same token. A tracking ray
carries its own base, so it no longer demands an anchor that the first
point of a command does not have yet.
Plugin command execution (#1425) re-implemented the command line inside
the plugin host: it dispatched families directly, skipping the teardown
that starts a command (grip edits, selection gestures, `last_point`, the
accepted snaps), and made every `CmdResult::Dispatch` in the application
skip plugin dispatch to avoid its own re-entrancy. A scripted line now
runs through `run_command_line`, with the trailing Enter left off while
the plugin streams the command, and the re-entrancy is handled by a flag
set for the length of the plugin's call. A pause parks the line's Enter
with the rest of its tokens instead of dropping it.
A font reference (#1432) tried the family lookup before the face-file
index, and that lookup ends in a prefix match a longer file name loses to
(`ISOCPEUI.TTF` would take `ISOCP`). The exact file answers first.
Co-Authored-By: Claude Opus 5 <[email protected]>
Select arc or circle / Dimension text / dimension line location / value or
name prompts with a radN parameter, invalid-selection, miss, duplicate and
invalid-expression messages, negative values as magnitudes, a dynamic radial
dimension on the constraints layer drawn as the reference does (mid-radius
text on the center-to-rim line, no hook, no center mark, one text grip), the
stored text position following the radius, center-anchored resizing, the
Properties title and Constraint section, DIMCONSTRAINT's Radius default,
the small-button Dimensional ribbon grid and tooltip descriptions.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
The Annotative row of text, MText, blocks, leaders, hatches and
dimensions is a Yes/No list, as the reference shows it; choosing a value
drives the same per-object annotative toggle as before.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
An angular dimension is titled `Angular Dimension` and a three-point
one `3 Point Angular Dimension`, as the reference names them.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Reads and sets the form new dimensional constraints take (0 dynamic,
1 annotational), the same state DCFORM sets.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Dynamic dimensions carry DIMEXO/DIMEXE/DIMASZ overrides in text-height
ratios, a two-line angular dimension draws extension lines only beyond
its sides, a selected dynamic angle shows triangle grips at the arc ends
with squares at the arc point and text, and the constraint dimension's
Properties follow the reference: kind titles, General before Constraint,
angular-precision Value and Measurement, drawn text position, reference
row order for Fit, Primary Units and Tolerances, and text/dimension line
alignment rows reading On as the aligned state.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Three-point angular dimensions take their sweep from the two rays and the
arc point (extension lines follow their own rays, straight and reflex
angles draw), dynamic angular dimensions store no text point so DIMTAD
places the text beside an unbroken arc, and dynamic dimensions carry a
DIMGAP override of a quarter text height.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
DCANGULAR picks two lines, an arc or three points, takes the dimension
line location to choose the sector and the value or name, and creates the
dynamic two-line or three-point angular dimension driven by an angN
parameter. Reference messages for invalid, repeated and parallel sides,
existing names and invalid names; angle values display within one turn at
the angular precision; the first side (or vertex and first point) stays
when the value changes; the ribbon Dimensional panel follows the reference
order.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Placements (entity lookups, intersections, String labels, projections)
recomputed per view() and per mouse-move hit-test, with overlay re-clones
and 2-3x offset recomputes. New constraints_epoch bumped on every set
mutation/visibility/undo/DWG-load (plus new set_constraint_enabled API);
single-slot Arc<[GlyphEntry]> memo on an 11-field key (hover/selection
excluded); overlay de-cloned/de-duped to the single geometry source;
hit paths reuse the cache.
Tests:
- cached_glyph_placements_hit_returns_same_arc: same-key Arc identity
- cached_glyph_placements_invalidated_by_metadata_edit: edit + selection change yield new Arc
- glyph_hit_test_entries_matches_precomputed_boxes: shared hit-test helper
Bench (cargo bench glyph, 60 constraints): 8.18us -> 0.05-0.15us (~55x).
A/B reference deleted.
A trackpad could only zoom: every scroll delta, wheel notch or not, went
into the same zoom step, and a pinch never arrived at all. iced's winit
layer converts only the window events it has an iced equivalent for, so
winit's `PinchGesture` was dropped before the app saw it.
Scroll deltas now split by what produced them: a wheel reports notches and
still zooms, a precise-scrolling device reports pixels and pans. The same
pixel split keeps working everywhere else — the browser build reports every
wheel notch as pixels, so there they keep zooming.
The pinch is read straight from AppKit with a local `NSEvent` monitor, since
the app cannot see the gesture through iced at all, and handed to the app
through a subscription shaped like the SpaceMouse bridge. It maps 1:1 onto
the camera: fingers 5% further apart leave the view 5% closer.
The pan and zoom bodies are now shared by the mouse and the gestures, so the
middle-button drag, the wheel, two fingers and a pinch all move the view
through one path — in model space, in a tiled pane and inside a floating
viewport alike.
On Windows the temp directory has backslashes, which a Python string literal reads
as escape sequences (C:\Users is a unicode escape), so the RasterImage and OLE
lifecycle tests could not even create their entity. Windows accepts forward slashes.
Found by the first Windows run of the fork build workflow; Linux passed all 60.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
A saved user preference (on by default) toggled by the SCRIPTCOMMANDS command
gates HostApi::run_command; Cancel stays allowed so a waiting command is never
stranded. The runner refuses the SCRIPTCOMMANDS command itself, so a script
cannot change it. Documents why no helper-thread or stack-growing dependency was
added: native builds link with at least 8 MiB, the nesting depth is fixed, and the
deepest step found needs 2 to 4 MiB in a debug build.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Drop two unneeded mut bindings in tests and mark the generated dict/enum
converters allow(dead_code), since a kind can leave one unused.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
polyline_close/open/width/reverse/join (a line or arc is turned into a polyline
first), array_path and array_3d, written against observed prompts and checked
for exact geometry in the real-IPC audit. Polylines default their pick point to
the first vertex. The audit runs on a large-stack thread because PEDIT's
line-to-polyline step needs more than a test thread's 2 MiB in a debug build.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
The generated dict-to-struct conversions for nested records defaulted every
absent field and ignored unknown keys, so an LwPolyline built from
{'x': .., 'y': ..} vertices became zero-coordinate vertices. They now refuse an
unknown key (naming the keys the record takes) and a manifest list,
required_struct_fields, enforces the fields that define a nested record's
geometry (vertex locations, hatch edge ends and centres, section symbol points).
Regression test over real IPC; every existing lifecycle audit still passes.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Each is written against the prompt sequence observed in the exploration harness
and checked for exact geometry in the real-IPC audit. HATCH is left to
create_entity because its command needs an interactive boundary pick.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
HostApi::run_command drives the real OCS command through the same primitives
the automation channel uses, synchronously on the host thread: run a line,
start a command and answer point/text/token/entity/selection/enter prompts, or
cancel (closing anything the command opened). Refused while another command is
active, for a denylist (QUIT, NEW, OPEN, SAVE*, PY_* ...) and off the active tab.
Python: doc.command, doc.start_command and doc.modify (offset, trim, extend,
fillet, move, copy, rotate, scale, mirror, erase). Real-IPC audit checks exact
geometry for every wrapper plus guards and undo; IPC and Python unit tests; docs.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
TableOperation gains simple-linetype create/modify/rename/delete (standard names
taken, rename follows layers and entities, guarded delete) and paper-space
layout create/rename/delete/set-current/set-page (default page setup and sheet
viewport, the application's own layout switch, Model protected). CTAB now reports
the current layout. Real-IPC audit with DWG/DXF persistence and undo, IPC and
Python unit tests, docs.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
BlockEntityAdd adds a validated entity to a block definition (owner set by the
host, same validation as a model-space entity, self-nesting inserts refused),
reusing the scene's block-editor routing. Deleting a block member now also
drops its handle from the block record. Real-IPC audit with an attribute
definition inside a block, DWG/DXF persistence and undo; IPC and Python unit
tests; docs.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
TableOperation gains BlockCreate (copy entities into a definition shifted by the
base point, optionally erasing originals), BlockModify, BlockRename (inserts
follow) and BlockDelete (refused while referenced; removes members, markers and
orphaned draw-order tables). Real-IPC audit with DWG/DXF persistence and undo,
IPC and Python unit tests, docs; the DXF loss of the block description is pinned
by a canary.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Extends TableOperation with text style create/modify, dimension style
create/modify (DimStyle fields as a validated JSON object), rename, delete and
set-current. Reuses OCS's style in-use scan and reference-following rename
(four style_ops methods widened to pub(super)); a renamed text style also
updates dimension styles that name it. Real-IPC audit with DWG/DXF persistence
and undo, IPC and Python unit tests, docs. Four cadcodec findings are pinned by
canaries.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Adds the additive v7 TableOperation request and HostApi::table_operation for
layer create/modify/rename/delete/set-current. Refusals are decided before the
undo step is recorded. Python wrapper, real-IPC audit with DWG/DXF persistence,
IPC round-trip test, Python unit test and docs.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Only the first line's ends are pinned while the second line is made
parallel, the way the Parallel constraint itself moves it; the distance
is then measured on the solved geometry.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Point & line and 2Lines take a text baseline or an ellipse axis as the
line; a zero value folds the points onto the first one; 2Lines turns the
second line about its start. The Properties Constraint section edits
Constraint Form (Dynamic on the *ADSK_CONSTRAINTS layer, Annotational on
the current layer), Reference (driven constraint in parentheses whose
parameter follows the measurement) and Description (stored with the
parameter and the native variable). Dynamic dimensions keep a 12 px text
and 8 px arrows at any zoom, drop trailing zeros and show formulas as
`fx: len=d1*2`; the hidden constraints layer stays out of the layer lists.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
DCFORM sets the annotational or dynamic form and continues into the
DIMCONSTRAINT option prompt, whose wording and last-used default match the
reference. -PARAMETERS manages parameters from the command line; a
double-clicked constraint dimension opens its value prompt. Dynamic
dimensions rescale on every camera change and their display overrides stay
out of the saved file. A driving dimension between an entity's own ends no
longer has its length retained, so a new value moves the second point along
the dimension axis; parameter edits hold the first constraint point.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
DCALIGNED opens with `[Object/Point & line/2Lines] <Object>`. Point & line
asks `Specify constraint point or [Line] <Line>:` then `Select line:` (or the
line first and `Select constraint point:`), measures perpendicular to the
line from the constraint point to the line end nearest to it, and stores a
directed distance with the line as direction reference. 2Lines asks
`Select first line:` and `Select second line to make parallel:`, adds a
Parallel constraint solved with the first line pinned, then measures on the
solved geometry between the nearest ends. Unsupported line picks report the
reference's message; the same measurement again reports `The constraint
already exists on the selected objects.` and ends the command; an invalid
expression reports both reference lines and asks again.
The offered default and seeded expression carry twelve significant digits;
a typed value moves the second point (or the other object) while the first
point and its measured line stay, negative values keep their sign in the
parameter and use their magnitude, zero folds the points together, and the
dynamic dimension's origins follow every solve. The lock mark sits after the
text, a selected dynamic dimension shows triangle grips at its points and the
text square, and its Properties show the Constraint section (Name and
Expression editable) plus Text rotation.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
A plain number shows as typed (d1=100), an expression under the fx: prefix
(fx: d2=d1*2); the text stays horizontal through DIMTIH/DIMTOH overrides
and the lock mark follows the text.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Every dynamic dimension gets a DIMSCALE override for 12 px text, refreshed
per zoom band, at creation and after load. A SCALE/ROTATE of an entity whose
own end points a driving dimension measures now pins its second constraint
point so the dimension moves the first end, as the reference does.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
The dynamic dimension of a dimensional constraint is now linked in the
drawing file (AcDbAssocDependency + AcDbAssocDimDependencyBody on the
constraint node), reread on load, hidden by DCHIDE/DYNCONSTRAINTDISPLAY
and never plotted; it carries a lock mark before its text. New
CONSTRAINTNAMEFORMAT and DYNCONSTRAINTDISPLAY variables and the
DIMCONSTRAINT option front end. A transformed entity whose own end points
a driving dimension measures keeps only the first constraint point, so a
scaled line returns to its dimension value.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
DCLINEAR, DCHORIZONTAL, DCVERTICAL and DCALIGNED follow the reference flow:
`Specify first constraint point or [Object] <Object>:`, `Specify second
constraint point:`, `Specify dimension line location:`, then `Dimension
text = …` and `Enter value or name and value <d1=100>:`. Linear reads
horizontal or vertical from the dimension line location the way a linear
dimension does; Object takes a line's, an arc's or a polyline segment's
ends. A miss reports `No valid constraint point found.` / `No object
found.` and asks again; another object type reports `Invalid selection for
Linear. Select a line, polyline segment or arc.`.
Each constraint creates a drawing parameter (`d1`, `d2`, …, or the typed
`name=expression`), drives the constraint through it, and draws a dynamic
dimension in constraint gray whose text follows CONSTRAINTNAMEFORMAT
(`d1=100.0000`); the dimension is associated with the constrained objects
and its text is refreshed after every solve. A typed value other than the
measured one moves the second point while the first stays, and so does a
later parameter edit. Deleting the constraint removes its dimension and,
when nothing else reads it, its parameter.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
A fresh reference session shows the "=" bar of every object made equal
through Multiple right away; the earlier hidden state was not the rule.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
A second object of the wrong kind (a circle after a line, a line after a
circle) or a pair that already carries Equal now reports and asks for the
second object again instead of ending the command. The mismatch message
names what the first object asks for — `Select a line segment, polyline
segment, text, MText, major or minor axis of ellipse or elliptical arc.`
after a length object, `Select a circle or arc.` after a radius object —
and the same-pick message carries the reference's double space.
Co-Authored-By: Claude Fable 5.1 <[email protected]>