forked from 1b-agent/opencadstudio-upstream
feat(ellipse): add complete grip editing
This commit is contained in:
commit
0f250bb485
5 files changed
+193
-92
No files matched your search
@@ -101,10 +101,8 @@ pub struct GripDef {
|
||||
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]>,
|
||||
/// World-space marker direction, projected with the grip position.
|
||||
pub dir: Option<glam::DVec3>,
|
||||
/// World-space axis that constrains this grip's drag.
|
||||
pub axis: Option<glam::DVec3>,
|
||||
}
|
||||
|
||||
+37
-9
@@ -78,6 +78,10 @@ impl GripEdit {
|
||||
|
||||
// ── Screen-space helpers ───────────────────────────────────────────────────
|
||||
|
||||
fn marker_direction(from: Vec2, to: Vec2) -> [f32; 2] {
|
||||
[to.x - from.x, from.y - to.y]
|
||||
}
|
||||
|
||||
/// Project a slice of `GripDef`s to screen space.
|
||||
/// Returns `(grip_id, screen_pos, is_midpoint, shape)` for each grip.
|
||||
pub fn grips_to_screen(
|
||||
@@ -91,11 +95,18 @@ pub fn grips_to_screen(
|
||||
// Project from the f64 grip position via the relative-to-eye path so
|
||||
// the grip stays glued to the wire at UTM-scale coordinates (an
|
||||
// `as_vec3` cast first would quantize it ~0.5 m off at high zoom).
|
||||
let screen = match camera.project(g.world, bounds) {
|
||||
let projected = camera.project(g.world, bounds);
|
||||
let screen = match projected {
|
||||
Some(p) => Point::new(bounds.x + p.x, bounds.y + p.y),
|
||||
None => Point::new(f32::NAN, f32::NAN),
|
||||
};
|
||||
(g.id, screen, g.is_midpoint, g.shape, g.dir)
|
||||
let dir = g.dir.and_then(|dir| {
|
||||
Some(marker_direction(
|
||||
projected?,
|
||||
camera.project(g.world + dir, bounds)?,
|
||||
))
|
||||
});
|
||||
(g.id, screen, g.is_midpoint, g.shape, dir)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@@ -110,14 +121,24 @@ pub fn grips_to_screen_paper(
|
||||
half_h: f32,
|
||||
bounds: Rectangle,
|
||||
) -> Vec<(usize, Point, bool, GripShape, Option<[f32; 2]>)> {
|
||||
let project = |world: DVec3| {
|
||||
Vec2::new(
|
||||
(world.x as f32 - tx + half_w) / (2.0 * half_w) * bounds.width,
|
||||
(ty + half_h - world.y as f32) / (2.0 * half_h) * bounds.height,
|
||||
)
|
||||
};
|
||||
grips
|
||||
.iter()
|
||||
.map(|g| {
|
||||
let screen = Point::new(
|
||||
(g.world.x as f32 - tx + half_w) / (2.0 * half_w) * bounds.width,
|
||||
(ty + half_h - g.world.y as f32) / (2.0 * half_h) * bounds.height,
|
||||
);
|
||||
(g.id, screen, g.is_midpoint, g.shape, g.dir)
|
||||
let projected = project(g.world);
|
||||
let screen = Point::new(projected.x, projected.y);
|
||||
let dir = g.dir.map(|dir| {
|
||||
[
|
||||
dir.x as f32 / (2.0 * half_w) * bounds.width,
|
||||
dir.y as f32 / (2.0 * half_h) * bounds.height,
|
||||
]
|
||||
});
|
||||
(g.id, screen, g.is_midpoint, g.shape, dir)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@@ -207,11 +228,18 @@ pub fn grips_to_screen_rte(
|
||||
grips
|
||||
.iter()
|
||||
.map(|g| {
|
||||
let screen = match project_rte(g.world, view_rot, eye, bounds) {
|
||||
let projected = project_rte(g.world, view_rot, eye, bounds);
|
||||
let screen = match projected {
|
||||
Some(p) => Point::new(bounds.x + p.x, bounds.y + p.y),
|
||||
None => Point::new(f32::NAN, f32::NAN),
|
||||
};
|
||||
(g.id, screen, g.is_midpoint, g.shape, g.dir)
|
||||
let dir = g.dir.and_then(|dir| {
|
||||
Some(marker_direction(
|
||||
projected?,
|
||||
project_rte(g.world + dir, view_rot, eye, bounds)?,
|
||||
))
|
||||
});
|
||||
(g.id, screen, g.is_midpoint, g.shape, dir)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user