diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs index 40cfe18c..8263edba 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs @@ -19,12 +19,15 @@ use crate::messages::tool::common_functionality::auto_panning::AutoPanning; use crate::messages::tool::common_functionality::graph_modification_utils::{self, get_clip_mode}; use crate::messages::tool::tool_messages::tool_prelude::{Key, MouseMotion}; use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo}; +use bezier_rs::Subpath; use glam::{DAffine2, DVec2, IVec2}; use graph_craft::document::value::TaggedValue; use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput}; use graph_craft::proto::GraphErrors; use graphene_std::math::math_ext::QuadExt; +use graphene_std::vector::misc::subpath_to_kurbo_bezpath; use graphene_std::*; +use kurbo::{Line, Point}; use renderer::Quad; use std::cmp::Ordering; @@ -1242,9 +1245,37 @@ impl<'a> MessageHandler> for NodeG } log::debug!("preferences.graph_wire_style: {:?}", preferences.graph_wire_style); let (wire, is_stack) = network_interface.vector_wire_from_input(&input, preferences.graph_wire_style, selection_network_path)?; - wire.rectangle_intersections_exist(bounding_box[0], bounding_box[1]).then_some((input, is_stack)) + + let bbox_rect = kurbo::Rect::new(bounding_box[0].x, bounding_box[0].y, bounding_box[1].x, bounding_box[1].y); + + let p1 = DVec2::new(bbox_rect.x0, bbox_rect.y0); + let p2 = DVec2::new(bbox_rect.x1, bbox_rect.y0); + let p3 = DVec2::new(bbox_rect.x1, bbox_rect.y1); + let p4 = DVec2::new(bbox_rect.x0, bbox_rect.y1); + let ps = [p1, p2, p3, p4]; + + let inside = wire.is_inside_subpath(&Subpath::from_anchors_linear(ps, true), None, None); + + let wire = subpath_to_kurbo_bezpath(wire); + + let intersect = wire.segments().any(|segment| { + let rect = kurbo::Rect::new(bounding_box[0].x, bounding_box[0].y, bounding_box[1].x, bounding_box[1].y); + + let top_line = Line::new(Point::new(rect.x0, rect.y0), Point::new(rect.x1, rect.y0)); + let bottom_line = Line::new(Point::new(rect.x0, rect.y1), Point::new(rect.x1, rect.y1)); + let left_line = Line::new(Point::new(rect.x0, rect.y0), Point::new(rect.x0, rect.y1)); + let right_line = Line::new(Point::new(rect.x1, rect.y0), Point::new(rect.x1, rect.y1)); + + !segment.intersect_line(top_line).is_empty() + || !segment.intersect_line(bottom_line).is_empty() + || !segment.intersect_line(left_line).is_empty() + || !segment.intersect_line(right_line).is_empty() + }); + + (intersect || inside).then_some((input, is_stack)) }) .collect::>(); + // Prioritize vertical thick lines and cancel if there are multiple potential wires let mut node_wires = Vec::new(); let mut stack_wires = Vec::new(); diff --git a/node-graph/gcore/src/vector/misc.rs b/node-graph/gcore/src/vector/misc.rs index 64e4f012..a273cd31 100644 --- a/node-graph/gcore/src/vector/misc.rs +++ b/node-graph/gcore/src/vector/misc.rs @@ -1,7 +1,9 @@ -use bezier_rs::BezierHandles; +use bezier_rs::{BezierHandles, ManipulatorGroup, Subpath}; use dyn_any::DynAny; use glam::DVec2; -use kurbo::{CubicBez, Line, PathSeg, Point, QuadBez}; +use kurbo::{BezPath, CubicBez, Line, PathSeg, Point, QuadBez}; + +use super::PointId; /// Represents different ways of calculating the centroid. #[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 } } } + +pub fn subpath_to_kurbo_bezpath(subpath: Subpath) -> BezPath { + let maniputor_groups = subpath.manipulator_groups(); + let closed = subpath.closed(); + bezpath_from_manipulator_groups(maniputor_groups, closed) +} + +pub fn bezpath_from_manipulator_groups(manipulator_groups: &[ManipulatorGroup], closed: bool) -> BezPath { + let mut bezpath = kurbo::BezPath::new(); + let mut out_handle; + + let Some(first) = manipulator_groups.first() else { return bezpath }; + bezpath.move_to(dvec2_to_point(first.anchor)); + out_handle = first.out_handle; + + for manipulator in manipulator_groups.iter().skip(1) { + match (out_handle, manipulator.in_handle) { + (Some(handle_start), Some(handle_end)) => bezpath.curve_to(dvec2_to_point(handle_start), dvec2_to_point(handle_end), dvec2_to_point(manipulator.anchor)), + (None, None) => bezpath.line_to(dvec2_to_point(manipulator.anchor)), + (None, Some(handle)) => bezpath.quad_to(dvec2_to_point(handle), dvec2_to_point(manipulator.anchor)), + (Some(handle), None) => bezpath.quad_to(dvec2_to_point(handle), dvec2_to_point(manipulator.anchor)), + } + out_handle = manipulator.out_handle; + } + + if closed { + match (out_handle, first.in_handle) { + (Some(handle_start), Some(handle_end)) => bezpath.curve_to(dvec2_to_point(handle_start), dvec2_to_point(handle_end), dvec2_to_point(first.anchor)), + (None, None) => bezpath.line_to(dvec2_to_point(first.anchor)), + (None, Some(handle)) => bezpath.quad_to(dvec2_to_point(handle), dvec2_to_point(first.anchor)), + (Some(handle), None) => bezpath.quad_to(dvec2_to_point(handle), dvec2_to_point(first.anchor)), + } + bezpath.close_path(); + } + bezpath +}