Skip to content

Commit 1dc87e4

Browse files
committed
Fix Tab to switch handles
1 parent e022fbb commit 1dc87e4

3 files changed

Lines changed: 55 additions & 24 deletions

File tree

editor/src/messages/tool/common_functionality/shape_editor.rs

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::f64::consts::PI;
2+
13
use super::graph_modification_utils::merge_layers;
24
use super::snapping::{SnapCache, SnapCandidatePoint, SnapData, SnapManager, SnappedPoint};
35
use super::utility_functions::{adjust_handle_colinearity, calculate_bezier_bbox, calculate_segment_angle, restore_g1_continuity, restore_previous_handle_position};
@@ -892,16 +894,20 @@ impl ShapeState {
892894
ManipulatorPointId::Anchor(point) => self.move_anchor(point, &vector_data, delta, layer, None, responses),
893895
ManipulatorPointId::PrimaryHandle(segment) => {
894896
self.move_primary(segment, delta, layer, responses);
895-
if let Some(handles) = point.get_handle_pair(&vector_data) {
896-
let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false };
897-
responses.add(GraphOperationMessage::Vector { layer, modification_type });
897+
if let Some(handle) = point.as_handle() {
898+
if let Some(handles) = vector_data.colinear_manipulators.iter().find(|handles| handles[0] == handle || handles[1] == handle) {
899+
let modification_type = VectorModificationType::SetG1Continuous { handles: *handles, enabled: false };
900+
responses.add(GraphOperationMessage::Vector { layer, modification_type });
901+
}
898902
}
899903
}
900904
ManipulatorPointId::EndHandle(segment) => {
901905
self.move_end(segment, delta, layer, responses);
902-
if let Some(handles) = point.get_handle_pair(&vector_data) {
903-
let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false };
904-
responses.add(GraphOperationMessage::Vector { layer, modification_type });
906+
if let Some(handle) = point.as_handle() {
907+
if let Some(handles) = vector_data.colinear_manipulators.iter().find(|handles| handles[0] == handle || handles[1] == handle) {
908+
let modification_type = VectorModificationType::SetG1Continuous { handles: *handles, enabled: false };
909+
responses.add(GraphOperationMessage::Vector { layer, modification_type });
910+
}
905911
}
906912
}
907913
}
@@ -1028,8 +1034,8 @@ impl ShapeState {
10281034
/// If both or neither handles are selected, the angle of both handles will be averaged from their current angles, weighted by their lengths.
10291035
/// Assumes all selected manipulators have handles that are already not colinear.
10301036
///
1031-
/// For vector meshes, the handle which is nearest in the direction of 180° angle separation, becomes colinear with current handle,
1032-
/// and if that handle was colinear with some other handle that constraint is removed from the vector data
1037+
/// For vector meshes, non colinear handle which is nearest in the direction of 180° angle separation, becomes colinear with current handle,
1038+
/// if there is no such handle, nothing happens
10331039
pub fn convert_selected_manipulators_to_colinear_handles(&self, responses: &mut VecDeque<Message>, document: &DocumentMessageHandler) {
10341040
let mut skip_set = HashSet::new();
10351041

@@ -1039,9 +1045,6 @@ impl ShapeState {
10391045
};
10401046
let transform = document.metadata().transform_to_document_if_feeds(layer, &document.network_interface);
10411047

1042-
log::info!("reaching hereeeeee");
1043-
1044-
// TODO: A point which has
10451048
for &point in layer_state.selected_points.iter() {
10461049
// Skip a point which has more than 2 segments connected (vector meshes)
10471050
if let ManipulatorPointId::Anchor(anchor) = point {
@@ -1050,21 +1053,17 @@ impl ShapeState {
10501053
}
10511054
}
10521055

1053-
// let Some(handles) = point.get_handle_pair(&vector_data) else { continue };
1054-
10551056
// Here we take handles as the current handle and the most opposite non-colinear-handle
10561057

10571058
let is_handle_non_colinear = |handle: HandleId| -> bool { !(vector_data.colinear_manipulators.iter().any(|&handles| handles[0] == handle || handles[1] == handle)) };
10581059

1059-
log::info!("reaching here");
10601060
let other_handles = match point {
10611061
ManipulatorPointId::Anchor(_) => point.get_handle_pair(&vector_data),
10621062
_ => {
1063-
// something
10641063
point.get_all_connected_handles(&vector_data).and_then(|handles| {
10651064
let mut non_colinear_handles = handles.iter().filter(|&handle| is_handle_non_colinear(*handle)).clone().collect::<Vec<_>>();
10661065

1067-
// Now sort these by angle from the current handle
1066+
// Sort these by angle from the current handle
10681067
non_colinear_handles.sort_by(|&handle_a, &handle_b| {
10691068
let anchor = point.get_anchor_position(&vector_data).expect("No anchor position for handle");
10701069
let orig_handle_pos = point.get_position(&vector_data).expect("No handle position");
@@ -1567,9 +1566,11 @@ impl ShapeState {
15671566
responses.add(GraphOperationMessage::Vector { layer, modification_type });
15681567
}
15691568
}
1570-
} else if let Some(handles) = point.get_handle_pair(&vector_data) {
1571-
let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false };
1572-
responses.add(GraphOperationMessage::Vector { layer, modification_type });
1569+
} else if let Some(handle) = point.as_handle() {
1570+
if let Some(handles) = vector_data.colinear_manipulators.iter().find(|handles| handles[0] == handle || handles[1] == handle) {
1571+
let modification_type = VectorModificationType::SetG1Continuous { handles: *handles, enabled: false };
1572+
responses.add(GraphOperationMessage::Vector { layer, modification_type });
1573+
}
15731574
}
15741575
}
15751576
}
@@ -1779,9 +1780,40 @@ impl ShapeState {
17791780
if point.as_anchor().is_some() {
17801781
continue;
17811782
}
1782-
if let Some(handles) = point.get_handle_pair(&vector_data) {
1783-
// handle[0] is selected, handle[1] is opposite / mirror handle
1784-
handles_to_update.push((layer, handles[0].to_manipulator_point(), handles[1].to_manipulator_point()));
1783+
1784+
if let Some(other_handles) = point.get_all_connected_handles(&vector_data) {
1785+
// Find the next closest handle in the clockwise sense
1786+
let mut candidates = other_handles.clone();
1787+
candidates.sort_by(|&handle_a, &handle_b| {
1788+
let anchor = point.get_anchor_position(&vector_data).expect("No anchor position for handle");
1789+
let orig_handle_pos = point.get_position(&vector_data).expect("No handle position");
1790+
1791+
let a_pos = handle_a.to_manipulator_point().get_position(&vector_data).expect("No handle position");
1792+
let b_pos = handle_b.to_manipulator_point().get_position(&vector_data).expect("No handle position");
1793+
1794+
let v_orig = (orig_handle_pos - anchor).normalize_or_zero();
1795+
1796+
let v_a = (a_pos - anchor).normalize_or_zero();
1797+
let v_b = (b_pos - anchor).normalize_or_zero();
1798+
1799+
let signed_angle = |base: DVec2, to: DVec2| -> f64 {
1800+
let angle = base.angle_to(to);
1801+
let cross = base.perp_dot(to);
1802+
1803+
if cross < 0.0 { 2.0 * PI - angle } else { angle }
1804+
};
1805+
1806+
let angle_a = signed_angle(v_orig, v_a);
1807+
let angle_b = signed_angle(v_orig, v_b);
1808+
1809+
angle_a.partial_cmp(&angle_b).unwrap_or(std::cmp::Ordering::Equal)
1810+
});
1811+
1812+
if candidates.is_empty() {
1813+
continue;
1814+
}
1815+
1816+
handles_to_update.push((layer, *point, candidates[0].to_manipulator_point()));
17851817
}
17861818
}
17871819
}

editor/src/messages/tool/tool_messages/path_tool.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -891,7 +891,6 @@ impl PathToolData {
891891
if is_colinear {
892892
shape_editor.disable_colinear_handles_state_on_selected(&document.network_interface, responses);
893893
} else {
894-
// Convert to colinear only if
895894
shape_editor.convert_selected_manipulators_to_colinear_handles(responses, document);
896895
}
897896
self.toggle_colinear_debounce = true;

node-graph/gcore/src/vector/vector_data.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ impl ManipulatorPointId {
572572
}
573573
ManipulatorPointId::EndHandle(segment) => {
574574
let point = vector_data.segment_domain.segment_end_from_id(segment)?;
575-
let current = HandleId::primary(segment);
575+
let current = HandleId::end(segment);
576576
Some(vector_data.segment_domain.all_connected(point).filter(|&value| value != current).collect::<Vec<_>>())
577577
}
578578
}

0 commit comments

Comments
 (0)