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
base: master
Are you sure you want to change the base?
Conversation
!build |
|
5a97aff
to
9d9f5ae
Compare
What's the latest status on this? It's still marked as a draft so I assume there's more to do? |
This is feature complete and awaiting review for code quality and robustness. |
9999d9c
to
b4b4f34
Compare
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 |
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.
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 comment
The 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));
@@ -873,6 +873,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag | |||
|
|||
impl DocumentMessageHandler { | |||
/// Runs an intersection test with all layers and a viewport space quad | |||
/// TODO: properly check if layer is filled |
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?
Any updates about getting the two code review comments resolved? (The question and the suggestion to reuse the existing winding function instead of reimplementing it.) Thanks! (I'm also going to mark this as a draft for the moment until I hear more.) |
Allows for selection of open shapes by clicking on the filled region.
Closes #1736