488 Commits
Author SHA1 Message Date
724c18c6af Constraint point names: s2 names segment 2, as documented (fixes #710) (#734)
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 05:04:26 -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 <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
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 <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 05:02:28 -04:00
Brandon ThomasandClaude Opus 5.5 636b041a4e DXF writer: resolve the #827/#871 merge (W keeps both the layer handles and the hatch reactors)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 04:51:37 -04:00
Brandon ThomasandClaude Opus 5.5 bb7e1046be docs: gaps F1/F2 rows after the STRETCH and REFEDIT merges (one row each)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 04:47:56 -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 <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
2026-10-13 04:47:19 -04:00
69f2b9724a Save xref layer overrides with the host, in DXF and DWG (fixes #886) (#889)
A colour or freeze set in the host on an xref's layers (xref|layer) was lost on save:
the saved view dropped every xref-dependent symbol, layers included, and the DWG save goes
through the same DXF tags. The reader already keeps such layers when the xref loads.

The xref's layers are now written as xref-dependent LAYER records (DXF Reference, LAYER
group 70: 16 externally dependent, 32 resolved), as AutoCAD does with VISRETAIN = 1, with
the xref linetypes they use (same flags): without them a DWG falls back to Continuous.

Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 04:46:45 -04:00
28b8160407 DXF: associative hatches in blocks keep their boundary; boundaries carry the hatch reactor (#871)
A hatch inside a block was written with no source objects (the writer looked
for them in model and paper space only), and no boundary object carried the
hatch as a persistent reactor. AutoCAD keeps the two linked both ways; without
it a stretched dynamic block in AutoCAD moved the outline but not the fill.

Co-authored-by: Cody Vogt <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
2026-10-13 04:46:29 -04:00
5b037b8f92 DXF: write viewport frozen layers as group 341 layer handles too (#827)
A layout VIEWPORT's frozen layers were saved only as CADCraft's own
1001 CADCRAFT / 1000 VPFROZEN xdata. Other programs ignore that, so in
any third-party viewer every viewport showed every layer.

The writer now also emits the standard group 341: one soft pointer per
frozen layer to its LAYER table record handle, after 90/340 and before
the xdata. A frozen name with no LAYER record is skipped for 341 only
(the xdata still carries it). The reader keeps preferring the xdata; a
VIEWPORT without it (a file from another program) resolves its 341
handles through the LAYER records' group-5 handles, ignoring unknown
handles and keeping the 341 order.

Not covered: the DXF-to-DWG converter does not carry group 341 yet, so
a DWG keeps per-viewport freezing only through the CADCraft xdata.

Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
2026-10-13 04:46:15 -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 <[email protected]>

* 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 <[email protected]>

---------

Co-authored-by: Claude Sonnet 5.5 <[email protected]>
Co-authored-by: Brandon Thomas <[email protected]>
2026-10-13 04:46:00 -04:00
a6200fa34f i18n(pt-BR): complete the Brazilian Portuguese catalog (#791)
Add the 238 rows that still fell back to English, taking the catalog to
1,231 rows: it now covers the reference catalog and every marked UI
literal (commands, menus, tool groups and tooltips, object snaps,
drafting prompts, dialogs and Preferences), so the i18n tests report no
remaining gaps for pt-BR.

The translations follow the terminology already used in the catalog
(cota, hachura, camada, pinça, janela gráfica, referência a objetos) and
preserve placeholders ({n}, {name}) and trailing ellipses exactly.

Also add a bundled-font glyph test for the catalog's accented letters,
mirroring the German and Ukrainian ones, and record the completion in
docs/localization-parity.md (status line and revision history) and
docs/localization.md.

Written from CADCraft's English strings; no proprietary localization
resources were copied.

Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 04:45:43 -04:00
25e4900fcd Recent files: the Start page and File ▸ Open Recent list the drawings opened last (fixes #858) (#864)
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 04:44:44 -04:00
4efb01332e Canvas: every click places a point while drawing, however fast (fixes #815) (#835)
Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 04:42:53 -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 <[email protected]>
2026-10-13 04:38:34 -04:00
ZaxaerithandZaxaerith 591692a264 docs: clarify engine commands in control protocol (#845) (#873)
Co-authored-by: Zaxaerith <[email protected]>
2026-10-13 04:38:29 -04:00
Marco Arnulfo 50246683c3 DXF: read every ENTITIES section, not only the last (fixes #865) (#869) 2026-10-13 04:38:24 -04:00
Marco Arnulfo 2effc8bf3e Double-click on text, mtext or an attribute definition starts TEXTEDIT on it (part of #842) (#868) 2026-10-13 04:38:18 -04:00
Marco Arnulfo 5b0238fc26 Dynamic Input and grip fields show distances in the drawing's UNITS (fixes #841) (#867) 2026-10-13 04:38:13 -04:00
Marco Arnulfo 7b723b7bc0 Viewport scale list: add engineering scales for imperial drawings (fixes #851) (#866) 2026-10-13 04:38:08 -04:00
aldozarandClaude Opus 5.5 a10e43cb2a CJK text: big-font cells in SHX text, CJK interface fonts in every language (#861)
Drawing (#674): in stroke-font (SHX) text, East Asian wide characters
from a fallback font fill a square cell from the baseline to the text
height, as a big font's do, instead of being scaled by the fallback
font's Latin cap height (about 1.3-1.5x too large and too widely spaced,
so CJK labels overran their space). A line no longer ends with the
stroke font's letter gap after a fallback glyph.

Interface (#513): a CJK font is installed after the Latin one in every
interface language, not only Chinese, so Japanese or Chinese file,
layout and layer names stop showing as boxes. A Japanese font comes
first unless the interface is Chinese; a craft-fonts face embedded in
the build comes last, for systems (and the web build) without one.

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 04:38:03 -04:00
Marco Arnulfo 7e38081b54 Control channel: control.methods lists the methods, ping answers (fixes #843) (#852)
A client could only learn the top-level methods from docs/control-protocol.md;
help, methods, ping and the like all came back as "unknown method". The app
and the headless backend now answer control.methods with each method they
serve ({method, params, description}) and ping with "pong", and an unknown
method's error points to control.methods. A test keeps the app's list equal
to the doc table and checks every listed method is dispatched.
2026-10-13 04:37:57 -04:00
Marco Arnulfo 3f709bed2e Desktop: a bare --control keeps the CADCRAFT_CONTROL_PORT port (fixes #844) (#848)
`--control` as the last argument read `args.next()` as None and reset the
port taken from CADCRAFT_CONTROL_PORT, without logging anything, so
`CADCRAFT_CONTROL_PORT=47321 cadcraft --control` started no control
channel. A bare `--control` now keeps the variable's port and logs a
warning either way; a port given on the command line still wins. The
precedence is documented in docs/control-protocol.md.
2026-10-13 04:37:52 -04:00
Ray caad180e98 fix(dxf): MTEXT direction ignores the embedded object's insertion point (#667) (#834)
An R2018+ MTEXT can carry an embedded object (group 101) in which 10 is the
X-axis direction and 11 the insertion point. AutoCAD writes one for MTEXT with
column settings, and so does the DWG bridge. The reader took the first group 11
anywhere in the entity as the direction, so such text turned towards its own
insertion point. Read 11/21 and 50 from the MTEXT's own groups only.
2026-10-13 04:37:47 -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 <[email protected]>
2026-10-13 04:37:42 -04:00
46ab40d211 Keep the layout tabs inside the status bar (#821)
* Keep the layout tabs inside the status bar

With many layouts or long layout names the tabs ran under the coordinates and
the drafting toggles and off the window.

The tabs now stop before the right-hand controls, leaving room for the
coordinates: Model and "+" stay, then the run of layouts that fits, always
holding the current one. A name wider than 150 px is cut with "…" and shows in
full on hover. When some layouts don't fit, a button after the last tab lists
them all; the "Layout list" button at the left of the bar opens the same list
(it did nothing before).

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* Status bar test: expect the other layout tabs only when the bar has room

At 900 pt the layout tabs that don't fit move into the layout list (d2fe40b), so
only the current tab is painted there. The test still required "Layout2" at
every size and failed on main.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Chanthawat Kiriyadee <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 04:37:37 -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 <[email protected]>

* Move REFEDIT translation lines into the middle of the catalogs (avoids PR merge conflicts)

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 5.5 <[email protected]>
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 <[email protected]>

* Move MLEADER translation lines away from the end of the catalogs (avoids PR merge conflicts)

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 5.5 <[email protected]>
2026-10-13 04:37:26 -04:00
Valentin KleinandClaude Sonnet 5.5 ea768ee92a docs: gaps.md FF14 lists what is left of SVG import (#814)
SVG import landed in #636 but its row still said it was missing.

Co-authored-by: Claude Sonnet 5.5 <[email protected]>
2026-10-13 04:37:21 -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 <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 04:37:16 -04:00
Valentin KleinandClaude Sonnet 5.5 853b2915b6 Compare hatch pattern lines with a tolerance in normal_zoom_pattern_is_unchanged (#804) (#805)
The view-limited path differs from full detail by ~3e-16 on Windows (float noise from the rotated-frame round trip); the test now compares structure exactly and coordinates within 1e-9.

Co-authored-by: Claude Sonnet 5.5 <[email protected]>
2026-10-13 04:37:11 -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 <[email protected]>
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 <[email protected]>
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 <[email protected]>

* 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 <[email protected]>

---------

Co-authored-by: Claude Sonnet 5.5 <[email protected]>
2026-10-13 04:36:56 -04:00
Jason Brashear 89c834155d Geometry: keep vector midpoints finite at coordinate extremes (#793) 2026-10-13 04:36:51 -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
bottelliemanuele-makerandClaude Fable 5.1 ecdb8f96b2 i18n: Italian interface catalog (it.tsv) (#789)
Adds Italian as an interface language: 1,227 rows written from the
English strings with Italian desktop-CAD vocabulary (Disegna,
Tratteggio, Quota, Direttrice, layer, spazio modello/carta). Two
`menu` entries keep the menu-bar headings apart from the command and
tool-group labels: View → Visualizza (object label: Vista) and
Modify → Edita (tool group: Modifica). Italian integer plurals follow
the English rule (one, other).

Registered in i18n::LANGUAGES and Preference (code `it`), reported in
the catalog tests, with a locale/preference/plural/menu/font test;
attributed in ATTRIBUTION.md; README, ROADMAP, docs/localization.md,
docs/localization-parity.md, docs/control-protocol.md and the Options
doc comment list the language.

Co-authored-by: Claude Fable 5.1 <[email protected]>
2026-10-13 04:36:40 -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 <[email protected]>

---------

Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 04:36:35 -04:00
c0335161c3 Geometry: spline arc length converges on tight bends, so LENGTHEN shortens to the target (#786)
* Geometry: spline arc length converges on tight bends, so LENGTHEN shortens to the target (fixes #705)

* Geometry: cap adaptive spline quadrature (depth 10, 1e-10 relative) so a hostile spline can't make LENGTHEN slow

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Brandon Thomas <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 04:36:28 -04:00
Marco Arnulfo 419d8848d6 MTEXT: Exactly line spacing keeps the pitch when a line has taller text (fixes #711) (#784) 2026-10-13 04:35:52 -04:00
aldozarandClaude Opus 5.5 c781169b95 Don't give entities made while reading handles the file still uses (#783)
Another program's file can name a $HANDSEED below handles it uses (a DWG
read through the bridge did: its seed was under the handles of its
dimension blocks). The faces a polyface mesh becomes were numbered from the
seed while reading, so they could take handles of records further on in
other lists (another block); within one list duplicates were already
renumbered. A DWG keeps one object per handle, so saving one lost the
duplicates: 15 faces of a block's mesh in a permit set.

Before entities are read, every handle a file uses is now reserved. A file
CADCraft wrote names its own next handle (#495), above which its rebuilt
records are numbered, so it is left to that and resaves stay identical.

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 04:35:44 -04:00
aldozarandClaude Opus 5.5 f314d3a591 Write an unedited dimension's block as it was read (#782)
Saving regenerated every dimension's anonymous block, even dimensions read
from another program's file and never touched: the definition points went
and other programs then showed CADCraft's drawing of each dimension (a
dimension line split around its text came back whole, for instance).

A dimension still linked to the block it was read with hasn't changed
since: every edit drops the link, and the screen draws that block while it
is there. Its block is now written as read, under its name and handles;
edited and new dimensions are generated as before.

On a 1,013-dimension permit set saved DWG -> CADCraft -> DWG, every
dimension's block now matches the original (before: none).

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-13 04:35:38 -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 <[email protected]>
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 565cadaa51 Extents: cache block bounds per depth so a deep visit can't hide a shallow reference (fixes #706) (#778) 2026-10-13 04:35:20 -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
Marco Arnulfo 045212139a Geometry: fit splines with too many points use them as control points instead of a dense solve (fixes #702) (#773) 2026-10-13 04:34:56 -04:00
Marco Arnulfo 6772150bc4 Constraints: an arc solved with a negative radius is stored turned half a turn, so its points stay put (fixes #703) (#772) 2026-10-13 04:34:51 -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