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

[wip] First attempts at implementing Haversine distance #48

Closed
wants to merge 6 commits into from

Conversation

tmcw
Copy link
Contributor

@tmcw tmcw commented Jul 21, 2016

This very much doesn't work yet. We're requiring the Float trait, but I want to use .to_radians() instead of doing it the manual multiplication way, an in order to require that the numeric type has that method, it requires a new trait, ToRadians, and currently that wreaks some havoc on the rest of the rust-geo codebase and I'm still learning why.

@frewsxcv
Copy link
Member

So you're looking to have a to_radians method available on all types that implement Float.

In general with Rust, the way to create new methods on types is through traits. In this particular case:

trait ToRadians<T> {
    fn to_radians(self) -> T;
}

ToRadians takes a type parameter T which specifies what the output type should be. Note that declaring this trait by itself doesn't allow us to use it anywhere yet. It's sort of like comparing "function declarations" vs. "function definitions", just the signature of the trait.

Anyways, we want ToRadians to operate on types that implement Float:

impl<F: Float> ToRadians<F> for F {
    fn to_radians(self) -> F {
        // code here
    }
}

This is an generic trait implementation (impl) for any type that implements Float. self here is an F (you could optionally write to_radians(self: F)) and the output type is an F. For more info about this, see these sections of the book:

Anyways, now for the meat of the implementation:

impl<F: Float> ToRadians<F> for F {
    fn to_radians(self) -> F {
        self * F::from(PI / 180f64).unwrap()
    }
}

As you can see here, Float is a sub-trait of Num (all the methods of Num are available to Float). You'll see that Num is a sub-trait of Mul<Self>. This means that any type that implements Float can be multiplied by the same type as itself. In this case, we want to multiply an F with an F. We want to multiply F with an F such that the second F is pi/180. We need to construct an F that is that value. Float is sub-trait of NumCast which offers a from method for construction from primitive types (it returns an Option because it can presumably fail for some reason or another).

You should be able to put this trait and impl in some module in rust-geo. Wherever you need to use the to_radians method on a Float, you should just need to use path::to::ToRadians and be good to go.

I hastily wrote this as I'm pretty busy with some work things, so sorry if there's any typos. Also, don't hesitate if you have any questions.

@frewsxcv
Copy link
Member

Also, in case it makes it easier to understand, here's how it would be implemented with a plain old function:

fn to_radians<F: Float>(x: F) -> F {
    x * F::from(PI / 180f64).unwrap()
}

@tmcw
Copy link
Contributor Author

tmcw commented Jul 22, 2016

@frewsxcv thanks for the input! There is one bit of the implementation which had a slightly different intent, though: to_radians is a built-in method of the f64 and f32 types - I was originally going to just implement it from scratch, but when I noticed that there was a built-in, went through these hoops in an effort to use it, rather than implementing it anew on a different type.

@frewsxcv
Copy link
Member

Oh wow, totally missed that it was already implemented for f64 and f32. Considering that, it might make sense for the to_radians and to_degrees methods to get implemented on Float in rust-num. I just opened rust-num/num#211.

@frewsxcv
Copy link
Member

FYI, to_radians and to_degrees support for Float got added in rust-num/num#212, so you should be able to use it once they cut a new release (you could just point to the git repo right now in cargo until then).

@frewsxcv
Copy link
Member

New version of rust-num just got published.

@tmcw
Copy link
Contributor Author

tmcw commented Jul 24, 2016

👍 awesome, taking another shot at this branch.

@tmcw
Copy link
Contributor Author

tmcw commented Jul 24, 2016

The baseline algorithm is implemented, and matches with a javascripty baseline! Now to think about how to expose it - right now it's very separate from the existing distance algorithm, but now looking at how .length() is implemented I think I'm starting to get why the templated function might be a good idea - it'd let you use different distance methods as the internal workings of length...

@frewsxcv
Copy link
Member

it'd let you use different distance methods as the internal workings of length...

That's a good point. If we went the type parameter route for distance, it would probably make sense to apply the same type parameter to the length function as well (unless I'm overlooking something here).

@tmcw tmcw force-pushed the haversine-distance branch from b88809a to e26beeb Compare August 21, 2016 21:42
@notriddle
Copy link

Superseded by #62.

@notriddle notriddle closed this Nov 4, 2016
@frewsxcv frewsxcv deleted the haversine-distance branch June 4, 2018 03:43
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