Skip to content

Add Spline tool test for drawing with PTZ applied to the canvas view #2573

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Apr 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2800,7 +2800,7 @@ mod document_message_handler_tests {
let document = editor.active_document();
for layer in document.metadata().all_layers() {
if let Some(bbox) = document.metadata().bounding_box_viewport(layer) {
if (bbox[0].x - min_x).abs() < 1.0 && (bbox[0].y - min_y).abs() < 1.0 {
if (bbox[0].x - min_x).abs() < 1. && (bbox[0].y - min_y).abs() < 1. {
return Some(layer);
}
}
Expand All @@ -2814,8 +2814,8 @@ mod document_message_handler_tests {
parent.children(document.metadata()).position(|child| child == layer)
}

let layer_middle = get_layer_by_bounds(&mut editor, 50.0, 50.0).await.unwrap();
let layer_top = get_layer_by_bounds(&mut editor, 100.0, 100.0).await.unwrap();
let layer_middle = get_layer_by_bounds(&mut editor, 50., 50.).await.unwrap();
let layer_top = get_layer_by_bounds(&mut editor, 100., 100.).await.unwrap();

let initial_index_top = get_layer_index(&mut editor, layer_top).await.unwrap();
let initial_index_middle = get_layer_index(&mut editor, layer_middle).await.unwrap();
Expand Down Expand Up @@ -2915,7 +2915,7 @@ mod document_message_handler_tests {
// Applying transform to folder1 (translation)
editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![folder1.to_node()] }).await;
editor.handle_message(TransformLayerMessage::BeginGrab).await;
editor.move_mouse(100.0, 50.0, ModifierKeys::empty(), MouseKeys::NONE).await;
editor.move_mouse(100., 50., ModifierKeys::empty(), MouseKeys::NONE).await;
editor
.handle_message(TransformLayerMessage::PointerMove {
slow_key: Key::Shift,
Expand All @@ -2927,7 +2927,7 @@ mod document_message_handler_tests {
// Applying different transform to folder2 (translation)
editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![folder2.to_node()] }).await;
editor.handle_message(TransformLayerMessage::BeginGrab).await;
editor.move_mouse(200.0, 100.0, ModifierKeys::empty(), MouseKeys::NONE).await;
editor.move_mouse(200., 100., ModifierKeys::empty(), MouseKeys::NONE).await;
editor
.handle_message(TransformLayerMessage::PointerMove {
slow_key: Key::Shift,
Expand All @@ -2946,7 +2946,7 @@ mod document_message_handler_tests {
editor.handle_message(DocumentMessage::MoveSelectedLayersTo { parent: folder1, insert_index: 0 }).await;

editor.handle_message(TransformLayerMessage::BeginGrab).await;
editor.move_mouse(50.0, 25.0, ModifierKeys::empty(), MouseKeys::NONE).await;
editor.move_mouse(50., 25., ModifierKeys::empty(), MouseKeys::NONE).await;
editor
.handle_message(TransformLayerMessage::PointerMove {
slow_key: Key::Shift,
Expand All @@ -2967,10 +2967,10 @@ mod document_message_handler_tests {
let rect_bbox_after = document.metadata().bounding_box_viewport(rect_layer).unwrap();

// Verifing the rectangle maintains approximately the same position in viewport space
let before_center = (rect_bbox_before[0] + rect_bbox_before[1]) / 2.0;
let after_center = (rect_bbox_after[0] + rect_bbox_after[1]) / 2.0;
let before_center = (rect_bbox_before[0] + rect_bbox_before[1]) / 2.;
let after_center = (rect_bbox_after[0] + rect_bbox_after[1]) / 2.;
let distance = before_center.distance(after_center);

assert!(distance < 1.0, "Rectangle should maintain its viewport position after moving between transformed groups");
assert!(distance < 1., "Rectangle should maintain its viewport position after moving between transformed groups");
}
}
30 changes: 17 additions & 13 deletions editor/src/messages/tool/tool_messages/line_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,8 +462,8 @@ mod test_line_tool {
if let Some((start_input, end_input)) = get_line_node_inputs(&mut editor).await {
match (start_input, end_input) {
(start_input, end_input) => {
assert!((start_input - DVec2::ZERO).length() < 1.0, "Start point should be near (0,0)");
assert!((end_input - DVec2::new(100.0, 100.0)).length() < 1.0, "End point should be near (100,100)");
assert!((start_input - DVec2::ZERO).length() < 1., "Start point should be near (0,0)");
assert!((end_input - DVec2::new(100., 100.)).length() < 1., "End point should be near (100,100)");
}
}
}
Expand All @@ -473,26 +473,30 @@ mod test_line_tool {
async fn test_line_tool_with_transformed_viewport() {
let mut editor = EditorTestUtils::create();
editor.new_document().await;
editor.handle_message(NavigationMessage::CanvasZoomSet { zoom_factor: 2.0 }).await;
editor.handle_message(NavigationMessage::CanvasPan { delta: DVec2::new(100.0, 50.0) }).await;
editor.handle_message(NavigationMessage::CanvasTiltSet { angle_radians: 30.0_f64.to_radians() }).await;
editor.handle_message(NavigationMessage::CanvasZoomSet { zoom_factor: 2. }).await;
editor.handle_message(NavigationMessage::CanvasPan { delta: DVec2::new(100., 50.) }).await;
editor
.handle_message(NavigationMessage::CanvasTiltSet {
angle_radians: (30. as f64).to_radians(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just write 30_f64.to_radians(). However it doesn't really matter.

})
.await;
editor.drag_tool(ToolType::Line, 0., 0., 100., 100., ModifierKeys::empty()).await;
if let Some((start_input, end_input)) = get_line_node_inputs(&mut editor).await {
let document = editor.active_document();
let document_to_viewport = document.metadata().document_to_viewport;
let viewport_to_document = document_to_viewport.inverse();

let expected_start = viewport_to_document.transform_point2(DVec2::ZERO);
let expected_end = viewport_to_document.transform_point2(DVec2::new(100.0, 100.0));
let expected_end = viewport_to_document.transform_point2(DVec2::new(100., 100.));

assert!(
(start_input - expected_start).length() < 1.0,
(start_input - expected_start).length() < 1.,
"Start point should match expected document coordinates. Got {:?}, expected {:?}",
start_input,
expected_start
);
assert!(
(end_input - expected_end).length() < 1.0,
(end_input - expected_end).length() < 1.,
"End point should match expected document coordinates. Got {:?}, expected {:?}",
end_input,
expected_end
Expand All @@ -519,7 +523,7 @@ mod test_line_tool {
let updated_line_vec = updated_end - updated_start;
let updated_angle = updated_line_vec.angle_to(DVec2::X);
assert!((original_angle - updated_angle).abs() < 0.1, "Line angle should be locked when Ctrl is kept pressed");
assert!((updated_start - updated_end).length() > 1.0, "Line should be able to change length when Ctrl is kept pressed");
assert!((updated_start - updated_end).length() > 1., "Line should be able to change length when Ctrl is kept pressed");
}
}
}
Expand All @@ -538,8 +542,8 @@ mod test_line_tool {
(start_input, end_input) => {
let expected_start = DVec2::new(0., 100.);
let expected_end = DVec2::new(200., 100.);
assert!((start_input - expected_start).length() < 1.0, "start point should be near (0,100)");
assert!((end_input - expected_end).length() < 1.0, "end point should be near (200,100)");
assert!((start_input - expected_start).length() < 1., "start point should be near (0,100)");
assert!((end_input - expected_end).length() < 1., "end point should be near (200,100)");
}
}
}
Expand All @@ -556,9 +560,9 @@ mod test_line_tool {
let line_vec = end_input - start_input;
let angle_radians = line_vec.angle_to(DVec2::X);
let angle_degrees = angle_radians.to_degrees();
let nearest_angle = (angle_degrees / 15.0).round() * 15.0;
let nearest_angle = (angle_degrees / 15.).round() * 15.;

assert!((angle_degrees - nearest_angle).abs() < 1.0, "Angle should snap to the nearest 15 degrees");
assert!((angle_degrees - nearest_angle).abs() < 1., "Angle should snap to the nearest 15 degrees");
}
}
}
Expand Down
151 changes: 151 additions & 0 deletions editor/src/messages/tool/tool_messages/spline_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -648,4 +648,155 @@ mod test_spline_tool {

assert_point_positions(&extended_vector_data, layer_to_viewport, &all_expected_points, 1e-10);
}

#[tokio::test]
async fn test_spline_with_zoomed_view() {
let mut editor = EditorTestUtils::create();
editor.new_document().await;

// Zooming the viewport
editor.handle_message(NavigationMessage::CanvasZoomSet { zoom_factor: 2.0 }).await;

// Selecting the spline tool
editor.select_tool(ToolType::Spline).await;

// Adding points by clicking at different positions
editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(50.0, 50.0), ModifierKeys::empty()).await;
editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(100.0, 50.0), ModifierKeys::empty()).await;
editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(150.0, 100.0), ModifierKeys::empty()).await;

// Finish the spline
editor.handle_message(SplineToolMessage::Confirm).await;

// Evaluate the graph to ensure everything is processed
editor.eval_graph().await;

// Get the layer and vector data
let document = editor.active_document();
let network_interface = &document.network_interface;
let layer = network_interface
.selected_nodes()
.selected_visible_and_unlocked_layers(network_interface)
.next()
.expect("Should have a selected layer");
let vector_data = network_interface.compute_modified_vector(layer).expect("Should have vector data");
let layer_to_viewport = document.metadata().transform_to_viewport(layer);

// Expected points in viewport coordinates
let expected_points = vec![DVec2::new(50.0, 50.0), DVec2::new(100.0, 50.0), DVec2::new(150.0, 100.0)];

// Assert all points are correctly positioned
assert_point_positions(&vector_data, layer_to_viewport, &expected_points, 1e-10);
}

#[tokio::test]
async fn test_spline_with_panned_view() {
let mut editor = EditorTestUtils::create();
editor.new_document().await;

let pan_amount = DVec2::new(200.0, 150.0);
editor.handle_message(NavigationMessage::CanvasPan { delta: pan_amount }).await;

editor.select_tool(ToolType::Spline).await;

// Add points by clicking at different positions
editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(50.0, 50.0), ModifierKeys::empty()).await;
editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(100.0, 50.0), ModifierKeys::empty()).await;
editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(150.0, 100.0), ModifierKeys::empty()).await;

editor.handle_message(SplineToolMessage::Confirm).await;

// Evaluating the graph to ensure everything is processed
editor.eval_graph().await;

// Get the layer and vector data
let document = editor.active_document();
let network_interface = &document.network_interface;
let layer = network_interface
.selected_nodes()
.selected_visible_and_unlocked_layers(network_interface)
.next()
.expect("Should have a selected layer");
let vector_data = network_interface.compute_modified_vector(layer).expect("Should have vector data");
let layer_to_viewport = document.metadata().transform_to_viewport(layer);

// Expected points in viewport coordinates
let expected_points = vec![DVec2::new(50.0, 50.0), DVec2::new(100.0, 50.0), DVec2::new(150.0, 100.0)];

// Assert all points are correctly positioned
assert_point_positions(&vector_data, layer_to_viewport, &expected_points, 1e-10);
}

#[tokio::test]
async fn test_spline_with_tilted_view() {
let mut editor = EditorTestUtils::create();
editor.new_document().await;

// Tilt/rotate the viewport (45 degrees)
editor.handle_message(NavigationMessage::CanvasTiltSet { angle_radians: 45.0_f64.to_radians() }).await;
editor.select_tool(ToolType::Spline).await;

editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(50.0, 50.0), ModifierKeys::empty()).await;
editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(100.0, 50.0), ModifierKeys::empty()).await;
editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(150.0, 100.0), ModifierKeys::empty()).await;

