Skip to content

Commit fd66f29

Browse files
0SlowPoke0Keavon
andauthored
Fix Shape tools bugs with stars/polygons with negative radii and circle radius click detection when viewport is zoomed (#2986)
* fixed spacing,click detection in radius gizmo fix drag in start point radiius gizmo * Code review --------- Co-authored-by: Keavon Chambers <[email protected]>
1 parent 5637f01 commit fd66f29

File tree

6 files changed

+67
-63
lines changed

6 files changed

+67
-63
lines changed

editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/circle_arc_radius_handle.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,24 +118,29 @@ impl RadiusHandle {
118118
let viewport = document.metadata().transform_to_viewport(layer);
119119
let center = viewport.transform_point2(DVec2::ZERO);
120120

121-
let start_point = viewport.transform_point2(calculate_circle_point_position(0., radius)).distance(center);
122-
let end_point = viewport.transform_point2(calculate_circle_point_position(FRAC_PI_2, radius)).distance(center);
121+
let x_point = viewport.transform_point2(calculate_circle_point_position(0., radius));
122+
let y_point = viewport.transform_point2(calculate_circle_point_position(FRAC_PI_2, radius));
123+
124+
let direction_x = viewport.transform_vector2(DVec2::X);
125+
let direction_y = viewport.transform_vector2(-DVec2::Y);
123126

124127
if let Some(stroke_width) = get_stroke_width(layer, &document.network_interface) {
125128
let spacing = Self::calculate_extra_spacing(viewport, radius, center, stroke_width, 15.);
126-
let smaller_radius_x = (start_point - spacing).abs();
127-
let smaller_radius_y = (end_point - spacing).abs();
129+
let smaller_radius_x = (x_point - direction_x * spacing).distance(center);
130+
let smaller_radius_y = (y_point - direction_y * spacing).distance(center);
128131

129-
let larger_radius_x = (start_point + spacing).abs();
130-
let larger_radius_y = (end_point + spacing).abs();
132+
let larger_radius_x = (x_point + direction_x * spacing).distance(center);
133+
let larger_radius_y = (y_point + direction_y * spacing).distance(center);
131134

132135
overlay_context.dashed_ellipse(center, smaller_radius_x, smaller_radius_y, None, None, None, None, None, None, Some(4.), Some(4.), Some(0.5));
133136
overlay_context.dashed_ellipse(center, larger_radius_x, larger_radius_y, None, None, None, None, None, None, Some(4.), Some(4.), Some(0.5));
134137

135138
return;
136139
}
137140

138-
overlay_context.dashed_ellipse(center, start_point, end_point, None, None, None, None, None, None, Some(4.), Some(4.), Some(0.5));
141+
let radius_x = x_point.distance(center);
142+
let radius_y = y_point.distance(center);
143+
overlay_context.dashed_ellipse(center, radius_x, radius_y, None, None, None, None, None, None, Some(4.), Some(4.), Some(0.5));
139144
}
140145
}
141146
}
@@ -153,7 +158,7 @@ impl RadiusHandle {
153158
let center = viewport_transform.transform_point2(DVec2::ZERO);
154159

155160
let delta_vector = viewport_transform.inverse().transform_point2(input.mouse.position) - viewport_transform.inverse().transform_point2(self.previous_mouse_position);
156-
let radius = document.metadata().document_to_viewport.transform_point2(drag_start) - center;
161+
let radius = drag_start - center;
157162
let sign = radius.dot(delta_vector).signum();
158163

159164
let net_delta = delta_vector.length() * sign * self.initial_radius.signum();

editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/number_of_points_dial.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,8 @@ impl NumberOfPointsDial {
189189
}
190190

191191
pub fn update_number_of_sides(&self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>, drag_start: DVec2) {
192-
let delta = input.mouse.position - document.metadata().document_to_viewport.transform_point2(drag_start);
193-
let sign = (input.mouse.position.x - document.metadata().document_to_viewport.transform_point2(drag_start).x).signum();
192+
let delta = input.mouse.position - drag_start;
193+
let sign = (input.mouse.position.x - drag_start.x).signum();
194194
let net_delta = (delta.length() / 25.).round() * sign;
195195

196196
let Some(layer) = self.layer else { return };

editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/point_radius_handle.rs

Lines changed: 47 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -142,14 +142,7 @@ impl PointRadiusHandle {
142142
}
143143
}
144144

145-
pub fn overlays(
146-
&self,
147-
selected_star_layer: Option<LayerNodeIdentifier>,
148-
document: &DocumentMessageHandler,
149-
input: &InputPreprocessorMessageHandler,
150-
mouse_position: DVec2,
151-
overlay_context: &mut OverlayContext,
152-
) {
145+
pub fn overlays(&self, selected_star_layer: Option<LayerNodeIdentifier>, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, overlay_context: &mut OverlayContext) {
153146
match &self.handle_state {
154147
PointRadiusHandleState::Inactive => {
155148
let Some(layer) = selected_star_layer else { return };
@@ -161,25 +154,12 @@ impl PointRadiusHandle {
161154
for i in 0..(2 * sides) {
162155
let point = star_vertex_position(viewport, i as i32, sides, radius1, radius2);
163156
let center = viewport.transform_point2(DVec2::ZERO);
164-
let viewport_diagonal = input.viewport_bounds.size().length();
165157

166158
// If the user zooms out such that shape is very small hide the gizmo
167159
if point.distance(center) < GIZMO_HIDE_THRESHOLD {
168160
return;
169161
}
170162

171-
if point.distance(mouse_position) < 5. {
172-
let Some(direction) = (point - center).try_normalize() else { continue };
173-
174-
overlay_context.manipulator_handle(point, true, None);
175-
let angle = ((i as f64) * PI) / (sides as f64);
176-
overlay_context.line(center, center + direction * viewport_diagonal, None, None);
177-
178-
draw_snapping_ticks(&self.snap_radii, direction, viewport, angle, overlay_context);
179-
180-
return;
181-
}
182-
183163
overlay_context.manipulator_handle(point, false, None);
184164
}
185165
}
@@ -191,22 +171,12 @@ impl PointRadiusHandle {
191171
for i in 0..sides {
192172
let point = polygon_vertex_position(viewport, i as i32, sides, radius);
193173
let center = viewport.transform_point2(DVec2::ZERO);
194-
let viewport_diagonal = input.viewport_bounds.size().length();
195174

196175
// If the user zooms out such that shape is very small hide the gizmo
197176
if point.distance(center) < GIZMO_HIDE_THRESHOLD {
198177
return;
199178
}
200179

201-
if point.distance(mouse_position) < 5. {
202-
let Some(direction) = (point - center).try_normalize() else { continue };
203-
204-
overlay_context.manipulator_handle(point, true, None);
205-
overlay_context.line(center, center + direction * viewport_diagonal, None, None);
206-
207-
return;
208-
}
209-
210180
overlay_context.manipulator_handle(point, false, None);
211181
}
212182
}
@@ -232,12 +202,9 @@ impl PointRadiusHandle {
232202
star_outline(Some(layer), document, overlay_context);
233203

234204
// Make the ticks for snapping
235-
236-
// If dragging to make radius negative don't show the
237-
if (mouse_position - center).dot(direction) < 0. {
238-
return;
205+
if (radius1.signum() * radius2.signum()).is_sign_positive() {
206+
draw_snapping_ticks(&self.snap_radii, direction, viewport, angle, overlay_context);
239207
}
240-
draw_snapping_ticks(&self.snap_radii, direction, viewport, angle, overlay_context);
241208

242209
return;
243210
}
@@ -368,25 +335,36 @@ impl PointRadiusHandle {
368335
return snap_radii;
369336
};
370337

371-
let other_index = if radius_index == 3 { 2 } else { 3 };
372-
373-
let Some(&TaggedValue::F64(other_radius)) = node_inputs[other_index].as_value() else {
338+
let (Some(&TaggedValue::F64(radius_1)), Some(&TaggedValue::F64(radius_2))) = (node_inputs[2].as_value(), node_inputs[3].as_value()) else {
374339
return snap_radii;
375340
};
341+
342+
let other_radius = if radius_index == 3 { radius_1 } else { radius_2 };
343+
376344
let Some(&TaggedValue::U32(sides)) = node_inputs[1].as_value() else {
377345
return snap_radii;
378346
};
379347

348+
let both_radii_negative = radius_1.is_sign_negative() && radius_2.is_sign_negative();
349+
let both_radii_same_sign = (radius_1.signum() * radius_2.signum()).is_sign_positive();
350+
351+
// When only one of the radii is negative, no need for snapping
352+
if !both_radii_same_sign {
353+
return snap_radii;
354+
}
355+
356+
let sign = if both_radii_negative { -1. } else { 1. };
357+
380358
// Inner radius for 90°
381359
let b = FRAC_PI_4 * 3. - PI / (sides as f64);
382360
let angle = b.sin();
383-
let required_radius = (other_radius / angle) * FRAC_1_SQRT_2;
361+
let required_radius = (other_radius.abs() * sign / angle) * FRAC_1_SQRT_2;
384362

385363
snap_radii.push(required_radius);
386364

387365
// Also push the case when the when it length increases more than the other
388366

389-
let flipped = other_radius * angle * SQRT_2;
367+
let flipped = other_radius.abs() * sign * angle * SQRT_2;
390368

391369
snap_radii.push(flipped);
392370

@@ -401,11 +379,11 @@ impl PointRadiusHandle {
401379
break;
402380
}
403381

404-
if other_radius * factor > 1e-6 {
405-
snap_radii.push(other_radius * factor);
382+
if other_radius.abs() * factor > 1e-6 {
383+
snap_radii.push(other_radius.abs() * sign * factor);
406384
}
407385

408-
snap_radii.push((other_radius * 1.) / factor);
386+
snap_radii.push((other_radius.abs() * sign) / factor);
409387
}
410388

411389
snap_radii
@@ -441,21 +419,23 @@ impl PointRadiusHandle {
441419
};
442420

443421
let viewport_transform = document.network_interface.document_metadata().transform_to_viewport(layer);
444-
let document_transform = document.network_interface.document_metadata().transform_to_document(layer);
445422
let center = viewport_transform.transform_point2(DVec2::ZERO);
446423
let radius_index = self.radius_index;
447424

448425
let original_radius = self.initial_radius;
449426

450-
let delta = viewport_transform.inverse().transform_point2(input.mouse.position) - document_transform.inverse().transform_point2(drag_start);
451-
let radius = document.metadata().document_to_viewport.transform_point2(drag_start) - center;
427+
let delta = viewport_transform.inverse().transform_point2(input.mouse.position) - viewport_transform.inverse().transform_point2(drag_start);
428+
let radius = drag_start - center;
452429
let projection = delta.project_onto(radius);
453430
let sign = radius.dot(delta).signum();
454431

455-
let mut net_delta = projection.length() * sign;
432+
let mut net_delta = projection.length() * sign * original_radius.signum();
456433
let new_radius = original_radius + net_delta;
457434

458435
self.update_state(PointRadiusHandleState::Dragging);
436+
437+
self.check_if_radius_flipped(original_radius, new_radius, document, layer, radius_index);
438+
459439
if let Some((index, snapped_delta)) = self.check_snapping(new_radius, original_radius) {
460440
net_delta = snapped_delta;
461441
self.update_state(PointRadiusHandleState::Snapped(index));
@@ -467,4 +447,23 @@ impl PointRadiusHandle {
467447
});
468448
responses.add(NodeGraphMessage::RunDocumentGraph);
469449
}
450+
451+
fn check_if_radius_flipped(&mut self, original_radius: f64, new_radius: f64, document: &DocumentMessageHandler, layer: LayerNodeIdentifier, radius_index: usize) {
452+
let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Star") else {
453+
return;
454+
};
455+
456+
let (Some(&TaggedValue::F64(radius_1)), Some(&TaggedValue::F64(radius_2))) = (node_inputs[2].as_value(), node_inputs[3].as_value()) else {
457+
return;
458+
};
459+
460+
let other_radius = if radius_index == 3 { radius_1 } else { radius_2 };
461+
462+
let flipped = (other_radius.is_sign_positive() && original_radius.is_sign_negative() && new_radius.is_sign_positive())
463+
|| (other_radius.is_sign_negative() && original_radius.is_sign_positive() && new_radius.is_sign_negative());
464+
465+
if flipped {
466+
self.snap_radii = Self::calculate_snap_radii(document, layer, radius_index);
467+
}
468+
}
470469
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ impl ShapeGizmoHandler for PolygonGizmoHandler {
6767
overlay_context: &mut OverlayContext,
6868
) {
6969
self.number_of_points_dial.overlays(document, selected_polygon_layer, shape_editor, mouse_position, overlay_context);
70-
self.point_radius_handle.overlays(selected_polygon_layer, document, input, mouse_position, overlay_context);
70+
self.point_radius_handle.overlays(selected_polygon_layer, document, input, overlay_context);
7171

7272
polygon_outline(selected_polygon_layer, document, overlay_context);
7373
}
@@ -85,7 +85,7 @@ impl ShapeGizmoHandler for PolygonGizmoHandler {
8585
}
8686

8787
if self.point_radius_handle.is_dragging_or_snapped() {
88-
self.point_radius_handle.overlays(None, document, input, mouse_position, overlay_context);
88+
self.point_radius_handle.overlays(None, document, input, overlay_context);
8989
}
9090
}
9191

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ impl ShapeGizmoHandler for StarGizmoHandler {
6464
overlay_context: &mut OverlayContext,
6565
) {
6666
self.number_of_points_dial.overlays(document, selected_star_layer, shape_editor, mouse_position, overlay_context);
67-
self.point_radius_handle.overlays(selected_star_layer, document, input, mouse_position, overlay_context);
67+
self.point_radius_handle.overlays(selected_star_layer, document, input, overlay_context);
6868

6969
star_outline(selected_star_layer, document, overlay_context);
7070
}
@@ -82,7 +82,7 @@ impl ShapeGizmoHandler for StarGizmoHandler {
8282
}
8383

8484
if self.point_radius_handle.is_dragging_or_snapped() {
85-
self.point_radius_handle.overlays(None, document, input, mouse_position, overlay_context);
85+
self.point_radius_handle.overlays(None, document, input, overlay_context);
8686
}
8787
}
8888

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -743,7 +743,7 @@ impl Fsm for ShapeToolFsmState {
743743
self
744744
}
745745
(ShapeToolFsmState::ModifyingGizmo, ShapeToolMessage::PointerMove(..)) => {
746-
tool_data.gizmo_manager.handle_update(tool_data.data.drag_start, document, input, responses);
746+
tool_data.gizmo_manager.handle_update(tool_data.data.viewport_drag_start(document), document, input, responses);
747747

748748
responses.add(OverlaysMessage::Draw);
749749

0 commit comments

Comments
 (0)