diff --git a/editor/src/messages/portfolio/document/node_graph/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_properties.rs index 9e65e14b62..db683ba4e8 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_properties.rs @@ -1253,7 +1253,7 @@ pub(crate) fn spiral_properties(node_id: NodeId, context: &mut NodePropertiesCon let turns = number_widget(ParameterWidgetsInfo::new(node_id, TurnsInput::INDEX, true, context), NumberInput::default().min(0.1)); let angle_offset = number_widget( ParameterWidgetsInfo::new(node_id, AngleOffsetInput::INDEX, true, context), - NumberInput::default().min(0.1).max(180.).unit("°"), + NumberInput::default().min(1.).max(180.).unit("°"), ); let start_angle = number_widget(ParameterWidgetsInfo::new(node_id, StartAngleInput::INDEX, true, context), NumberInput::default().unit("°")); diff --git a/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/spiral_tightness_gizmo.rs b/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/spiral_tightness_gizmo.rs index 8588b45a22..70b1e017fc 100644 --- a/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/spiral_tightness_gizmo.rs +++ b/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/spiral_tightness_gizmo.rs @@ -9,6 +9,7 @@ use crate::messages::prelude::{DocumentMessageHandler, FrontendMessage, InputPre use crate::messages::tool::common_functionality::graph_modification_utils::{self}; use crate::messages::tool::common_functionality::shape_editor::ShapeState; use crate::messages::tool::common_functionality::shapes::shape_utility::{calculate_b, extract_arc_or_log_spiral_parameters, get_arc_spiral_end_point, get_spiral_type, spiral_point}; +use crate::messages::tool::common_functionality::shapes::spiral_shape::calculate_circle_point; use glam::{DAffine2, DVec2}; use graph_craft::document::NodeInput; use graph_craft::document::value::TaggedValue; @@ -236,7 +237,6 @@ impl TightnessGizmo { } { let theta_start = base_theta; let theta_end = if is_reversed { base_theta - TAU } else { base_theta + TAU }; - log::info!("segment index {:?}, theta_start {:?} ,theta_end {:?}", segment_index, theta_start.to_degrees(), theta_end.to_degrees()); if (!is_reversed && theta_end > max_theta + start_angle_rad) || (is_reversed && theta_end < 0.0) { break; @@ -247,6 +247,10 @@ impl TightnessGizmo { continue; } + if is_reversed && theta_end < start_angle_rad { + break; + } + let spiral_start = spiral_point(theta_start, inner_radius, b, spiral_type); let spiral_end = spiral_point(theta_end, inner_radius, b, spiral_type); @@ -294,14 +298,14 @@ impl TightnessGizmo { let (start_point, end_point) = if self.spiral_slot == 0 && !reversed { let endpoint = spiral_point(0. + start_angle_rad, inner_radius, b, spiral_type); + let circle_point = calculate_circle_point(self.angle, inner_radius.max(5.)); let radius = endpoint.distance(DVec2::ZERO); ( - viewport.transform_point2(radius * DVec2::new(self.angle.cos(), -self.angle.sin())), + viewport.transform_point2(circle_point), viewport.transform_point2(spiral_point(base_angle, inner_radius, b, spiral_type)), ) } else if self.spiral_slot == self.turns.floor() as i32 && reversed { - log::info!("am i plzz reaching here"); let radius = spiral_point(max_theta, inner_radius, b, spiral_type).distance(DVec2::ZERO); let endpoint = if self.angle >= (max_theta + start_angle_rad).rem_euclid(TAU) { viewport.transform_point2(spiral_point(base_angle - TAU, inner_radius, b, spiral_type)) @@ -310,8 +314,12 @@ impl TightnessGizmo { }; (viewport.transform_point2(radius * DVec2::new(self.angle.cos(), -self.angle.sin())), endpoint) } else { - let ref_angle = (self.spiral_slot as f64 - 1.) * TAU + base_angle; - let end_point_angle = if reversed { ref_angle - TAU } else { ref_angle + TAU }; + let ref_angle = if reversed { + base_angle - (turns - self.spiral_slot as f64) * TAU + } else { + (self.spiral_slot as f64 - 1.) * TAU + base_angle + }; + let end_point_angle = ref_angle + TAU; ( viewport.transform_point2(spiral_point(ref_angle, inner_radius, b, spiral_type)), viewport.transform_point2(spiral_point(end_point_angle, inner_radius, b, spiral_type)), diff --git a/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/spiral_turns_handle.rs b/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/spiral_turns_handle.rs index 17d522f374..1107b584b0 100644 --- a/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/spiral_turns_handle.rs +++ b/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/spiral_turns_handle.rs @@ -173,7 +173,7 @@ impl SpiralTurns { match self.gizmo_type { GizmoType::Start => { - let sign = total_delta.signum() * -1.; + let sign = -1.; responses.add(NodeGraphMessage::SetInput { input_connector: InputConnector::node(node_id, SPIRAL_START_ANGLE), input: NodeInput::value(TaggedValue::F64(self.initial_start_angle + total_delta), false), diff --git a/editor/src/messages/tool/common_functionality/shapes/spiral_shape.rs b/editor/src/messages/tool/common_functionality/shapes/spiral_shape.rs index 662cba920f..e2b54bf2f5 100644 --- a/editor/src/messages/tool/common_functionality/shapes/spiral_shape.rs +++ b/editor/src/messages/tool/common_functionality/shapes/spiral_shape.rs @@ -41,8 +41,8 @@ impl ShapeGizmoHandler for SpiralGizmoHandler { input: &InputPreprocessorMessageHandler, responses: &mut VecDeque, ) { - // self.radius_handle.handle_actions(selected_spiral_layer, document, input.mouse.position, responses); - // self.turns_handle.handle_actions(selected_spiral_layer, mouse_position, document, responses); + self.radius_handle.handle_actions(selected_spiral_layer, document, input.mouse.position, responses); + self.turns_handle.handle_actions(selected_spiral_layer, mouse_position, document, responses); self.tightness_handle.handle_actions(selected_spiral_layer, input.mouse.position, document, responses); } diff --git a/libraries/bezier-rs/src/subpath/core.rs b/libraries/bezier-rs/src/subpath/core.rs index fd83334b2b..137e6c7b51 100644 --- a/libraries/bezier-rs/src/subpath/core.rs +++ b/libraries/bezier-rs/src/subpath/core.rs @@ -281,34 +281,47 @@ impl Subpath { let mut theta = start_angle; while theta < theta_end { - let theta_next = f64::min(theta + delta_theta, theta_end); - - let p0 = spiral_point(theta, a, b, spiral_type); - let p3 = spiral_point(theta_next, a, b, spiral_type); - let t0 = spiral_tangent(theta, a, b, spiral_type); - let t1 = spiral_tangent(theta_next, a, b, spiral_type); - - let arc_len = spiral_arc_length(theta, theta_next, a, b, spiral_type); - let d = arc_len / 3.0; - - let p1 = p0 + d * t0; - let p2 = p3 - d * t1; - - manipulator_groups.push(ManipulatorGroup::new(p0, prev_in_handle, Some(p1))); - prev_in_handle = Some(p2); - - // If final segment, end with anchor at theta_end - if (theta_next - theta_end).abs() < f64::EPSILON { - manipulator_groups.push(ManipulatorGroup::new(p3, prev_in_handle, None)); - break; - } - - theta = theta_next; + let next_theta = f64::min(theta + delta_theta, theta_end); + Self::fit_spiral_segment(theta, next_theta, a, b, spiral_type, &mut manipulator_groups, &mut prev_in_handle); + theta = next_theta; } + // Add final anchor point + let p_last = spiral_point(theta_end, a, b, spiral_type); + manipulator_groups.push(ManipulatorGroup::new(p_last, prev_in_handle, None)); + Self::new(manipulator_groups, false) } + fn fit_spiral_segment(theta_start: f64, theta_end: f64, a: f64, b: f64, spiral_type: SpiralType, manipulator_groups: &mut Vec>, prev_in_handle: &mut Option) { + let delta = (theta_end - theta_start).abs(); + + // Split large arcs into two halves + if delta > std::f64::consts::FRAC_PI_2 { + let mid = (theta_start + theta_end) / 2.0; + Self::fit_spiral_segment(theta_start, mid, a, b, spiral_type, manipulator_groups, prev_in_handle); + Self::fit_spiral_segment(mid, theta_end, a, b, spiral_type, manipulator_groups, prev_in_handle); + return; + } + + // Compute endpoints and tangents + let p0 = spiral_point(theta_start, a, b, spiral_type); + let p3 = spiral_point(theta_end, a, b, spiral_type); + let t0 = spiral_tangent(theta_start, a, b, spiral_type); + let t1 = spiral_tangent(theta_end, a, b, spiral_type); + + // Use fixed handle length: 1/3 of the arc length + let arc_len = spiral_arc_length(theta_start, theta_end, a, b, spiral_type); + let h_in = arc_len / 3.0; + let h_out = arc_len / 3.0; + + let p1 = p0 + h_in * t0; + let p2 = p3 - h_out * t1; + + manipulator_groups.push(ManipulatorGroup::new(p0, *prev_in_handle, Some(p1))); + *prev_in_handle = Some(p2); + } + /// Constructs an ellipse with `corner1` and `corner2` as the two corners of the bounding box. pub fn new_ellipse(corner1: DVec2, corner2: DVec2) -> Self { let size = (corner1 - corner2).abs();