fix(grips): compute grip positions in f64 so they sit on the wire

Grip markers drew visibly offset from the entity on large-coordinate
(UTM-scale) drawings: every Grippable impl cast the f64 entity coordinates
to f32 BEFORE the world-offset subtraction, and at 1e7 magnitude an f32
holds ~0.9 drawing units of rounding error. The wires subtract the offset
in f64 first (precision-preserving), so the grips landed up to ~1 unit
away from the geometry they belong to.

GripDef.world is now DVec3: producers fill it straight from the f64
entity data, refresh_selected_grips subtracts the world offset in f64,
and only the small offset-local result is cast to f32 for screen-space
projection (grips_to_screen / find_hit_grip) and drag state.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-06-11 00:04:37 +03:00
commit 25715d1b03
33 changed files with 898 additions and 817 deletions

View file

@ -141,7 +141,11 @@ fn to_truck(t: &Text, document: &acadrust::CadDocument) -> TruckEntity {
&t.value,
);
TruckEntity {
object: TruckObject::Text(vec![TextStroke { strokes, origin, color: None }]),
object: TruckObject::Text(vec![TextStroke {
strokes,
origin,
color: None,
}]),
snap_pts: vec![(snap_pt, SnapHint::Insertion)],
tangent_geoms: vec![],
key_vertices: vec![],
@ -150,10 +154,10 @@ fn to_truck(t: &Text, document: &acadrust::CadDocument) -> TruckEntity {
}
fn grips(t: &Text) -> Vec<GripDef> {
let p = Vec3::new(
t.insertion_point.x as f32,
t.insertion_point.y as f32,
t.insertion_point.z as f32,
let p = glam::DVec3::new(
t.insertion_point.x,
t.insertion_point.y,
t.insertion_point.z,
);
vec![square_grip(0, p)]
}
@ -316,23 +320,25 @@ impl Grippable for Text {
apply_grip(self, grip_id, apply);
}
fn grip_menu(
&self,
_grip_id: usize,
) -> Vec<crate::scene::object::GripMenuItem> {
fn grip_menu(&self, _grip_id: usize) -> Vec<crate::scene::object::GripMenuItem> {
use crate::scene::object::{GripMenuAction, GripMenuItem};
vec![
GripMenuItem { label: "Stretch", action: GripMenuAction::Stretch },
GripMenuItem { label: "Move with Text", action: GripMenuAction::MoveWithText },
GripMenuItem { label: "Rotate", action: GripMenuAction::RotateText },
GripMenuItem {
label: "Stretch",
action: GripMenuAction::Stretch,
},
GripMenuItem {
label: "Move with Text",
action: GripMenuAction::MoveWithText,
},
GripMenuItem {
label: "Rotate",
action: GripMenuAction::RotateText,
},
]
}
fn apply_grip_menu(
&mut self,
_grip_id: usize,
_action: crate::scene::object::GripMenuAction,
) {
fn apply_grip_menu(&mut self, _grip_id: usize, _action: crate::scene::object::GripMenuAction) {
// Move-with-Text falls through to Stretch (single grip moves
// the whole text); Rotate needs a follow-up angle handled by
// `apply_grip_menu_value`.