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

Validity of longitudes and latitudes #52

Open
anowacki opened this issue Oct 1, 2019 · 3 comments
Open

Validity of longitudes and latitudes #52

anowacki opened this issue Oct 1, 2019 · 3 comments

Comments

@anowacki
Copy link
Contributor

anowacki commented Oct 1, 2019

Currently, no check is done on the range of values when either constructing or converting LLAs or LatLons:

julia> using Geodesy

julia> p = LLA(lat=1000.0, lon=1000.0, alt=0.0)
LLA(lat=1000.0°, lon=1000.0°, alt=0.0)

julia> ECEF(p, wgs84)
ECEF(192951.75490366874, -1.0942837796485086e6, -6.25954296102869e6)

julia> ENU(p, p, wgs84)
ENU(0.0, 0.0, 0.0)

julia> UTMZ(p, wgs84)
UTMZ(NaN, NaN, 0.0, zone=polar (north))

(It appears the ECEF conversion works as if the latitude wraps around over the pole, whilst clearly the UTM conversion needs valid latitudes.)

It is also the case that longitudes are compared as if they are linear numbers, when in reality they are periodic, and thus two points can represent the same position when n × 360° apart but not be 'equal':

julia> p1, p2 = LLA(0, 10, 0), LLA(0, 370, 0);

julia> p1 == p2
false

julia> ECEF(p1, wgs84) == ECEF(p2, wgs84)
true

This raises a few questions:

  1. Should latitudes be enforced to be in the correct range? I guess doing so in an inner constructor may reduce performance, but I haven't checked this.
  2. Should converting a permitted invalid latitude return nonsense values, an error, or a 'bad value' flag (as is currently done I think inadvertently for the UTM conversion)?
  3. Should longitudes:
    a. be normalised to a range on construction (say [–180,180] or [0,360]); or
    b. be compared modulo 360 when comparing LLAs and LatLons; or
    c. remain unnormalised and points only be equal when longitudes are strictly the same?

Letting the user make their own mistakes is an acceptable approach, but I think it should be noted carefully somewhere if this is the case. Alternatively, the safety net of bailing out when abs(latitude) > 90 is often worth the effort, not least since it quite often might catch cases of latitude and longitude being mixed up!

Happy to submit a PR for whichever route is best.

(My own preference would be for enforcement of -90 ≤ lat ≤ 90 in construction for LLAs and LatLons, and modulo-360 comparison of longitudes. This allows one to keep longitudes around some arbitrary meridian.)

@c42f
Copy link
Member

c42f commented Oct 2, 2019

Good questions.

  1. Tentatively, yes. This seems helpful and not too expensive.
  2. For UTM conversion, it's always possible to validate the input if necessary. The UTM conversion is complicated and I'd be surprised if we saw any measurable performance hit.
  3. Um, this one is hard. The type of equality operation distinguishes between comparing values in the coordinate system vs comparing points on the underlying manifold. Which is most useful? Comparison mod 360 is always going to run afoul of numerical precision if floats are used:
julia> lon = 1/60  # one arc minute
0.016666666666666666

julia> (lon + 360) - 360 == lon
false

@andyferris
Copy link
Contributor

This is really interesting. Where should the validation occur? We can definitely verify that the latitude is sensible for UTM conversions and catch that case. Should user's be expected to do the same with their code? Or should the inner constructor do it for them?

I could go any way on this... I'd probably be tempted to trust the user to do the right thing and just treat LLA as a simple struct (without invariants enforced) and let operations worry about that, but that is not a strong opinion.

@c42f
Copy link
Member

c42f commented Oct 2, 2019

Yes I could go either way as well. Having the LLA as "simple data" has certian advantages, for example it allows you to reinterpret a buffer of a separate type as LLAs which could be handy for interop. It also makes things more flexible when dealing with data from outside Geodesy which may want different or broken invariants. A good analogy here is String which allows invalid UTF-8 data for the same reasons:

julia> s = "\xff"
"\xff"

julia> s[1]
'\xff': Malformed UTF-8 (category Ma: Malformed, bad data)

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

No branches or pull requests

3 participants