Path: Remove Anchor Points is Object › Path's one item and shares the Delete Anchor Point refit (review of #241)

- 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>
This commit is contained in:
bflatastic
2026-10-08 03:27:07 +07:00
co-authored by Claude Opus 5.5
parent f5c3ecb47c
commit d5a060a009
21 changed files with 257 additions and 485 deletions
-22
View File
@@ -501,26 +501,4 @@ mod tests {
let a = click(&mut t, &cx, 325.0, 351.0, shift);
assert!(matches!(&a[..], [Action::Begin(_), Action::Preview(c, _)] if c == "path.create"), "{a:?}");
}
#[test]
fn alt_click_on_an_anchor_does_not_remove_it() {
let (d, id) = doc_with_rect();
let mut sel = Selection::default();
sel.set([id]);
let p = paint();
let cx = cx(&d, &sel, &p);
let mut t = PenTool::default();
let mods = Mods { alt: true, ..Mods::default() };
// Alt over an anchor stays the Pen. Convert Anchor Point will use this key later.
assert_eq!(t.cursor(&cx, Point::new(200.0, 100.0), mods), Cursor::Pen);
let down = t.pointer(&cx, &PointerEvent::new(PointerKind::Down, 200.0, 100.0).with_mods(mods));
let up = t.pointer(&cx, &PointerEvent::new(PointerKind::Up, 200.0, 100.0).with_mods(mods));
for act in down.iter().chain(&up) {
let name = match act {
Action::Begin(c) | Action::Preview(c, _) | Action::Exec(c, _) | Action::Dialog(c, _) => c.as_str(),
_ => "",
};
assert_ne!(name, "path.smartRemoveAnchor", "{act:?}");
}
}
}