-
-
Notifications
You must be signed in to change notification settings - Fork 381
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow selection by clicking open shapes that are visibly filled #1711
Changes from all commits
d598f58
4084f9a
06893f6
f68753a
e354456
3a35ce2
b4b4f34
7adf2aa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -269,7 +269,33 @@ impl<ManipulatorGroupId: crate::Identifier> Subpath<ManipulatorGroupId> { | |
|
||
/// Does a path contain a point? Based on the non zero winding | ||
pub fn contains_point(&self, target_point: DVec2) -> bool { | ||
self.iter().map(|bezier| bezier.winding(target_point)).sum::<i32>() != 0 | ||
if self.closed() { | ||
// Winding number for a closed curve. | ||
return self.iter().map(|bezier| bezier.winding(target_point)).sum::<i32>() != 0; | ||
} | ||
|
||
// The curve is not closed. Pretend that it is and compute the winding number | ||
// change as if we had a segment from the last point back to the first. | ||
|
||
// Position of first and last anchor points. | ||
let first_anchor_point = self.manipulator_groups.first().map(|group| group.anchor); | ||
let last_anchor_point = self.manipulator_groups.last().map(|group| group.anchor); | ||
let endpoints = first_anchor_point.zip(last_anchor_point); | ||
|
||
// Weight interpolating intersection location from last to first anchor point. Reject weights outside of [0, 1]. | ||
let t = endpoints.map(|(first, last)| (target_point.y - last.y) / (first.y - last.y)).filter(|t| (0.0..=1.).contains(t)); | ||
// Compute point of intersection. | ||
// Reject points that are right of the click location since we compute winding numbers by ray-casting left. | ||
let intersection_point = endpoints.zip(t).map(|((first, last), t)| t * first + (1. - t) * last).filter(|p| p.x <= target_point.x); | ||
let winding_modification = first_anchor_point.zip(intersection_point).map_or_else( | ||
// None variant implies no intersection and no modification to winding number. | ||
|| 0, | ||
// Clockwise (decrement winding number) and counterclockwise (increment winding number) intersection respectively. | ||
|(first, intersection)| if first.y >= intersection.y { -1 } else { 1 }, | ||
); | ||
|
||
// Add the winding modification to the winding number of the rest of the curve. | ||
self.iter().map(|bezier| bezier.winding(target_point)).sum::<i32>() + winding_modification != 0 | ||
Comment on lines
+272
to
+298
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Couldn't this just involve temporarily closing the shape, calculating the value, then un-closing it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Keavon this would require the function to take the mutable shape which is unnecessarily restrictive and would involve cloning in some cases. Although I agree that this could be simplified to use the existing winding function instead of re-implementing it: let modification = endpoints.map_or(0, |(p1, p2)| bezier_rs::Bezier::from_linear_dvec2(p1, p2).winding(target_point)); |
||
} | ||
|
||
/// Randomly places points across the filled surface of this subpath (which is assumed to be closed). | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this resolved?