Skip to content

Commit 30e5567

Browse files
authored
Fix collision detection for node drag-and-drop onto a wire (#2910)
* refactor * check if the wire is inside the node itself
1 parent 7ee0d9a commit 30e5567

File tree

2 files changed

+72
-3
lines changed

2 files changed

+72
-3
lines changed

editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,15 @@ use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
1919
use crate::messages::tool::common_functionality::graph_modification_utils::{self, get_clip_mode};
2020
use crate::messages::tool::tool_messages::tool_prelude::{Key, MouseMotion};
2121
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
22+
use bezier_rs::Subpath;
2223
use glam::{DAffine2, DVec2, IVec2};
2324
use graph_craft::document::value::TaggedValue;
2425
use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput};
2526
use graph_craft::proto::GraphErrors;
2627
use graphene_std::math::math_ext::QuadExt;
28+
use graphene_std::vector::misc::subpath_to_kurbo_bezpath;
2729
use graphene_std::*;
30+
use kurbo::{Line, Point};
2831
use renderer::Quad;
2932
use std::cmp::Ordering;
3033

@@ -1242,9 +1245,37 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
12421245
}
12431246
log::debug!("preferences.graph_wire_style: {:?}", preferences.graph_wire_style);
12441247
let (wire, is_stack) = network_interface.vector_wire_from_input(&input, preferences.graph_wire_style, selection_network_path)?;
1245-
wire.rectangle_intersections_exist(bounding_box[0], bounding_box[1]).then_some((input, is_stack))
1248+
1249+
let bbox_rect = kurbo::Rect::new(bounding_box[0].x, bounding_box[0].y, bounding_box[1].x, bounding_box[1].y);
1250+
1251+
let p1 = DVec2::new(bbox_rect.x0, bbox_rect.y0);
1252+
let p2 = DVec2::new(bbox_rect.x1, bbox_rect.y0);
1253+
let p3 = DVec2::new(bbox_rect.x1, bbox_rect.y1);
1254+
let p4 = DVec2::new(bbox_rect.x0, bbox_rect.y1);
1255+
let ps = [p1, p2, p3, p4];
1256+
1257+
let inside = wire.is_inside_subpath(&Subpath::from_anchors_linear(ps, true), None, None);
1258+
1259+
let wire = subpath_to_kurbo_bezpath(wire);
1260+
1261+
let intersect = wire.segments().any(|segment| {
1262+
let rect = kurbo::Rect::new(bounding_box[0].x, bounding_box[0].y, bounding_box[1].x, bounding_box[1].y);
1263+
1264+
let top_line = Line::new(Point::new(rect.x0, rect.y0), Point::new(rect.x1, rect.y0));
1265+
let bottom_line = Line::new(Point::new(rect.x0, rect.y1), Point::new(rect.x1, rect.y1));
1266+
let left_line = Line::new(Point::new(rect.x0, rect.y0), Point::new(rect.x0, rect.y1));
1267+
let right_line = Line::new(Point::new(rect.x1, rect.y0), Point::new(rect.x1, rect.y1));
1268+
1269+
!segment.intersect_line(top_line).is_empty()
1270+
|| !segment.intersect_line(bottom_line).is_empty()
1271+
|| !segment.intersect_line(left_line).is_empty()
1272+
|| !segment.intersect_line(right_line).is_empty()
1273+
});
1274+
1275+
(intersect || inside).then_some((input, is_stack))
12461276
})
12471277
.collect::<Vec<_>>();
1278+
12481279
// Prioritize vertical thick lines and cancel if there are multiple potential wires
12491280
let mut node_wires = Vec::new();
12501281
let mut stack_wires = Vec::new();

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

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
use bezier_rs::BezierHandles;
1+
use bezier_rs::{BezierHandles, ManipulatorGroup, Subpath};
22
use dyn_any::DynAny;
33
use glam::DVec2;
4-
use kurbo::{CubicBez, Line, PathSeg, Point, QuadBez};
4+
use kurbo::{BezPath, CubicBez, Line, PathSeg, Point, QuadBez};
5+
6+
use super::PointId;
57

68
/// Represents different ways of calculating the centroid.
79
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, Hash, DynAny, specta::Type, node_macro::ChoiceType)]
@@ -131,3 +133,39 @@ pub fn handles_to_segment(start: DVec2, handles: BezierHandles, end: DVec2) -> P
131133
}
132134
}
133135
}
136+
137+
pub fn subpath_to_kurbo_bezpath(subpath: Subpath<PointId>) -> BezPath {
138+
let maniputor_groups = subpath.manipulator_groups();
139+
let closed = subpath.closed();
140+
bezpath_from_manipulator_groups(maniputor_groups, closed)
141+
}
142+
143+
pub fn bezpath_from_manipulator_groups(manipulator_groups: &[ManipulatorGroup<PointId>], closed: bool) -> BezPath {
144+
let mut bezpath = kurbo::BezPath::new();
145+
let mut out_handle;
146+
147+
let Some(first) = manipulator_groups.first() else { return bezpath };
148+
bezpath.move_to(dvec2_to_point(first.anchor));
149+
out_handle = first.out_handle;
150+
151+
for manipulator in manipulator_groups.iter().skip(1) {
152+
match (out_handle, manipulator.in_handle) {
153+
(Some(handle_start), Some(handle_end)) => bezpath.curve_to(dvec2_to_point(handle_start), dvec2_to_point(handle_end), dvec2_to_point(manipulator.anchor)),
154+
(None, None) => bezpath.line_to(dvec2_to_point(manipulator.anchor)),
155+
(None, Some(handle)) => bezpath.quad_to(dvec2_to_point(handle), dvec2_to_point(manipulator.anchor)),
156+
(Some(handle), None) => bezpath.quad_to(dvec2_to_point(handle), dvec2_to_point(manipulator.anchor)),
157+
}
158+
out_handle = manipulator.out_handle;
159+
}
160+
161+
if closed {
162+
match (out_handle, first.in_handle) {
163+
(Some(handle_start), Some(handle_end)) => bezpath.curve_to(dvec2_to_point(handle_start), dvec2_to_point(handle_end), dvec2_to_point(first.anchor)),
164+
(None, None) => bezpath.line_to(dvec2_to_point(first.anchor)),
165+
(None, Some(handle)) => bezpath.quad_to(dvec2_to_point(handle), dvec2_to_point(first.anchor)),
166+
(Some(handle), None) => bezpath.quad_to(dvec2_to_point(handle), dvec2_to_point(first.anchor)),
167+
}
168+
bezpath.close_path();
169+
}
170+
bezpath
171+
}

0 commit comments

Comments
 (0)