editor.handle_message(SplineToolMessage::Confirm).await;

// Evaluating the graph to ensure everything is processed
editor.eval_graph().await;

// Get the layer and vector data
let document = editor.active_document();
let network_interface = &document.network_interface;
let layer = network_interface
.selected_nodes()
.selected_visible_and_unlocked_layers(network_interface)
.next()
.expect("Should have a selected layer");
let vector_data = network_interface.compute_modified_vector(layer).expect("Should have vector data");
let layer_to_viewport = document.metadata().transform_to_viewport(layer);

// Expected points in viewport coordinates
let expected_points = vec![DVec2::new(50.0, 50.0), DVec2::new(100.0, 50.0), DVec2::new(150.0, 100.0)];

// Assert all points are correctly positioned
assert_point_positions(&vector_data, layer_to_viewport, &expected_points, 1e-10);
}

#[tokio::test]
async fn test_spline_with_combined_transformations() {
let mut editor = EditorTestUtils::create();
editor.new_document().await;

// Applying multiple transformations
editor.handle_message(NavigationMessage::CanvasZoomSet { zoom_factor: 1.5 }).await;
editor.handle_message(NavigationMessage::CanvasPan { delta: DVec2::new(100.0, 75.0) }).await;
editor.handle_message(NavigationMessage::CanvasTiltSet { angle_radians: 30.0_f64.to_radians() }).await;

editor.select_tool(ToolType::Spline).await;

editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(50.0, 50.0), ModifierKeys::empty()).await;
editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(100.0, 50.0), ModifierKeys::empty()).await;
editor.click_tool(ToolType::Spline, MouseKeys::LEFT, DVec2::new(150.0, 100.0), ModifierKeys::empty()).await;

editor.handle_message(SplineToolMessage::Confirm).await;
editor.eval_graph().await;

// Get the layer and vector data
let document = editor.active_document();
let network_interface = &document.network_interface;
let layer = network_interface
.selected_nodes()
.selected_visible_and_unlocked_layers(network_interface)
.next()
.expect("Should have a selected layer");
let vector_data = network_interface.compute_modified_vector(layer).expect("Should have vector data");
let layer_to_viewport = document.metadata().transform_to_viewport(layer);

// Expected points in viewport coordinates
let expected_points = vec![DVec2::new(50.0, 50.0), DVec2::new(100.0, 50.0), DVec2::new(150.0, 100.0)];

// Assert all points are correctly positioned
assert_point_positions(&vector_data, layer_to_viewport, &expected_points, 1e-10);
}
}
Loading
Loading