Skip to content
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

Fix trivial_hull implementation for collinear points #907

Merged
merged 6 commits into from
Sep 18, 2022

Conversation

tyilo
Copy link
Contributor

@tyilo tyilo commented Sep 13, 2022

  • I agree to follow the project's code of conduct.
  • I added an entry to CHANGES.md if knowledge of this change could be valuable to users.

Fixes #905

@urschrei
Copy link
Member

Thanks! This looks good to me, but it would be great if you could add a brief explanation of the fix to your comment above, for those of us who can't easily visualise what's going on.

@tyilo
Copy link
Contributor Author

tyilo commented Sep 13, 2022

If include_hull is false, then given the input [(0, 0), (1, 1), (2,2)] (in any order) the output should be [(0, 0), (2, 2), (0, 0)] (or [(2, 2), (0, 0), (2, 2)]).

Before this fix, with input [(0, 0), (1, 1), (2, 2)] the output is [(0, 0), (1, 1), (2, 2), (0, 0)].

To fix it, we need to remove the "middle" point if the three points are colinear.
To do this, we first sort the three points (first by x, then by y) and then remove the point at index 1, if they are colinear.

The sorting is needed to give the correct output for any permutation of [(0, 0), (1, 1), (2, 2)], for instance [(2, 2), (0, 0), (1, 1)].

Copy link
Contributor

@rmanoka rmanoka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR @tyilo ! Just have a few minor suggestions, but the overall logic looks good to me.

@@ -77,7 +80,21 @@ where
// are to be included.
let mut ls: Vec<Coordinate<T>> = points.to_vec();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to avoid this extra Vec allocation? Can you sort the input mut-slice directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can sort the mut-slice directly, however we can't do ls.remove(1); on a slice, so I don't see how we can do it without creating a new Vec.

@rmanoka I find it weird that the convex hull algorithms (trivial_hull, graham_hull and quick_hull) takes points: &mut [Coordinate<T>] as input.
We don't guarantee anything about how points has been mutated by the algorithm, right?

So wouldn't it be better to take either &[Coordinate<T>] or Vec<Coordinate<T>> as input?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need mutable points for the partition_slice function which reorders coordinates based on a predicate?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need mutable points for the partition_slice function which reorders coordinates based on a predicate?

That would also work if we took input as Vec<Coordinate<T>>.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need mutable points for the partition_slice function which reorders coordinates based on a predicate?

That would also work if we took input as Vec<Coordinate<T>>.

I am confused – could you say more about what you have in mind here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need mutable points for the partition_slice function which reorders coordinates based on a predicate?

That would also work if we took input as Vec<Coordinate<T>>.

I am confused – could you say more about what you have in mind here?

So there are basically three options for taking slices as input in rust:

  • Owned: Box<[Coordinate<T>]> or Vec<Coordinate<T>>. Makes sense if we need to consume the input to do the computation.
  • Borrowed: &[Coordinate<T>]. Makes sense if we only need to read the input and consuming the input (as in "Owned") doesn't speed up the computation.
  • Mutably borrowed: &mut [Coordinate<T>]. Makes sense if the computation needs to change the input, but also the user of the function should (at least in some situations) be interested in the mutated input. If mutated input is never useful for the user, we should prefer to use an owned input.

I'm arguing that the mutated points input is never useful for the user and thus to prevent the user from accidentally using the now garbage list of points and to make the api more clear, we should choose the "Owned" option.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the function signature was primarily whatever works for the implementation. Note that the usage is anyway via the trait. If it simplifies code without extra allocations, we can move to something more intuitive.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the function signature was primarily whatever works for the implementation. Note that the usage is anyway via the trait. If it simplifies code without extra allocations, we can move to something more intuitive.

Makes sense. I don't think that change is relevant to this pull request.
Do I need to fix anything else before this can get merged?

@rmanoka
Copy link
Contributor

rmanoka commented Sep 17, 2022

@tyilo pls. pull changes from main to fix the other CI issues. I think it's ready to merge once CI passes.

@tyilo
Copy link
Contributor Author

tyilo commented Sep 18, 2022

@tyilo pls. pull changes from main to fix the other CI issues. I think it's ready to merge once CI passes.

Done.

@tyilo tyilo changed the title Fix trivial_hull implementation for colinear points Fix trivial_hull implementation for collinear points Sep 18, 2022
@urschrei
Copy link
Member

bors r=rmanoka

@bors
Copy link
Contributor

bors bot commented Sep 18, 2022

Build succeeded:

@bors bors bot merged commit 40e416b into georust:main Sep 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Convex hull of three colinear points contains all three points
3 participants