Skip to content

Commit 1beb0be

Browse files
committed
impl radius-gizmo for arc
1 parent d8a2203 commit 1beb0be

File tree

5 files changed

+123
-13
lines changed

5 files changed

+123
-13
lines changed

editor/src/messages/portfolio/document/overlays/utility_types.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,80 @@ impl OverlayContext {
294294
self.end_dpi_aware_transform();
295295
}
296296

297+
#[allow(clippy::too_many_arguments)]
298+
pub fn dashed_ellipse(
299+
&mut self,
300+
center: DVec2,
301+
radius_x: f64,
302+
radius_y: f64,
303+
rotation: Option<f64>,
304+
start_angle: Option<f64>,
305+
end_angle: Option<f64>,
306+
counterclockwise: Option<bool>,
307+
color_fill: Option<&str>,
308+
color_stroke: Option<&str>,
309+
dash_width: Option<f64>,
310+
dash_gap_width: Option<f64>,
311+
dash_offset: Option<f64>,
312+
) {
313+
let color_stroke = color_stroke.unwrap_or(COLOR_OVERLAY_BLUE);
314+
let center = center.round();
315+
316+
self.start_dpi_aware_transform();
317+
318+
if let Some(dash_width) = dash_width {
319+
let dash_gap_width = dash_gap_width.unwrap_or(1.);
320+
let array = js_sys::Array::new();
321+
array.push(&JsValue::from(dash_width));
322+
array.push(&JsValue::from(dash_gap_width));
323+
324+
if let Some(dash_offset) = dash_offset {
325+
if dash_offset != 0. {
326+
self.render_context.set_line_dash_offset(dash_offset);
327+
}
328+
}
329+
330+
self.render_context
331+
.set_line_dash(&JsValue::from(array))
332+
.map_err(|error| log::warn!("Error drawing dashed line: {:?}", error))
333+
.ok();
334+
}
335+
336+
self.render_context.begin_path();
337+
self.render_context
338+
.ellipse_with_anticlockwise(
339+
center.x,
340+
center.y,
341+
radius_x,
342+
radius_y,
343+
rotation.unwrap_or_default(),
344+
start_angle.unwrap_or_default(),
345+
end_angle.unwrap_or(TAU),
346+
counterclockwise.unwrap_or_default(),
347+
)
348+
.expect("Failed to draw ellipse");
349+
self.render_context.set_stroke_style_str(color_stroke);
350+
351+
if let Some(fill_color) = color_fill {
352+
self.render_context.set_fill_style_str(fill_color);
353+
self.render_context.fill();
354+
}
355+
self.render_context.stroke();
356+
357+
// Reset the dash pattern back to solid
358+
if dash_width.is_some() {
359+
self.render_context
360+
.set_line_dash(&JsValue::from(js_sys::Array::new()))
361+
.map_err(|error| log::warn!("Error drawing dashed line: {:?}", error))
362+
.ok();
363+
}
364+
if dash_offset.is_some() && dash_offset != Some(0.) {
365+
self.render_context.set_line_dash_offset(0.);
366+
}
367+
368+
self.end_dpi_aware_transform();
369+
}
370+
297371
pub fn dashed_circle(
298372
&mut self,
299373
position: DVec2,

editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/circle_radius_handle.rs renamed to editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/circle_arc_radius_handle.rs

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ use crate::messages::portfolio::document::utility_types::document_metadata::Laye
55
use crate::messages::portfolio::document::{overlays::utility_types::OverlayContext, utility_types::network_interface::InputConnector};
66
use crate::messages::prelude::{DocumentMessageHandler, InputPreprocessorMessageHandler, NodeGraphMessage};
77
use crate::messages::prelude::{FrontendMessage, Responses};
8-
use crate::messages::tool::common_functionality::graph_modification_utils::{self, get_arc_id};
8+
use crate::messages::tool::common_functionality::graph_modification_utils::{self, get_arc_id, get_stroke_width};
99
use crate::messages::tool::common_functionality::shapes::shape_utility::{extract_arc_parameters, extract_circle_radius};
10-
use glam::DVec2;
10+
use glam::{DAffine2, DVec2};
1111
use graph_craft::document::NodeInput;
1212
use graph_craft::document::value::TaggedValue;
1313
use std::collections::VecDeque;
14+
use std::f64::consts::FRAC_PI_2;
1415

1516
#[derive(Clone, Debug, Default, PartialEq)]
1617
pub enum RadiusHandleState {
@@ -47,25 +48,34 @@ impl RadiusHandle {
4748
self.handle_state = state;
4849
}
4950

51+
pub fn check_if_inside_dash_lines(angle: f64, mouse_position: DVec2, viewport: DAffine2, radius: f64, document: &DocumentMessageHandler, layer: LayerNodeIdentifier) -> bool {
52+
let center = viewport.transform_point2(DVec2::ZERO);
53+
if let Some(stroke_width) = get_stroke_width(layer, &document.network_interface) {
54+
let layer_mouse = viewport.inverse().transform_point2(mouse_position);
55+
let spacing = 3. * stroke_width;
56+
layer_mouse.distance(DVec2::ZERO) >= (radius - spacing) && layer_mouse.distance(DVec2::ZERO) <= (radius + spacing)
57+
} else {
58+
let point_position = viewport.transform_point2(calculate_circle_point_position(angle, radius.abs()));
59+
mouse_position.distance(center) <= point_position.distance(center)
60+
}
61+
}
62+
5063
pub fn handle_actions(&mut self, layer: LayerNodeIdentifier, document: &DocumentMessageHandler, mouse_position: DVec2, responses: &mut VecDeque<Message>) {
5164
match &self.handle_state {
5265
RadiusHandleState::Inactive => {
5366
let Some(radius) = extract_circle_radius(layer, document).or(extract_arc_parameters(Some(layer), document).map(|(r, _, _, _)| r)) else {
5467
return;
5568
};
5669
let viewport = document.metadata().transform_to_viewport(layer);
57-
5870
let angle = viewport.inverse().transform_point2(mouse_position).angle_to(DVec2::X);
59-
60-
let point_position = viewport.transform_point2(get_circle_point_position(angle, radius.abs()));
71+
let point_position = viewport.transform_point2(calculate_circle_point_position(angle, radius.abs()));
6172
let center = viewport.transform_point2(DVec2::ZERO);
6273

63-
log::info!("reaching here");
6474
if point_position.distance(center) < GIZMO_HIDE_THRESHOLD {
6575
return;
6676
}
6777

68-
if mouse_position.distance(center) <= point_position.distance(center) {
78+
if Self::check_if_inside_dash_lines(angle, mouse_position, viewport, radius.abs(), document, layer) {
6979
self.layer = Some(layer);
7080
self.initial_radius = radius;
7181
self.previous_mouse_position = mouse_position;
@@ -89,9 +99,35 @@ impl RadiusHandle {
8999
return;
90100
};
91101
let viewport = document.metadata().transform_to_viewport(layer);
102+
let center = viewport.transform_point2(DVec2::ZERO);
103+
104+
let start_point = viewport.transform_point2(calculate_circle_point_position(0., radius)).distance(center);
105+
let end_point = viewport.transform_point2(calculate_circle_point_position(FRAC_PI_2, radius)).distance(center);
106+
107+
if let Some(stroke_width) = get_stroke_width(layer, &document.network_interface) {
108+
let threshold = 15.0;
109+
let min_radius = start_point.min(end_point);
110+
111+
let extra_spacing = if min_radius < threshold {
112+
10.0 * (min_radius / threshold) // smoothly scales from 0 → 10
113+
} else {
114+
10.0
115+
};
116+
117+
let spacing = stroke_width + extra_spacing;
118+
let smaller_radius_x = (start_point - spacing).abs();
119+
let smaller_radius_y = (end_point - spacing).abs();
120+
121+
let larger_radius_x = (start_point + spacing).abs();
122+
let larger_radius_y = (end_point + spacing).abs();
123+
124+
overlay_context.dashed_ellipse(center, smaller_radius_x, smaller_radius_y, None, None, None, None, None, None, Some(4.), Some(4.), Some(0.5));
125+
overlay_context.dashed_ellipse(center, larger_radius_x, larger_radius_y, None, None, None, None, None, None, Some(4.), Some(4.), Some(0.5));
126+
127+
return;
128+
}
92129

93-
overlay_context.dashed_circle(DVec2::ZERO, radius.abs(), None, None, Some(20.), Some(4.), Some(0.5), Some(viewport));
94-
// overlay_context.dashed_line(center, point_position, None, None, Some(4.), Some(4.), Some(0.5));
130+
overlay_context.dashed_ellipse(center, start_point, end_point, None, None, None, None, None, None, Some(4.), Some(4.), Some(0.5));
95131
}
96132
}
97133
}
@@ -124,6 +160,6 @@ impl RadiusHandle {
124160
}
125161
}
126162

127-
fn get_circle_point_position(theta: f64, radius: f64) -> DVec2 {
163+
fn calculate_circle_point_position(theta: f64, radius: f64) -> DVec2 {
128164
DVec2::new(radius * theta.cos(), -radius * theta.sin())
129165
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
pub mod circle_radius_handle;
1+
pub mod circle_arc_radius_handle;
22
pub mod number_of_points_dial;
33
pub mod point_radius_handle;
44
pub mod sweep_angle_gizmo;

editor/src/messages/tool/common_functionality/shapes/arc_shape.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::messages::portfolio::document::graph_operation::utility_types::Transf
44
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
55
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
66
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate};
7-
use crate::messages::tool::common_functionality::gizmos::shape_gizmos::circle_radius_handle::{RadiusHandle, RadiusHandleState};
7+
use crate::messages::tool::common_functionality::gizmos::shape_gizmos::circle_arc_radius_handle::{RadiusHandle, RadiusHandleState};
88
use crate::messages::tool::common_functionality::gizmos::shape_gizmos::sweep_angle_gizmo::{SweepAngleGizmo, SweepAngleGizmoState};
99
use crate::messages::tool::common_functionality::graph_modification_utils;
1010
use crate::messages::tool::common_functionality::shapes::shape_utility::{ShapeGizmoHandler, arc_outline};

editor/src/messages/tool/common_functionality/shapes/circle_shape.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::messages::portfolio::document::overlays::utility_types::OverlayContex
44
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
55
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate};
66

7-
use crate::messages::tool::common_functionality::gizmos::shape_gizmos::circle_radius_handle::{RadiusHandle, RadiusHandleState};
7+
use crate::messages::tool::common_functionality::gizmos::shape_gizmos::circle_arc_radius_handle::{RadiusHandle, RadiusHandleState};
88
use crate::messages::tool::common_functionality::graph_modification_utils;
99

1010
use crate::messages::tool::common_functionality::shape_editor::ShapeState;

0 commit comments

Comments
 (0)