refactor(grip): square-only marker set + oriented stretch handles

Phase 1 of bringing the grip vocabulary in line with the standard
CAD convention: drop the per-position-type shape encoding (Diamond
for translate, Circle for parameter) and use a plain square for
every endpoint / vertex / centre grip. The behavioural midpoint vs
vertex distinction stays — it lives on `GripDef::is_midpoint` and
drives `Translate` vs `Absolute` in the grip-edit dispatcher — only
the marker shape collapses.

- `GripShape` keeps `Square`, `Rectangle`, `Triangle`. Diamond /
  Circle are gone.
- `GripDef` gains `dir: Option<[f32; 2]>` — a world-XY direction
  vector consumed by `Rectangle` to orient the box along its
  segment.
- `entities::common` exposes `square_grip`, `center_grip` (same
  square marker, flagged as translate), `rectangle_grip(id, world,
  dir)` for oriented mid-segment handles, and a kept-for-Phase-2
  `triangle_grip`.
- `overlay::GripMarker` / `grips_to_screen[_paper]` thread `dir`
  through to the canvas painter; the Rectangle path rotates the
  box around the grip centre using the world-XY direction (flipping
  the sin for screen-Y).

Every existing `diamond_grip(id, w)` call becomes `center_grip(id,
w)` — the visual change is square-replacing-diamond at line
midpoints / arc midpoints / circle centres / ellipse centres /
viewport / hatch loop centroids / dimension grips / image corners /
multileader / ray / underlay / ole2frame / solid3d.

`LwPolyline` grows a stretch handle on every segment (straight or
arc), drawn as the new oriented rectangle. The grip-edit path
translates both segment endpoints for straight segments and
adjusts the arc bulge from the new midpoint for arc segments.
This commit is contained in:
Hakan Seven 2026-05-29 02:07:34 +03:00
commit 5755c2e130
20 changed files with 184 additions and 133 deletions

View file

@ -36,7 +36,7 @@ pub fn grips_to_screen(
grips: &[GripDef],
view_proj: Mat4,
bounds: Rectangle,
) -> Vec<(usize, Point, bool, GripShape)> {
) -> Vec<(usize, Point, bool, GripShape, Option<[f32; 2]>)> {
grips
.iter()
.map(|g| {
@ -45,7 +45,7 @@ pub fn grips_to_screen(
bounds.x + (ndc.x + 1.0) * 0.5 * bounds.width,
bounds.y + (1.0 - ndc.y) * 0.5 * bounds.height,
);
(g.id, screen, g.is_midpoint, g.shape)
(g.id, screen, g.is_midpoint, g.shape, g.dir)
})
.collect()
}
@ -59,7 +59,7 @@ pub fn grips_to_screen_paper(
half_w: f32,
half_h: f32,
bounds: Rectangle,
) -> Vec<(usize, Point, bool, GripShape)> {
) -> Vec<(usize, Point, bool, GripShape, Option<[f32; 2]>)> {
grips
.iter()
.map(|g| {
@ -67,7 +67,7 @@ pub fn grips_to_screen_paper(
(g.world.x - tx + half_w) / (2.0 * half_w) * bounds.width,
(ty + half_h - g.world.y) / (2.0 * half_h) * bounds.height,
);
(g.id, screen, g.is_midpoint, g.shape)
(g.id, screen, g.is_midpoint, g.shape, g.dir)
})
.collect()
}

View file

@ -51,23 +51,23 @@ pub struct PropSection {
// ── Grip types ─────────────────────────────────────────────────────────────
/// Visual marker shape for a grip point. The complete vocabulary used
/// across entity types:
/// * `Square` — vertex / endpoint that moves a single point.
/// * `Rectangle` — direction-aware mid-segment stretch (polyline
/// straight segments, dimension extension lines).
/// * `Diamond` — midpoint of a curve / centre of a closed shape (drags
/// the whole shape or stretches the midpoint).
/// * `Triangle` — directional control (rotate / add vertex / continue).
/// * `Circle` — parametric control (radius / dimension value).
/// Visual marker shape for a grip point. The complete vocabulary that
/// matches the standard CAD grip conventions:
/// * `Square` — endpoint / vertex / centre. Drag → moves a single
/// point or translates the entity.
/// * `Rectangle` — direction-aware mid-segment stretch handle.
/// Drawn as a small box rotated along `dir` (the in-plane segment
/// direction in world XY). Used for polyline / wipeout / image /
/// dimension segment midpoints.
/// * `Triangle` — directional indicator (Phase 2: dynamic-block
/// parameters, dimension reverse-arrow flips, multi-functional
/// hover popups).
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[allow(dead_code)]
pub enum GripShape {
Square,
Rectangle,
Diamond,
Triangle,
Circle,
}
/// Describes one grip point for an entity.
@ -77,11 +77,15 @@ pub struct GripDef {
pub id: usize,
/// World-space position of the grip.
pub world: Vec3,
/// `true` → midpoint grip (diamond, translates whole object).
/// `false` → endpoint grip (square, moves a single vertex).
/// `true` → midpoint / centre grip (drags the whole shape).
/// `false` → endpoint / vertex grip (moves a single point).
pub is_midpoint: bool,
/// Visual marker shape for the grip.
pub shape: GripShape,
/// World-XY direction vector used to orient a `Rectangle` grip
/// along its segment. `None` for shapes that don't need rotation
/// (Square, Triangle in non-directional contexts).
pub dir: Option<[f32; 2]>,
}
/// How to apply a grip drag result.