Commit Graph
243 Commits
Author SHA1 Message Date
5d39f8710c HATCHEDIT: choosing SOLID on a gradient hatch makes it a plain solid fill (fixes #721) (#740)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 05:07:46 -04:00
6394c7c6f3 JOIN: an elliptical arc named twice is one object, so the joined result stays (fixes #725) (#739)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 05:07:02 -04:00
2483993218 HATCH: a pattern name with no definition is refused instead of drawn as ANSI31 (fixes #722) (#736)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 05:06:15 -04:00
cc57dff527 POLYGON: a typed radius of zero or less, or a radius point on the centre, is refused and asked again (fixes #720) (#735)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 05:05:37 -04:00
8e0b867f6c BREAK, BREAKATPOINT and JOIN: leave objects on locked layers alone (fixes #727) (#730)
BREAK and BREAKATPOINT (break_entity) and line/arc/polyline JOIN
(modify::join) removed their source objects and added replacements
without checking the source layer's lock, so a locked line could be cut
or merged into a polyline. ERASE, MOVE, TRIM, FILLET, EXPLODE and the
ellipse/spline JOIN already guard against this.

Both now refuse with the same errors the sibling commands use:
"The object is on a locked layer." (BREAK, BREAKATPOINT, like FILLET)
and "An object is on a locked layer." (JOIN, like the ellipse/spline
join). JOIN refuses the whole request when any selected object is
locked, so a mixed-layer pair keeps its locked original in either
order. The guards sit in the shared functions, so JSON calls with
explicit handles or the selection, the interactive prompts and the
command line all reach them. The interactive commands report the
refusal on the command line.

Tests (crates/engine/tests/break_join_locked_layers.rs, red before the
fix): BREAK and BREAKATPOINT on a locked line by handle and by
selection; BREAK on a locked arc and circle; JOIN of locked lines and
of a locked/unlocked pair in both orders; interactive BREAK and JOIN.
Each checks the drawing is unchanged while locked, and that the same
edit works unlocked (BREAK also undoes and redoes).

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 05:03:16 -04:00
36f938e90a Performance: restrict object-snap intersections to cursor aperture (#701)
* Snap: pin finite and apparent intersection behavior

* Snap: skip finite intersections outside the aperture

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 05:02:28 -04:00
f807e65e30 STRETCH: polygon and fence selection (#892)
At "Select objects", CP and WP take a polygon (Enter closes it) whose
inside marks the vertices that move, as a crossing window does; F takes a
fence, and what it crosses moves whole, like objects picked one at a
time. BOX works too, Undo takes back the last point, and the polygon or
fence is drawn while its points are placed.

The JSON form takes `polygon` or `fence` in place of `window`; both are
capped at the selection modes' point limit and refuse non-finite points.

Co-authored-by: Chanthawat Kiriyadee <enwuft@icloud.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-13 04:47:19 -04:00
5fd23f75fc Command line: a bare system variable name runs SETVAR on it (part of U10) (#799)
* Command line: a bare system variable name runs SETVAR on it (part of U10)

Typing ORTHOMODE, PICKADD and the like at the command line returned
"unknown command". Session::start now falls back to SETVAR with the name
already entered when the text is not a command but is a known variable;
dash, dot and underscore prefixes never mean a variable, and real
commands still win. Read-only variables print their value, and the
transparent form ('OSMODE) resumes the interrupted command.

Checked: fmt, clippy, test, assets, layers and wasm pass; also driven
through the control channel in the running app.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Tests: every variable name, command collisions and hostile input for bare SETVAR

Covers each variable SETVAR lists: a name that is not a command starts SETVAR
(or prints a read-only value), a name that is also a command keeps the command,
and odd input (lone apostrophes, NUL, wide characters, a 1 MiB name) never
panics and leaves the session usable. Disabling the fix makes all three new
and old tests fail.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-13 04:46:00 -04:00
mattlafyandClaude Opus 5.5 d134079f11 Xdata travels with its object: COPY, MIRROR, ARRAY and paste keep it (#890)
Other applications' xdata on an entity was kept beside the drawing,
keyed by handle, so a copy (new handle) lost it: a copied hyperlink
(PE_URL) had no link, third-party tags stayed on the original only.
In AutoCAD xdata is part of the object.

Move entity xdata onto the entity as Common::xdata (the same raw
groups); every copy path already clones Common. The DXF reader puts it
there (handle references still noted for remapping), the writer takes
it from the entity, PDF hyperlinks come from the entities. EXPLODE's
pieces of an object don't inherit its xdata. Table record and block
xdata stay in Foreign.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 04:38:34 -04:00
Valentin KleinandClaude Sonnet 5.5 80ec2dcc60 Ctrl+Z / U during LINE, PLINE... removes the last segment instead of the whole command (#750) (#831)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 04:37:42 -04:00
Valentin KleinandClaude Sonnet 5.5 9464945f82 REFEDIT, REFSET and REFCLOSE: edit block references in place (#818)
* 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>
2026-10-13 04:37:31 -04:00
Valentin KleinandClaude Sonnet 5.5 3dd678ff3d MLEADEREDIT, MLEADERALIGN, MLEADERCOLLECT (#816)
* 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>
2026-10-13 04:37:26 -04:00
5ce44acfb2 Pick dimensions and multileaders anywhere on their text (#807)
Plain TEXT and MTEXT are picked anywhere inside their box, but a
dimension or multileader was only found near its lines: its hit geometry
is built without text. Hovering or clicking the words of a dimension found
nothing (on a survey plan, 2 of 34 letters of a dimension's text).

A point inside the box around the words, turned with the text, now picks
the object. A dimension with a block, as AutoCAD saves them, is drawn
from that block, so its text box comes from the TEXT and MTEXT in the
block, not from the text the dimension's own geometry would place (on the
same plan that was a different place, eight times smaller). A
multileader's text box comes from its MTEXT layout.

Co-authored-by: Cody Vogt <18035288+codyvogt@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 04:37:16 -04:00
Valentin KleinandClaude Sonnet 5.5 0b92b59fcd Open drawings on a worker thread with an Opening... indicator (#694) (#797)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 04:37:06 -04:00
Valentin KleinandClaude Sonnet 5.5 f26588a357 PEDIT: pre-selected line or arc asks to turn it into a polyline (#745) (#796)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 04:37:01 -04:00
Valentin KleinandClaude Sonnet 5.5 8073453d86 BOUNDARY: cap point list and aggregate output per call (#723) (#795)
* BOUNDARY: cap point list and aggregate output per call (#723)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* BOUNDARY: a call over the output budget restores the drawing

The session does not roll back a command that returns an error, so the
polylines created before the cap was hit stayed in the drawing.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 04:36:56 -04:00
Marco Arnulfo 14343212a9 Zoom Window: the opposite corner ignores ortho, so the window stays a rectangle (fixes #787) (#790) 2026-10-13 04:36:46 -04:00
4c63ba1470 LINE: resolve deferred TAN first point with typed @distance<angle> (#788)
* LINE: resolve deferred TAN first point with typed @distance<angle>

* LINE: collapse the nested if-let (clippy collapsible_if)

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>
2026-10-13 04:36:35 -04:00
aldozarandClaude Opus 5.5 e9d8462828 Keep the ACIS geometry of 3D solids, regions and bodies on save (ACDSDATA) (#781)
From AutoCAD 2013 on, a 3DSOLID, REGION or BODY doesn't carry its ACIS
geometry: the binary SAB lives in the file's data store section (ACDSDATA),
one ACDSRECORD per entity bound by a 320 handle. CADCraft kept those
entities (as unknown entities, with their handles) but dropped the section,
so a drawing saved as DWG or DXF had empty solids, and saving reported them
as not saved.

- doc: Foreign::data_store keeps the section's groups as read;
  data_store_entities() lists the entities it has records for.
- io: the reader keeps the section; the writer puts it back for files of
  2013 and later (and in the DXF the DWG bridge converts, which acadrust
  reads into the DWG), without the records of entities no longer written.
  Nothing is written for older files or when no record's entity remains.
- engine: not_saved_as(d, version): from 2013 a solid, region or body with a
  data store record isn't reported; saves and document.bytes pass the version
  being written.

On a 39,600-object permit set with 625 3D solids and 2 regions, DWG ->
CADCraft -> DWG now keeps all 627 bodies with byte-identical SAB (before:
none), and the save no longer reports them.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 04:35:31 -04:00
Marco Arnulfo 6ab800e64c Engine: NEW and OPEN end a command left running in the previous drawing (fixes #715) (#780)
A command started in one drawing kept running after a programmatic NEW or OPEN made another
drawing current. Finishing it there recorded an undo step holding the first drawing, so undo in
the new drawing brought the other drawing back. Session::new_drawing and open_drawing now end a
running command before the new drawing becomes current, as CLOSE and document.switch already do
and as starting NEW from the command line did: its undo step lands in the drawing it started in.
With no command running, nothing changes (the previous drawing keeps its selection).
2026-10-13 04:35:26 -04:00
Marco Arnulfo bca698a588 SPLINE: cap programmatic control points like spline.cv (fixes #719) (#776) 2026-10-13 04:35:14 -04:00
Marco Arnulfo 5de2324973 Selection: rebuild the spatial index when a layer used inside blocks is hidden or shown (fixes #716) (#775) 2026-10-13 04:35:08 -04:00
Marco Arnulfo 266ee7e6ea Autosave: a write that failed is tried again without another change (fixes #717) (#774)
The planner marked a drawing as autosaved when it dispatched the write, and the background
worker only logged a failure. An unchanged drawing whose write failed was then never written
again, even once the folder became writable. The worker now reports whether the file was
written; on a failure (or a thread that could not be spawned) the drawing is no longer counted as
autosaved, so the next plan restarts its SAVETIME clock and tries again.
2026-10-13 04:35:02 -04:00
NetterSilver b2ba585251 TRIM: a pick after a closed polyline's last cut keeps only the complementary run (#726) (#771)
* TRIM: a pick after a closed polyline's last cut keeps only the complementary run (#726)

With no cutting intersection past the pick, trim_polyline used the first cut
plus the perimeter as the end of the piece and then kept the run from the
first cut to the last cut plus a whole perimeter, so one extra circuit of the
outline stayed (a 4 x 4 square became an open polyline of length 24 instead of
8). The kept run now ends at the last cut before the pick.

* Docs: update the progress docs for this change
2026-10-13 04:34:46 -04:00
Marco Arnulfo f5d58913cc CIRCLE: a radius point on the centre is refused and asked again (follow-up to #735) (#761) 2026-10-13 04:34:25 -04:00
Marco Arnulfo 5ce1ea3dfc POLYGON: an Edge second endpoint on the first is refused and asked again (follow-up to #735) (#760) 2026-10-13 04:34:19 -04:00
5183f63bc5 Hatch and Gradient dialog (create and edit) (#753)
* HATCH/GRADIENT: points and objects in one call; GRADIENT name and centered

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* HATCHEDIT: gradient parameter (make or change a gradient fill)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* HATCHPICK: pick hatch boundaries, an origin or hatches for the dialog

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hatch dialog: state, defaults and the OK command call

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hatch dialog: pick points, objects, origin or hatch and come back

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hatch and Gradient dialog window (pattern swatches, gradient, origin, boundaries, options)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* HATCH, GRADIENT and HATCHEDIT open the hatch dialog; double-click a hatch to edit; HPDLGMODE

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hatch dialog: keep the window to its content (OK and Cancel stayed off screen); double-click test

A vertical separator between the two columns took the height available, so the window grew
every frame until its buttons left the screen. Found in the running app.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Docs: hatch dialogs in gaps, target-app parity and UI parity

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hatch dialog review fixes

- Double-clicking a hatch at its centre opened the dialog and also started a grip edit.
- Edit mode no longer clamps an out-of-range scale or angle into a change nobody made.
- HPORIGINMODE outside 1-5 means the current origin, as HATCH reads it.
- Picks made in one space are dropped when the dialog comes back in another (layout tab).
- A gradient hatch's Pattern tab offers the current pattern (HPNAME), not SOLID.
- Ukrainian: "Default to boundary extents" said "outside the boundary".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: lloyd <lloyd@stackworx.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 04:34:09 -04:00
cyfung1031 bcd6322ee9 Plotting: honor model-space center and X/Y offsets (#751)
* plot: add bounded model-space paper placement

* plot: expose center and paper offset parameters

* ui: add model-space Plot offset controls
2026-10-13 04:34:04 -04:00
Marco Arnulfo e71e17a8df View: refuse a view that maps to an infinite viewport view, keeping the viewport (fixes #714) (#749) 2026-10-13 04:33:59 -04:00
Marco Arnulfo 08cfbd5dd7 Select: pick a SOLID inside its fill, not its bounding rectangle (fixes #718) (#747) 2026-10-13 04:33:52 -04:00
cyfung1031andClaude Opus 5.5 890f7f1c6f Performance: reuse nearby snap geometry for tracking acquisition (#698)
Squash of PR #698 by @cyfung1031.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 03:35:13 -04:00
aldozarandClaude Opus 5.5 0675648de8 Hatch: pick the pattern from swatches instead of typing its name (fixes #669) (#679)
Squash of PR #679 by @aldozar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 03:21:49 -04:00
aldozarandClaude Opus 5.5 c2f8782cc2 Plot dialog: device, plot style table, Window <, and a preview of its settings (#673)
Squash of PR #673 by @aldozar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 03:21:33 -04:00
aldozarandClaude Opus 5.5 d365b60704 MIRROR and PASTE previews on the GPU; GPU previews in layouts too (#655)
Squash of PR #655 by @aldozar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 03:21:18 -04:00
LionandClaude Opus 5.5 935cb98eed SCRIPT command: run .scr files from the command line, menus and JSON (gaps.md E2) (#693)
Squash of PR #693 by @Lion-1209.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 03:13:51 -04:00
rangoDJandClaude Opus 5.5 875f99d26f Deduplicate identical boundary loops to prevent empty hatch fills (#671)
Squash of PR #671 by @rangoDJ.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 03:13:20 -04:00
Jason BrashearandClaude Opus 5.5 bc6dc997ef AUNITS: degrees/minutes/seconds angles round at the displayed precision (#672)
Squash of PR #672 by @webdevtodayjason.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 03:11:42 -04:00
aldozarandClaude Opus 5.5 c57879a5c8 GPU errors and device loss: keep running, autosave at once, tell the user (#652)
Squash of PR #652 by @aldozar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 20:42:45 -04:00
Gert Pellin - GPEandClaude Opus 5.5 f7c6293d09 feat: SVG import — read SVG and SVGZ into native entities (#636)
Squash of PR #636 by @switch87.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 20:11:22 -04:00
Valentin KleinandClaude Opus 5.5 89064fd82a Drafting/plot/UI follow-ups: PolarSnap over isometric snap, MVIEW Restore, plot margins, PNG/SVG pens, PE_URL links, OPTIONS settings (part of #626) (#633)
Squash of PR #633 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 20:11:06 -04:00
aldozarandClaude Opus 5.5 1e1f68bf40 Fix fatal wgpu buffer overflow; draw MOVE/COPY/ROTATE/SCALE previews and the selection highlight on the GPU (#642)
Squash of PR #642 by @aldozar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 20:10:51 -04:00
aldozarandClaude Opus 5.5 135c928fea Hatches: draw the pattern definition stored in the file; scale library patterns in metric drawings (#643)
Squash of PR #643 by @aldozar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:54:18 -04:00
Valentin KleinandClaude Opus 5.5 9477f37503 File-format follow-ups: version-gated MULTILEADER and DIMSTYLE groups, kept $DWGCODEPAGE, PURGE multiline styles (#632)
Squash of PR #632 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:54:03 -04:00
MarekSpodBiedryandClaude Opus 5.5 83b8a84050 Add PTYPE as an alias of the Point Style command (#622) (#645)
Squash of PR #645 by @MarekSpodBiedry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:52:37 -04:00
PedroGuilleandClaude Opus 5.5 f967dc7aca Persist SNAPUNIT and GRIDUNIT in DXF (fix #607) (#614)
Squash of PR #614 by @PedroGuille.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:28:56 -04:00
Valentin KleinandClaude Opus 5.5 e1e61a13b5 feat(modify): SPLINEDIT Join, Edit vertex Add and Elevate order (#559)
Squash of PR #559 by @vangel76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:28:41 -04:00
MarekSpodBiedryandClaude Opus 5.5 5ef32b3afa Select: pick pattern hatches on their visible strokes (#489) (#599)
Squash of PR #599 by @MarekSpodBiedry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:28:14 -04:00
MarekSpodBiedryandClaude Opus 5.5 04aa716920 Page Setup: report unsupported layout plot areas as not available yet (#491) (#597)
Squash of PR #597 by @MarekSpodBiedry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:28:00 -04:00
MarekSpodBiedryandClaude Opus 5.5 41c3c83fb9 AREA: refuse an open elliptical arc instead of measuring the whole ellipse (#487) (#601)
Squash of PR #601 by @MarekSpodBiedry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:04:40 -04:00
MarekSpodBiedryandClaude Opus 5.5 0b5a0a2eb8 Plot: apply an explicit scale to non-fitted layout plots (#490) (#598)
Squash of PR #598 by @MarekSpodBiedry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:04:10 -04:00