feat(grips): improve direct editing
Refit arcs from fixed control points and highlight hovered grips. Let Lengthen preview from the cursor or accept a typed distance.
This commit is contained in:
parent
b744d4bf2d
commit
539d83de47
10 changed files with 421 additions and 59 deletions
|
|
@ -24,10 +24,18 @@ pub struct GripEdit {
|
|||
pub origin_world: DVec3,
|
||||
/// Last world-space cursor position (needed for incremental delta on translate drags).
|
||||
pub last_world: DVec3,
|
||||
/// How cursor movement modifies the selected grip.
|
||||
pub mode: GripEditMode,
|
||||
/// Every hot grip moved by this edit. A normal grip edit contains one target.
|
||||
pub targets: Vec<GripTarget>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum GripEditMode {
|
||||
Stretch,
|
||||
Lengthen,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GripTarget {
|
||||
pub handle: Handle,
|
||||
|
|
@ -48,6 +56,7 @@ impl GripEdit {
|
|||
grip_id,
|
||||
origin_world: world,
|
||||
last_world: world,
|
||||
mode: GripEditMode::Stretch,
|
||||
targets: vec![GripTarget {
|
||||
handle,
|
||||
grip_id,
|
||||
|
|
@ -56,6 +65,12 @@ impl GripEdit {
|
|||
}],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lengthen(handle: Handle, grip_id: usize, world: DVec3) -> Self {
|
||||
let mut edit = Self::single(handle, grip_id, false, world);
|
||||
edit.mode = GripEditMode::Lengthen;
|
||||
edit
|
||||
}
|
||||
}
|
||||
|
||||
// ── Screen-space helpers ───────────────────────────────────────────────────
|
||||
|
|
|
|||
|
|
@ -245,6 +245,57 @@ pub fn apply_grip(entity: &mut EntityType, grip_id: usize, apply: crate::scene::
|
|||
EntityTypeOps::apply_grip(entity, grip_id, apply);
|
||||
}
|
||||
|
||||
/// Rebuild an arc from its drag-start control points and the point grips moved
|
||||
/// in the current frame. Returns `None` for non-arc entities and `Some(false)`
|
||||
/// when the requested points are temporarily degenerate.
|
||||
pub fn refit_arc_grips(
|
||||
entity: &mut EntityType,
|
||||
original: &EntityType,
|
||||
edits: &[(usize, glam::DVec3)],
|
||||
) -> Option<bool> {
|
||||
let EntityType::Arc(arc) = entity else {
|
||||
return None;
|
||||
};
|
||||
let EntityType::Arc(original_arc) = original else {
|
||||
return None;
|
||||
};
|
||||
let edits = match planar_ocs_normal(original) {
|
||||
Some(normal) => edits
|
||||
.iter()
|
||||
.map(|&(grip_id, point)| {
|
||||
let (x, y, z) =
|
||||
super::transform::wcs_point_to_ocs((point.x, point.y, point.z), normal);
|
||||
(grip_id, glam::DVec3::new(x, y, z))
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
None => edits.to_vec(),
|
||||
};
|
||||
Some(crate::entities::arc::refit_grips(
|
||||
arc,
|
||||
original_arc,
|
||||
&edits,
|
||||
))
|
||||
}
|
||||
|
||||
/// Convert a world-space cursor point into the value expected by an
|
||||
/// interactive grip-menu action.
|
||||
pub fn grip_menu_point_value(
|
||||
entity: &EntityType,
|
||||
grip_id: usize,
|
||||
action: crate::scene::model::object::GripMenuAction,
|
||||
point: glam::DVec3,
|
||||
) -> Option<f64> {
|
||||
let point = match planar_ocs_normal(entity) {
|
||||
Some(normal) => {
|
||||
let (x, y, z) =
|
||||
super::transform::wcs_point_to_ocs((point.x, point.y, point.z), normal);
|
||||
glam::DVec3::new(x, y, z)
|
||||
}
|
||||
None => point,
|
||||
};
|
||||
EntityTypeOps::grip_menu_point_value(entity, grip_id, action, point)
|
||||
}
|
||||
|
||||
pub fn apply_transform(entity: &mut EntityType, t: &EntityTransform) {
|
||||
EntityTypeOps::apply_transform(entity, t);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue