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

Converting coordinates (Vector3 to latlngAltitude) #887

Open
ashkalor opened this issue Oct 26, 2023 · 8 comments
Open

Converting coordinates (Vector3 to latlngAltitude) #887

ashkalor opened this issue Oct 26, 2023 · 8 comments
Labels
priority: p2 Moderately-important priority. Fix may not be included in next release. type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design.

Comments

@ashkalor
Copy link

Hello,

I've noticed that the library provides support for converting from latitude, longitude, and altitude (latLngAltitude) to vector3 coordinates. However, I'm unable to figure out how to convert from vector3 coordinates to a latLng literal. Is this something that is planned for the future roadmap? I did see a pull request mentioning this (#618), but it seems that the pull request has been closed.

It would be a great help if you could provide an update on this matter.

Thanks.

@ashkalor ashkalor added triage me I really want to be triaged. type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design. labels Oct 26, 2023
@wangela
Copy link
Member

wangela commented Oct 26, 2023

If you would like to upvote the priority of this issue, please comment below or react on the original post above with 👍 so we can see what is popular when we triage.

@ashkalor Thank you for opening this issue. 🙏
Please check out these other resources that might help you get to a resolution in the meantime:

This is an automated message, feel free to ignore.

@usefulthink
Copy link
Contributor

The minmal functionality for that is still there: https://github.com/googlemaps/js-three/blob/main/src/util.ts#L89-L96

That function will convert an [x, y] coordinate (in mercator-projection) to a LatLngLiteral.

To get from your three.js coordinates to mercator-meters you need to apply the spherical scale factor of the mercator-projection – cos(degToRad(reference.lat))). So to fully convert that'd be something like

function vec3ToLatLngAlt(vec3: Vector3, anchor: LatLngAltitudeLiteral) {
  const z = vec3.z;

  vec3.multiplyScalar(1 / cos(degToRad(anchor.lat))));
  const {lat, lng} = xyToLatLng([vec3.x, vec3.y]);

  return {lat, lng, altitude: anchor.altitude + z};
}

(this is assuming that you're using the default up-axis, otherwise you still have to apply the axis rotation before everything else).

All that said, I'm open to adding this as a method to the overlay class when I get around to do it.

@usefulthink usefulthink added priority: p2 Moderately-important priority. Fix may not be included in next release. and removed triage me I really want to be triaged. labels Oct 26, 2023
@MstrD
Copy link

MstrD commented May 16, 2024

@usefulthink I am having the same problem described in this thread. I tried applying the function you provided above, but it doesn't seem to be right.

The values did not match. However, I've noticed that the values are extremely close if the function is something like this:

const vec3ToLatLngAlt = (vec3: Vector3, anchor: LatLngAltitudeLiteral) => {
    const z = vec3.z;

    vec3.multiplyScalar(1 / Math.cos(MathUtils.degToRad(anchor.lat)));
    const { lat, lng } = xyToLatLng([vec3.x, vec3.y]);

    return { lat: anchor.lat + lat, lng: anchor.lng + lng, altitude: anchor.altitude + z };
};

The values seem to be correct when the return value is the sum of the computed lat/lng with the anchor lat/lng. Moreover, I've noticed that the lng matches the exact geographic coordinate (listened in a Google Maps Event), but lat has a small deviation from the original coordinate.

Is there any calculation that may be missing in order to achieve the exact lat value? Or could this be a floating point problem?

Thank you in advance.

@usefulthink
Copy link
Contributor

That's a very good point, I did somehow miss adding the anchor lat/lng values to the result.

but lat has a small deviation from the original coordinate.

How small are we talking here?
Can you provide some concrete values for vec3, anchor and the expected and actual results?

@MstrD
Copy link

MstrD commented May 17, 2024

@usefulthink yes, of course.

How small are we talking here?

It seems that, the further away from the anchor, the larger the deviation is.

In the following examples, my anchor point is:

{
    "altitude": 0,
    "lat": 40.7127753,
    "lng": -74.0059728
}

The first example is a click very close to the anchor point. When I click on the map, the Google Maps listener event tells me this point has the following geographic coordinates:

{
    "lat": 40.713043413517056,
    "lng": -74.00622962150632
}

This point converts to the following Vector3 in local coordinates:

{
    "x": -21.64611191882111,
    "y": 29.81296967957644,
    "z": 0
}

And when I try to reconvert it to geographic coordinates by using the function I provided above, this is the result:

{
    "lat": 40.7131290176473,
    "lng": -74.00622962150632
}

Notice how the lng values between the expected and the actual result are exactly the same, but with lat having that small discrepancy (in this case, with a value of 0.00008560413024127911).

Visually, the deviation corresponds to the following:
3jsoverlayview

Finally, an example with the same anchor, but using a point much further away from it. Its Google Maps coordinates are:

{
    "lat": 41.27495703856301,
    "lng": -73.9395450002507
}

These coordinates translate to the following Vector3, in local space:

{
    "x": 5598.84414844186,
    "y": 62778.270074034874,
    "z": 0
}

Which, when reconverted to geographic coordinates using that same method, return the following value:

{
    "lat": 41.45759062062852,
    "lng": -73.9395450002507
}

Please notice again how the lng value is the same, but how the deviation in lat has increased regarding the previous example. This time, its value is 0.18263358206551317 (a very considerable value).

Thank you very much for your support.

@MstrD
Copy link

MstrD commented May 20, 2024

@usefulthink after spending some time researching and studying how proj4 works and why the values were not matching (also inspired by what I've read in another issue of this project), I ended up fixing this function. It should be something like this:

const vec3ToLatLngAlt = (vec3: Vector3, anchor: any = _threejsOverlay.anchor) => {
    vec3.applyQuaternion(_threejsOverlay.rotationInverse.clone().invert());

    const z = vec3.z;

    const [anchorX, anchorY] = latLngToXY(anchor);

    vec3.multiplyScalar(1 / Math.cos(MathUtils.degToRad(anchor.lat)));

    const { lat, lng } = xyToLatLng([vec3.x + anchorX, vec3.y + anchorY]);

    return { lat, lng, altitude: anchor.altitude + z };
};

The return values of this function (lat and lng) are now exactly the same as the ones read in a Google Maps event (or, worst case scenario, only rounded to the 15th decimal place - which, for my use case, is neglegible).

It would be pretty nice to have this function added to the source code, since it's useful and it's not that trivial to make these calculations.

@usefulthink
Copy link
Contributor

That makes a lot of sense, thanks for taking the time to figure this out!
Do you want to prepare a PR or should I just take your code and integrate it?

@MstrD
Copy link

MstrD commented May 22, 2024

You can just integrate this code if you want. I'll just add that the vec3 passed as an argument should be cloned before performing these calculations, because it shouldn't be modified. So, in the end, the function would be something like this:

const vector3ToLatLngAlt = (vec3: Vector3, anchor: google.maps.LatLngAltitude = overlay.anchor) => {
    const vector3 = vec3.clone();

    vector3.applyQuaternion(overlay.rotationInverse.clone().invert());

    const z = vector3.z;

    const [anchorX, anchorY] = latLngToXY(anchor);

    vector3.multiplyScalar(1 / Math.cos(MathUtils.degToRad(anchor.lat)));

    const { lat, lng } = xyToLatLng([vector3.x + anchorX, vector3.y + anchorY]);

    return { lat, lng, altitude: anchor.altitude + z };
};

Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
priority: p2 Moderately-important priority. Fix may not be included in next release. type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design.
Projects
None yet
Development

No branches or pull requests

4 participants