diff --git a/node-graph/gcore/src/vector/algorithms/bezpath_algorithms.rs b/node-graph/gcore/src/vector/algorithms/bezpath_algorithms.rs index 6a1213d55e..a18dda6314 100644 --- a/node-graph/gcore/src/vector/algorithms/bezpath_algorithms.rs +++ b/node-graph/gcore/src/vector/algorithms/bezpath_algorithms.rs @@ -608,8 +608,9 @@ pub fn round_line_join(bezpath1: &BezPath, bezpath2: &BezPath, center: DVec2) -> } /// Returns `true` if the `bezpath1` is completely inside the `bezpath2`. +/// NOTE: `bezpath2` must be a closed path to get correct results. pub fn bezpath_is_inside_bezpath(bezpath1: &BezPath, bezpath2: &BezPath, accuracy: Option, minimum_separation: Option) -> bool { - // Eliminate any possibility of one being inside the other, if either of them is empty + // Eliminate any possibility of one being inside the other, if either of them are empty if bezpath1.is_empty() || bezpath2.is_empty() { return false; } @@ -621,7 +622,7 @@ pub fn bezpath_is_inside_bezpath(bezpath1: &BezPath, bezpath2: &BezPath, accurac // Reasoning: // If the inner bezpath bounding box is larger than the outer bezpath bounding box in any direction // then the inner bezpath is intersecting with or outside the outer bezpath. - if !outer_bbox.contains_rect(inner_bbox) { + if !outer_bbox.contains_rect(inner_bbox) && outer_bbox.intersect(inner_bbox).is_zero_area() { return false; } diff --git a/node-graph/gcore/src/vector/click_target.rs b/node-graph/gcore/src/vector/click_target.rs index 976f8682ae..6ab7c1860a 100644 --- a/node-graph/gcore/src/vector/click_target.rs +++ b/node-graph/gcore/src/vector/click_target.rs @@ -1,4 +1,4 @@ -use super::algorithms::intersection::filtered_segment_intersections; +use super::algorithms::{bezpath_algorithms::bezpath_is_inside_bezpath, intersection::filtered_segment_intersections}; use super::misc::dvec2_to_point; use crate::math::math_ext::QuadExt; use crate::math::quad::Quad; @@ -6,7 +6,7 @@ use crate::subpath::Subpath; use crate::vector::PointId; use crate::vector::misc::point_to_dvec2; use glam::{DAffine2, DMat2, DVec2}; -use kurbo::{Affine, ParamCurve, PathSeg, Point, Shape}; +use kurbo::{Affine, BezPath, ParamCurve, PathSeg, Shape}; #[derive(Copy, Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] pub struct FreePoint { @@ -125,9 +125,11 @@ impl ClickTarget { return true; } + let mut selection = BezPath::from_path_segments(bezier_iter()); + selection.close_path(); + // Check if shape is entirely within selection - let any_point_from_subpath = subpath.manipulator_groups().first().map(|manipulators| manipulators.anchor); - any_point_from_subpath.is_some_and(|shape_point| bezier_iter().map(|bezier| bezier.winding(Point::new(shape_point.x, shape_point.y))).sum::() != 0) + bezpath_is_inside_bezpath(&subpath.to_bezpath(), &selection, None, None) } ClickTargetType::FreePoint(point) => bezier_iter().map(|bezier: PathSeg| bezier.winding(dvec2_to_point(point.position))).sum::() != 0, }