Skip to content

Commit 0b548e5

Browse files
committed
fixed wrapping need to fix snapping and overlays
1 parent cdb1bf7 commit 0b548e5

2 files changed

Lines changed: 145 additions & 33 deletions

File tree

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

Lines changed: 144 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::messages::{
1313
prelude::{DocumentMessageHandler, FrontendMessage},
1414
};
1515
use glam::DVec2;
16+
use graph_craft::document::NodeId;
1617
use graph_craft::document::NodeInput;
1718
use graph_craft::document::value::TaggedValue;
1819
use std::collections::VecDeque;
@@ -41,6 +42,7 @@ pub struct SweepAngleGizmo {
4142
endpoint: EndpointType,
4243
initial_start_angle: f64,
4344
initial_sweep_angle: f64,
45+
initial_start_point: DVec2,
4446
previous_mouse_position: DVec2,
4547
total_angle_delta: f64,
4648
snap_angles: Vec<f64>,
@@ -203,6 +205,7 @@ impl SweepAngleGizmo {
203205
let offset_angle = initial_vector.to_angle() + tilt_offset;
204206

205207
let angle = initial_vector.angle_to(final_vector).to_degrees();
208+
log::info!("angle {:?}", angle);
206209
let display_angle = calculate_display_angle(angle);
207210

208211
let text = format!("{}°", format_rounded(display_angle, 2));
@@ -224,52 +227,161 @@ impl SweepAngleGizmo {
224227
return;
225228
};
226229

227-
let Some((_, start_angle, _, _)) = extract_arc_parameters(Some(layer), document) else {
230+
let Some((_, current_start_angle, current_sweep_angle, _)) = extract_arc_parameters(Some(layer), document) else {
228231
return;
229232
};
230233

231234
let viewport = document.metadata().transform_to_viewport(layer);
232-
let angle = self.total_angle_delta
233-
+ viewport
234-
.inverse()
235-
.transform_point2(self.previous_mouse_position)
236-
.angle_to(viewport.inverse().transform_point2(input.mouse.position))
237-
.to_degrees();
235+
let angle_delta = viewport
236+
.inverse()
237+
.transform_point2(self.previous_mouse_position)
238+
.angle_to(viewport.inverse().transform_point2(input.mouse.position))
239+
.to_degrees();
240+
let angle = self.total_angle_delta + angle_delta;
238241

239242
let Some(node_id) = graph_modification_utils::get_arc_id(layer, &document.network_interface) else {
240243
return;
241244
};
242245

243246
self.update_state(SweepAngleGizmoState::Dragging);
244-
if self.endpoint == EndpointType::End {
245-
let mut total = angle;
246-
if let Some(snapped_delta) = self.check_snapping(start_angle, self.initial_sweep_angle + angle) {
247-
total += snapped_delta;
248-
self.update_state(SweepAngleGizmoState::Snapped);
247+
248+
match self.endpoint {
249+
EndpointType::Start => {
250+
// Dragging start changes both start and sweep
251+
252+
let sign = angle.signum() * -1.;
253+
let mut total = angle;
254+
255+
let new_start_angle = self.initial_start_angle + total;
256+
let new_sweep_angle = self.initial_sweep_angle + total.abs() * sign;
257+
258+
// Clamp sweep angle to 360°
259+
if new_sweep_angle > 360. {
260+
let wrapped = new_sweep_angle % 360.;
261+
self.total_angle_delta = -wrapped;
262+
263+
// Remaining drag gets passed to the end endpoint
264+
let rest_angle = angle_delta + wrapped;
265+
self.endpoint = EndpointType::End;
266+
267+
self.initial_sweep_angle = 360.;
268+
self.initial_start_angle = current_start_angle + rest_angle;
269+
270+
self.apply_arc_update(node_id, self.initial_start_angle, self.initial_sweep_angle - wrapped, input, responses);
271+
return;
272+
}
273+
274+
if new_sweep_angle < 0. {
275+
let rest_angle = angle_delta + new_sweep_angle;
276+
277+
self.total_angle_delta = new_sweep_angle.abs();
278+
self.endpoint = EndpointType::End;
279+
280+
self.initial_sweep_angle = 0.;
281+
self.initial_start_angle = current_start_angle + rest_angle;
282+
283+
self.apply_arc_update(node_id, self.initial_start_angle, new_sweep_angle.abs(), input, responses);
284+
return;
285+
}
286+
287+
// Wrap start angle > 180° back into [-180°, 180°] and adjust sweep
288+
if new_start_angle > 180. {
289+
let overflow = new_start_angle % 180.;
290+
let rest_angle = angle_delta - overflow;
291+
292+
// We wrap the angle back into [-180°, 180°] range by jumping from +180° to -180°
293+
// Example: dragging past 190° becomes -170°, and we subtract the overshoot from sweep
294+
// Sweep angle must shrink to maintain consistent arc
295+
self.total_angle_delta = rest_angle;
296+
self.initial_start_angle = -180.;
297+
self.initial_sweep_angle = current_sweep_angle - rest_angle;
298+
299+
self.apply_arc_update(node_id, self.initial_start_angle + overflow, self.initial_sweep_angle - overflow, input, responses);
300+
return;
301+
}
302+
303+
// Wrap start angle < -180° back into [-180°, 180°] and adjust sweep
304+
if new_start_angle < -180. {
305+
let underflow = new_start_angle % 180.;
306+
let rest_angle = angle_delta - underflow;
307+
308+
// We wrap the angle back into [-180°, 180°] by jumping from -190° to +170°
309+
// Sweep must grow to reflect continued clockwise drag past -180°
310+
// Start angle flips from -190° to +170°, and sweep increases accordingly
311+
self.total_angle_delta = underflow;
312+
self.initial_start_angle = 180.;
313+
self.initial_sweep_angle = current_sweep_angle + rest_angle.abs();
314+
315+
self.apply_arc_update(node_id, self.initial_start_angle + underflow, self.initial_sweep_angle + underflow.abs(), input, responses);
316+
return;
317+
}
318+
319+
if let Some(snapped_delta) = self.check_snapping(self.initial_start_angle + angle, self.initial_sweep_angle + total.abs() * sign) {
320+
total += snapped_delta;
321+
self.update_state(SweepAngleGizmoState::Snapped);
322+
}
323+
324+
self.total_angle_delta = angle;
325+
self.apply_arc_update(node_id, self.initial_start_angle + total, self.initial_sweep_angle + total.abs() * sign, input, responses);
249326
}
250-
responses.add(NodeGraphMessage::SetInput {
251-
input_connector: InputConnector::node(node_id, 3),
252-
input: NodeInput::value(TaggedValue::F64(self.initial_sweep_angle + total), false),
253-
});
254-
} else {
255-
let sign = angle.signum() * -1.;
256-
let mut total = angle;
327+
EndpointType::End => {
328+
// Dragging the end only changes sweep angle
329+
330+
let mut total = angle;
331+
let new_sweep_angle = self.initial_sweep_angle + angle;
332+
333+
// Clamp sweep angle below 0°, switch to start
334+
if new_sweep_angle < 0. {
335+
let delta = angle_delta - current_sweep_angle;
336+
let sign = delta.signum() * -1.;
337+
338+
self.initial_sweep_angle = 0.;
339+
self.total_angle_delta = delta;
340+
self.endpoint = EndpointType::Start;
341+
342+
self.apply_arc_update(node_id, self.initial_start_angle + delta, self.initial_sweep_angle + delta.abs() * sign, input, responses);
343+
return;
344+
}
257345

258-
if let Some(snapped_delta) = self.check_snapping(self.initial_start_angle + angle, self.initial_sweep_angle + total.abs() * sign) {
259-
total += snapped_delta;
260-
self.update_state(SweepAngleGizmoState::Snapped);
346+
// Clamp sweep angle above 360°, switch to start
347+
if new_sweep_angle > 360. {
348+
let delta = angle_delta - (360. - current_sweep_angle);
349+
let sign = delta.signum() * -1.;
350+
351+
self.total_angle_delta = angle_delta;
352+
self.initial_sweep_angle = 360.;
353+
self.endpoint = EndpointType::Start;
354+
355+
self.apply_arc_update(node_id, self.initial_start_angle + angle_delta, self.initial_sweep_angle + angle_delta.abs() * sign, input, responses);
356+
return;
357+
}
358+
359+
if let Some(snapped_delta) = self.check_snapping(self.initial_start_angle, self.initial_sweep_angle + angle) {
360+
total += snapped_delta;
361+
self.update_state(SweepAngleGizmoState::Snapped);
362+
}
363+
364+
self.total_angle_delta = angle;
365+
self.apply_arc_update(node_id, self.initial_start_angle, self.initial_sweep_angle + total, input, responses);
261366
}
262-
responses.add(NodeGraphMessage::SetInput {
263-
input_connector: InputConnector::node(node_id, 2),
264-
input: NodeInput::value(TaggedValue::F64(self.initial_start_angle + total), false),
265-
});
266-
responses.add(NodeGraphMessage::SetInput {
267-
input_connector: InputConnector::node(node_id, 3),
268-
input: NodeInput::value(TaggedValue::F64(self.initial_sweep_angle + total.abs() * sign), false),
269-
});
367+
EndpointType::None => {}
270368
}
369+
}
370+
371+
/// Applies the updated start and sweep angles to the arc.
372+
fn apply_arc_update(&mut self, node_id: NodeId, start_angle: f64, sweep_angle: f64, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
373+
self.snap_angles = self.calculate_snap_angles(start_angle, sweep_angle);
374+
375+
responses.add(NodeGraphMessage::SetInput {
376+
input_connector: InputConnector::node(node_id, 2),
377+
input: NodeInput::value(TaggedValue::F64(start_angle), false),
378+
});
379+
responses.add(NodeGraphMessage::SetInput {
380+
input_connector: InputConnector::node(node_id, 3),
381+
input: NodeInput::value(TaggedValue::F64(sweep_angle), false),
382+
});
383+
271384
self.previous_mouse_position = input.mouse.position;
272-
self.total_angle_delta = angle;
273385
responses.add(NodeGraphMessage::RunDocumentGraph);
274386
}
275387

@@ -299,7 +411,7 @@ impl SweepAngleGizmo {
299411

300412
if self.endpoint == EndpointType::End {
301413
for i in 0..8 {
302-
let snap_point = i as f64 * FRAC_PI_4;
414+
let snap_point = wrap_to_tau(i as f64 * FRAC_PI_4 + initial_start_angle);
303415
snap_points.push(snap_point.to_degrees());
304416
}
305417
}

node-graph/gcore/src/vector/generator_nodes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::misc::{ArcType, AsU64, GridType};
22
use super::{PointId, SegmentId, StrokeId};
33
use crate::Ctx;
4-
use crate::registry::types::PixelSize;
4+
use crate::registry::types::{Angle, PixelSize};
55
use crate::vector::{HandleId, VectorData, VectorDataTable};
66
use bezier_rs::Subpath;
77
use glam::DVec2;

0 commit comments

Comments
 (0)