Object > Path > Split Into Grid took a number of rows and columns and one gutter, and split each
selected path on its own. The dialog now has the documented options, the rows beside the columns:
number, height or width, gutter and total, with Add Guides and Preview. Several selected paths
become one grid over them all, painted as the topmost one, as documented.
object.path.splitIntoGrid takes rowGutter and columnGutter (gutter still sets both), totalHeight
and totalWidth, height and width (the size of each row and column, which sets the total) and
addGuides, which adds ruler guides along the row and column edges on the grid's layer.
Behaviour reference:
https://helpx.adobe.com/illustrator/desktop/manage-objects/edit-objects/divide-or-split-objects.html
Trim, Merge and Crop walk the arrangement once per input shape, and every walk tested each edge
side with a coverage mask built from a winding vector with one slot per input. On 300 paths,
against main:
- Trim: 362 → 31 ms
- Merge: 366 → 31 ms
- Crop: 303 → 28 ms
- Unite, Intersect, Exclude, Minus Front and Minus Back: unchanged or a little faster
- Multi, the arrangement's winding, keeps only the non-zero windings as sorted (input, winding)
pairs, added in place. A face is covered by a few inputs, so a test reads a few entries
instead of one per input. The winding arithmetic is unchanged.
- Arrangement::covered lists the inputs that cover a face (the true entries of its coverage
mask). Trim, Merge, Crop, Minus Front, Minus Back, Intersect and Exclude test that list; each
test's old mask form is in a comment beside it. mask() still builds the same mask for the rest.
pathfinder_pinned hashes the output of all ten operations on 2, 5, 12 and 30 overlapping
ellipses, rectangles and stars (even-odd and non-zero, shared keys for Merge). The 40 hashes were
computed with main's dense windings, and the new code gives every one of them. A wrong Crop test
fails it. The pathops suite (103 tests) passes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VmMmc1J8XeNLxhRihWv9cc
- Parity: Object › Path › Remove Anchor Points now runs the new command (`path.removeAnchors`,
the menu's feature name) instead of `path.deleteAnchors`, which deleted the anchors with their
segments and opened closed paths; that stays the Delete key's command ("Delete Anchor Points",
off the menu). No second "Smart" item.
- Geometry: the refit moves to `vectorcraft_pathops::remove_anchor` on the existing least-squares
fitter (fixed end tangents, a golden-section search for where the curve passes the removed
point) instead of a ~1,000-candidate grid search in geom (about 4 ms per anchor, now well under
0.1 ms). Two straight sides stay one straight side (a rectangle loses a corner and becomes a
triangle), as Illustrator does; non-finite input leaves the handles alone.
- The Delete Anchor Point tool (`path.removeAnchor`) uses the same function, replacing its
heuristic handle stretch; the explicit id/anchor and `fit` params of the new command are dropped
as duplicates of it. The command is enabled by direct-selected anchors (`has_anchors`), not a
UI override.
- The Control bar shows an icon button (the Delete Anchor Point icon, tooltip "Remove Anchor
Points") instead of a 204 pt text button; the labels reuse the translated "Remove Anchor
Points"; zh-hant gains "Delete Anchor Points". The Pen test that pinned Alt-click as plain Pen
(Illustrator's Alt over an anchor is Convert Anchor Point) is dropped.
- Tests for the refit, closed paths, straight sides and bad input; docs/mcp.md and ROADMAP.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shipped code no longer unwraps, expects or panics: every one of the 124
unwrap()/expect()/panic!/unreachable! sites outside tests now handles the
failure (Result/Option, ?, let-else, defaults) and reports errors to the user.
- Lints: workspace clippy denies unwrap_used, expect_used, panic, todo,
unimplemented and unreachable; clippy.toml allows them in tests, and
integration tests, examples and testkit opt out explicitly.
- Safety net (vectorcraft_engine::guard): a panic in a top-level command rolls
the document back and returns EngineError::Internal; a panicking tool is
reset; the MCP server answers with an internal error and keeps serving; the
UI frame and each control request are guarded.
- APIs that hid failures now return them: Rendered::to_png/to_jpeg/to_webp
return Result (JPEG/WebP errors used to write empty files),
FontDb::face returns Option, Region::top returns Option.
- Fuzzing: engine/tests/import_fuzz.rs feeds garbage, hostile and mutated SVG
and PDF through import → render → export (30k cases locally, no panics).
- Docs: AGENTS.md/CLAUDE.md rule, docs/development.md "Robustness" section,
README pointer and a PR template checklist.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The sweep compares a curve with another segment over a y-span shorter than
its tolerance by bounding boxes only, so an edge rising by less than that
tolerance (e.g. a rectangle edge cut through a circle's cap, whose computed
intersection end sits ~1e-12 off the horizontal) was mis-ordered and the
result lost a corner: xor/difference/area disagreed by up to 10%. Every
sweep input now snaps on-curve y values within the tolerance to one level
(handles follow and are levelled with their anchor), so such edges become
exact horizontals, which the sweep handles exactly.
- tests/regressions.rs: the six minimal failures found by the properties,
the root cause in isolation, and the self-crossing "star" polygon.
- The star-polygon strategy rejected no angular step of half a turn or
more, so it sometimes drew self-crossing polygons (the shoelace failure).
- Property suites run from a fixed seed (PROPTEST_CASES / PROPTEST_RNG_SEED
still override), so CI cannot fail at random.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>