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

implement euclidean distance for all geometry types #1029

Merged
merged 3 commits into from
Aug 7, 2023

Conversation

mcassels
Copy link
Contributor

@mcassels mcassels commented Jul 9, 2023

  • [ x] 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.

This change implements #979

Copy link
Member

@michaelkirk michaelkirk left a comment

Choose a reason for hiding this comment

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

Hi @mcassels - thanks for the PR!

I haven't reviewed very thoroughly yet, but I had a question about the usage of clone - see my inline commentary.

T: GeoFloat + FloatConst + RTreeNum + FloatConst,
{
fn euclidean_distance(&self, geom: &Geometry<T>) -> T {
let self_as_geom = Geometry::from(self.clone());
Copy link
Member

Choose a reason for hiding this comment

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

This usage of clone is unfortunate, since it potentially doubles our memory usage. Did you explore alternatives that don't require a clone here? Maybe it'd be a ton of code?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the review! I've updated this to avoid the use of clone

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm quite personally interested in this :) Could the use of cloning here be avoided by creating the impls manually?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@JosiahParry the most recent commit removes this use of clone :)

Copy link
Member

@michaelkirk michaelkirk 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 getting rid of that clone - this is getting closer!

geo/src/algorithm/euclidean_distance.rs Outdated Show resolved Hide resolved
geo/src/algorithm/euclidean_distance.rs Outdated Show resolved Hide resolved
T: GeoFloat + FloatConst + RTreeNum + FloatConst,
{
fn euclidean_distance(&self, other: &$for) -> T {
match self {
Copy link
Member

Choose a reason for hiding this comment

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

We end up doing this in a lot of places. You can use:

impl<T> EuclideanDistance<T, $for> for Geometry<T>  
where                                               
T: GeoFloat + FloatConst + RTreeNum
{                                                      
    crate::geometry_delegate_impl! {                 
        fn euclidean_distance(&self, other: &$for) -> T;  
    }                                                         
}      

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thanks! done

impl_euclidean_distance_for_iter_geometry!(MultiPoint<T>, [Point<T>, Line<T>, LineString<T>, MultiLineString<T>, Polygon<T>, MultiPolygon<T>, GeometryCollection<T>]);
impl_euclidean_distance_for_iter_geometry!(MultiLineString<T>, [Point<T>, Line<T>, LineString<T>, Polygon<T>, MultiPolygon<T>, GeometryCollection<T>]);
impl_euclidean_distance_for_iter_geometry!(MultiPolygon<T>, [Point<T>, Line<T>, LineString<T>, Polygon<T>, GeometryCollection<T>]);
impl_euclidean_distance_for_iter_geometry!(GeometryCollection<T>, [Point<T>, Line<T>, LineString<T>, Polygon<T>]);
Copy link
Member

@michaelkirk michaelkirk Jul 17, 2023

Choose a reason for hiding this comment

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

Each of these macros is taking a smaller list of input for the second parameter. I assume that's because the implementations have already been covered by a previous macro.

The trouble is, it's hard to review this and be confident that we didn't miss one.

For example, while geometry.euclidean_distance(&multi_polygon) is implemented, we are missing geometry.euclidean_distance(&multi_point).

One idea I had is, even though it might be more typing, to not have the macro implementation be reflexive.
e.g. only implement impl<T> EuclideanDistance<T, $target> for $for, but not the inverse impl<T> EuclideanDistance<T, $for> for $target.

I think that might make it easier to scan the source code for missing combinations. e.g. something like

impl_euclidean_distance_for_iter_geometry!(MultiPoint<T>,         [Point<T>, MultiPoint<T>, Line<T>, LineString<T>, MultiLineString<T>, Polygon<T>, MultiPolygon<T>, GeometryCollection<T>, Geometry<T>]);
impl_euclidean_distance_for_iter_geometry!(MultiLineString<T>,    [Point<T>, MultiPoint<T>, Line<T>, LineString<T>, MultiLineString<T>, Polygon<T>, MultiPolygon<T>, GeometryCollection<T>, Geometry<T>]);
impl_euclidean_distance_for_iter_geometry!(MultiPolygon<T>,       [Point<T>, MultiPoint<T>, Line<T>, LineString<T>, MultiLineString<T>, Polygon<T>, MultiPolygon<T>, GeometryCollection<T>, Geometry<T>]);
impl_euclidean_distance_for_iter_geometry!(GeometryCollection<T>, [Point<T>, MultiPoint<T>, Line<T>, LineString<T>, MultiLineString<T>, Polygon<T>, MultiPolygon<T>, GeometryCollection<T>, Geometry<T>]);

(Note I included Geometry in the second parameter list)

Possibly that second parameter could be baked into a macro itself so you don't have to type it all out, but I don't feel that strongly about that.

Similarly with the other macros.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, I agree that it's hard to see if any combinations are missing. I've now updated this to make the macro implementations not reflexive, and also re-organized the macros a bit. I hope that it's more readable and clear now.

One note regarding this point:

geometry.euclidean_distance(&multi_polygon) is implemented, we are missing geometry.euclidean_distance(&multi_point)

In the new version, all the implementations of euclidean distance between Geometry<T> and specific geometry types are handled by 2 separate macros, so Geometry<T> is not included in the parameter lists for the multi-geometry macros. This seemed cleaner, since we need to have impl<T> EuclideanDistance<T, Geometry<T>> for all geometry types.

fn euclidean_distance(&self, point: &Point<T>) -> T {
if self.intersects(point) {
return T::zero();
fn euclidean_distance(&self, other: &Geometry<T>) -> T {
Copy link
Member

Choose a reason for hiding this comment

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

My condolences to your wrists. 😉

I'd expect this to be implementable as

impl<T> EuclideanDistance<T> for Geometry<T>
 where T: GeoFloat + FloatConst 
{
    crate::geometry_delegate_impl! {
        fn euclidean_distance(&self, other: &Geometry<T>) -> T;
    }
}

Please revisit this method after addressing the missing implementations mentioned above.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thanks! done

@michaelkirk
Copy link
Member

Hi @mcassels, are you still interested in working on this? Let me know if you have any questions.

If you don't think you'll have time, I can try to finish it up.

@mcassels
Copy link
Contributor Author

mcassels commented Aug 1, 2023

@michaelkirk thanks for the review! I'm still planning to work on this, sorry for the delay -- been travelling with limited internet access. I'm hoping to get back to this within the next couple days

Copy link
Member

@michaelkirk michaelkirk left a comment

Choose a reason for hiding this comment

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

LGTM - thanks!

bors r+

@bors
Copy link
Contributor

bors bot commented Aug 7, 2023

Build succeeded!

The publicly hosted instance of bors-ng is deprecated and will go away soon.

If you want to self-host your own instance, instructions are here.
For more help, visit the forum.

If you want to switch to GitHub's built-in merge queue, visit their help page.

@bors bors bot merged commit 95176bb into georust:main Aug 7, 2023
13 checks passed
@JosiahParry
Copy link
Contributor

Amazing!

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.

3 participants