From 6b847b980056014f3e035c85e8c46209d31314d3 Mon Sep 17 00:00:00 2001 From: ThunderBlaze Date: Wed, 17 Dec 2025 19:46:06 +0530 Subject: [PATCH] Adds a Toggle for Inner Radius in Polygon tool (#3484) --- .../shape_gizmos/number_of_points_dial.rs | 26 ++++++++------- .../shape_gizmos/point_radius_handle.rs | 32 ++++++++++++------- .../shapes/shape_utility.rs | 16 +++++++--- .../nodes/vector/src/generator_nodes.rs | 9 ++++-- 4 files changed, 54 insertions(+), 29 deletions(-) diff --git a/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/number_of_points_dial.rs b/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/number_of_points_dial.rs index c6fef1fbda..4fcc692b74 100644 --- a/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/number_of_points_dial.rs +++ b/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/number_of_points_dial.rs @@ -14,7 +14,7 @@ use glam::{DAffine2, DVec2}; use graph_craft::document::NodeInput; use graph_craft::document::value::TaggedValue; use std::collections::VecDeque; -use std::f64::consts::TAU; +use std::f64::consts::{PI, TAU}; #[derive(Clone, Debug, Default, PartialEq)] pub enum NumberOfPointsDialState { @@ -68,11 +68,12 @@ impl NumberOfPointsDial { } // Polygon - if let Some((sides, radius)) = extract_polygon_parameters(Some(layer), document) { + if let Some((sides, radius, is_inner_radius)) = extract_polygon_parameters(Some(layer), document) { let viewport = document.metadata().transform_to_viewport(layer); let center = viewport.transform_point2(DVec2::ZERO); - let point_on_max_radius = polygon_vertex_position(viewport, 0, sides, radius); + let effective_radius = if is_inner_radius { radius / (PI / sides as f64).cos() } else { radius }; + let point_on_max_radius = polygon_vertex_position(viewport, 0, sides, effective_radius); if mouse_position.distance(center) < NUMBER_OF_POINTS_DIAL_SPOKE_LENGTH && point_on_max_radius.distance(center) > GIZMO_HIDE_THRESHOLD { self.layer = Some(layer); @@ -122,7 +123,7 @@ impl NumberOfPointsDial { } // Polygon - if let Some((sides, radius)) = extract_polygon_parameters(Some(layer), document) { + if let Some((sides, radius, is_inner_radius)) = extract_polygon_parameters(Some(layer), document) { let viewport = document.metadata().transform_to_viewport(layer); let center = viewport.transform_point2(DVec2::ZERO); @@ -131,10 +132,11 @@ impl NumberOfPointsDial { { return; } - let point_on_max_radius = polygon_vertex_position(viewport, 0, sides, radius); + let effective_radius = if is_inner_radius { radius / (PI / sides as f64).cos() } else { radius }; + let point_on_max_radius = polygon_vertex_position(viewport, 0, sides, effective_radius); - if inside_polygon(viewport, sides, radius, mouse_position) && point_on_max_radius.distance(center) > GIZMO_HIDE_THRESHOLD { - self.draw_spokes(center, viewport, sides, radius, overlay_context); + if inside_polygon(viewport, sides, effective_radius, mouse_position) && point_on_max_radius.distance(center) > GIZMO_HIDE_THRESHOLD { + self.draw_spokes(center, viewport, sides, effective_radius, overlay_context); } } } @@ -144,10 +146,12 @@ impl NumberOfPointsDial { }; // Get the star's greater radius or polygon's radius, as well as the number of sides - let Some((sides, radius)) = extract_star_parameters(Some(layer), document) - .map(|(sides, r1, r2)| (sides, r1.max(r2))) - .or_else(|| extract_polygon_parameters(Some(layer), document)) - else { + let Some((sides, radius)) = extract_star_parameters(Some(layer), document).map(|(sides, r1, r2)| (sides, r1.max(r2))).or_else(|| { + extract_polygon_parameters(Some(layer), document).map(|(sides, radius, is_inner_radius)| { + let effective_radius = if is_inner_radius { radius / (PI / sides as f64).cos() } else { radius }; + (sides, effective_radius) + }) + }) else { return; }; diff --git a/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/point_radius_handle.rs b/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/point_radius_handle.rs index 55c131dce1..d8f9e24122 100644 --- a/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/point_radius_handle.rs +++ b/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/point_radius_handle.rs @@ -86,11 +86,12 @@ impl PointRadiusHandle { } // Draw the point handle gizmo for the polygon shape - if let Some((sides, radius)) = extract_polygon_parameters(Some(layer), document) { + if let Some((sides, radius, is_inner_radius)) = extract_polygon_parameters(Some(layer), document) { let viewport = document.metadata().transform_to_viewport(layer); + let effective_radius = if is_inner_radius { radius / (PI / sides as f64).cos() } else { radius }; for i in 0..sides { - let point = polygon_vertex_position(viewport, i as i32, sides, radius); + let point = polygon_vertex_position(viewport, i as i32, sides, effective_radius); let center = viewport.transform_point2(DVec2::ZERO); // If the user zooms out such that shape is very small hide the gizmo @@ -129,8 +130,9 @@ impl PointRadiusHandle { } // Polygon - if let Some((sides, radius)) = extract_polygon_parameters(Some(layer), document) { - let point = polygon_vertex_position(viewport, self.point as i32, sides, radius); + if let Some((sides, radius, is_inner_radius)) = extract_polygon_parameters(Some(layer), document) { + let effective_radius = if is_inner_radius { radius / (PI / sides as f64).cos() } else { radius }; + let point = polygon_vertex_position(viewport, self.point as i32, sides, effective_radius); if matches!(&self.handle_state, PointRadiusHandleState::Hover) && (mouse_position - point).length() > 5. { self.update_state(PointRadiusHandleState::Inactive); @@ -165,11 +167,12 @@ impl PointRadiusHandle { } // Draw the point handle gizmo for the Polygon shape - if let Some((sides, radius)) = extract_polygon_parameters(Some(layer), document) { + if let Some((sides, radius, is_inner_radius)) = extract_polygon_parameters(Some(layer), document) { let viewport = document.metadata().transform_to_viewport(layer); + let effective_radius = if is_inner_radius { radius / (PI / sides as f64).cos() } else { radius }; for i in 0..sides { - let point = polygon_vertex_position(viewport, i as i32, sides, radius); + let point = polygon_vertex_position(viewport, i as i32, sides, effective_radius); let center = viewport.transform_point2(DVec2::ZERO); // If the user zooms out such that shape is very small hide the gizmo @@ -210,8 +213,9 @@ impl PointRadiusHandle { } // Polygon - if let Some((sides, radius)) = extract_polygon_parameters(Some(layer), document) { - let point = polygon_vertex_position(viewport, self.point as i32, sides, radius); + if let Some((sides, radius, is_inner_radius)) = extract_polygon_parameters(Some(layer), document) { + let effective_radius = if is_inner_radius { radius / (PI / sides as f64).cos() } else { radius }; + let point = polygon_vertex_position(viewport, self.point as i32, sides, effective_radius); let Some(direction) = (point - center).try_normalize() else { return }; @@ -419,17 +423,23 @@ impl PointRadiusHandle { }; let viewport_transform = document.network_interface.document_metadata().transform_to_viewport(layer); - let center = viewport_transform.transform_point2(DVec2::ZERO); + let radius_index = self.radius_index; let original_radius = self.initial_radius; - let delta = viewport_transform.inverse().transform_point2(input.mouse.position) - viewport_transform.inverse().transform_point2(drag_start); - let radius = drag_start - center; + let drag_start = viewport_transform.inverse().transform_point2(drag_start); + let delta = viewport_transform.inverse().transform_point2(input.mouse.position) - drag_start; + let radius = drag_start; let projection = delta.project_onto(radius); let sign = radius.dot(delta).signum(); let mut net_delta = projection.length() * sign * original_radius.signum(); + if let Some((sides, _, is_inner_radius)) = extract_polygon_parameters(Some(layer), document) { + if is_inner_radius { + net_delta *= (PI / sides as f64).cos(); + } + } let new_radius = original_radius + net_delta; self.update_state(PointRadiusHandleState::Dragging); diff --git a/editor/src/messages/tool/common_functionality/shapes/shape_utility.rs b/editor/src/messages/tool/common_functionality/shapes/shape_utility.rs index a94847c514..542f69f673 100644 --- a/editor/src/messages/tool/common_functionality/shapes/shape_utility.rs +++ b/editor/src/messages/tool/common_functionality/shapes/shape_utility.rs @@ -245,14 +245,16 @@ pub fn extract_star_parameters(layer: Option, document: &Do /// Extract the node input values of Polygon. /// Returns an option of (sides, radius). -pub fn extract_polygon_parameters(layer: Option, document: &DocumentMessageHandler) -> Option<(u32, f64)> { +pub fn extract_polygon_parameters(layer: Option, document: &DocumentMessageHandler) -> Option<(u32, f64, bool)> { let node_inputs = NodeGraphLayer::new(layer?, &document.network_interface).find_node_inputs("Regular Polygon")?; - let (Some(&TaggedValue::U32(n)), Some(&TaggedValue::F64(radius))) = (node_inputs.get(1)?.as_value(), node_inputs.get(2)?.as_value()) else { + let (Some(&TaggedValue::U32(n)), Some(&TaggedValue::F64(radius)), Some(&TaggedValue::Bool(is_inner_radius))) = + (node_inputs.get(1)?.as_value(), node_inputs.get(2)?.as_value(), node_inputs.get(3)?.as_value()) + else { return None; }; - Some((n, radius)) + Some((n, radius, is_inner_radius)) } /// Extract the node input values of an arc. @@ -349,14 +351,18 @@ pub fn star_outline(layer: Option, document: &DocumentMessa /// Outlines the geometric shape made by polygon-node pub fn polygon_outline(layer: Option, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext) { let Some(layer) = layer else { return }; - let Some((sides, radius)) = extract_polygon_parameters(Some(layer), document) else { + let Some((sides, radius, is_inner_radius)) = extract_polygon_parameters(Some(layer), document) else { return; }; let viewport = document.metadata().transform_to_viewport(layer); let points = sides as u64; - let radius: f64 = radius * 2.; + let radius: f64 = if is_inner_radius { + (radius * 2.) / (std::f64::consts::PI / points as f64).cos() + } else { + radius * 2. + }; let subpath: Vec = vec![ClickTargetType::Subpath(Subpath::new_regular_polygon(DVec2::splat(-radius), points, radius))]; diff --git a/node-graph/nodes/vector/src/generator_nodes.rs b/node-graph/nodes/vector/src/generator_nodes.rs index df587528ef..af4858af86 100644 --- a/node-graph/nodes/vector/src/generator_nodes.rs +++ b/node-graph/nodes/vector/src/generator_nodes.rs @@ -157,10 +157,15 @@ fn regular_polygon( #[unit(" px")] #[default(50)] radius: f64, + #[default(false)] is_inner_radius: bool, ) -> Table { let points = sides.as_u64(); - let radius: f64 = radius * 2.; - Table::new_from_element(Vector::from_subpath(subpath::Subpath::new_regular_polygon(DVec2::splat(-radius), points, radius))) + let effective_radius = if is_inner_radius { + radius * 2. / (std::f64::consts::PI / points as f64).cos() + } else { + radius * 2. + }; + Table::new_from_element(Vector::from_subpath(subpath::Subpath::new_regular_polygon(DVec2::splat(-effective_radius), points, effective_radius))) } /// Generates an n-pointed star shape with inner and outer points at chosen radii from the center.