• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by jeango · Jun 24, 2019 at 01:14 PM · gps

How to get accurate in-game coordinates based on GPS coordinates on a Lambert2008 projection?

Hi, I'm building a geo-localisation game where people have to go to a specific location.

I want to display a map of their surroundings, and place markers on that map to indicate - where the player is - the target location

I found some bits of code on the net that allows me to turn a gps coordinate into an in-game coordinate, but the problem is that the result is always a few (about 20 or so) meters off. But 20m is a lot for the purpose of my app.

All the code I found assumes that the earth is a sphere, but since the earth is not exactly a sphere I guess that's where my difference comes from. Here's the code I'm currently using.

     public static Vector3 GpsToGameCoord(Vector2 gpsCoordinates, float scale)
     {
         Vector3 result = Vector3.zero;
         // latitude is vertical, longitude is horizontal, so we need to inverse the values.
         result.y = gpsCoordinates.x * Mathf.Deg2Rad * earthRadius;
         result.x = gpsCoordinates.y * Mathf.Deg2Rad * earthRadius;
         result *= scale;
         return result;
     }


Is there a library out there that I could use to have more precision? An asset would work too, but I don't need a full blown geolocalisation asset bundled with all kinds of thing I don't need.


Edit: answered some questions in the comments


I'm using official gouvernement maps (the ones they use in the military etc...) the projection is Lambert2008 ( http://www.ngi.be/FR/FR2-1-7.shtm )


The waypoints coordinates come from Google maps, they're entered directly in the inspector, so don't rely on GPS accuracy. The player location however depends on device GPS, obviously.


The game always happen at the same location (it's for a hotel resort, game happens in the woods nearby), so I only need a tiny patch of map like you say..


For simplification, my map always points north, I don't try to rotate it according to player orientation. To position the waypoints, I pick a point on the map as my center point (recognisable landmark, so I can have accurate GPS coordinates from google maps). All the waypoints and player ping are positioned relative to that center point using my GpsToGameCoord method.


To scale my map properly, I pick three coordinates to triangulate the distance between each of them, and then scale the map manually in the editor (of course keeping the same aspect ratio) so that the waypoints match their location on the map. My problem though, is that with the waypoints I get, there is no way to scale the map in order to achieve a satisfying correspondance to my triangulation.


Followup: I modified the GpsToGameCoord method when I realised the radius I'm using should be the radius of the latitude circle at my coordinates, and not the earth radius. I know it's still an approximation, because the method still assumes the earth is a sphere and not an elipsoïd.

     public static Vector3 GpsToGameCoord(Vector2 gpsCoordinates, float scale)
     {
         Vector3 result = Vector3.zero;
         // latitude is vertical, longitude is horizontal, so we need to inverse the values.
         result.y = gpsCoordinates.x * Mathf.Deg2Rad * poleRadius;
         result.x = gpsCoordinates.y * Mathf.Deg2Rad * eqRadius * Mathf.Cos(gpsCoordinates.x * Mathf.Deg2Rad);
         result *= scale;
         return result;
     }



Here's what the problem was with the old implementation:

alt text


Here's what the game looks like with the new implementation of my method. Everything is actually much closer.

alt text


As you can see it's a lot better.

Comment
Add comment · Show 2
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Casiell · Jun 24, 2019 at 02:14 PM 2
Share

Isn't the top tier GPS precision like 5m in an open field? Near buildings it is likely worse. Also high precision is not really something you can rely on. One of the biggest GPS-based games right now (Pokemon GO) has absolutely garbage accuracy and they are not really a small company.

Also did you turn on high-precision localization in your smartphone settings?

avatar image TreyH · Jun 24, 2019 at 04:36 PM 0
Share

Others have pointed out that coordinates like that (degrees) aren't going to have a clean representation in your world out of the box.


Accuracy will always be a consideration for the actual coordinates you get, but getting a metered representation of some lat/lon is often done by converting that point into metered east/north through UT$$anonymous$$ zones.

Those east/north values are usually quite large though and often exceed floating point precision. To get around that, you'd pick some coordinate as a local origin using doubles ins$$anonymous$$d of floats. You'd then take your converted east/north points, get the difference with your origin, and float-cast that difference for your scene's simulated Vector3 positions.

2 Replies

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by jeango · Jun 26, 2019 at 12:36 PM

Thanks to @Bunny83 I looked up the projection used for my map which is a specific projection used by the Belgian National Geographic Institute. On their website I found this pdf with all the formulas used to convert geographic coordinates into Lambert2008 coordinates.

http://www.ngi.be/Common/Lambert2008/Transformation_Geographic_Lambert_FR.pdf

I made a static class to transcribe those formulas into code. now I get results with a 24cm precision (as long as I use Belgian official maps).

If you're wondering, I use double precision because it's actually faster than floats (using System.Math instead of UnityEngine.Mathf )

Since this is quite specific, I updated the original question title. Maybe this helps someone in the future, who knows.

Here's the code, feel free to use it for your own inscrutable purposes.

     public static class Lambert2008
     {
         public const int a = 6378137;
         public const double f = 1 / 298.257222101;
         public const double lowerLatitude = 49.8333333 * Mathf.Deg2Rad;
         public const double upperLatitude = 51.1666667 * Mathf.Deg2Rad;
         public const double originLatitude = 50.797815 * Mathf.Deg2Rad;
         public const double originLongitude = 4.359215833 * Mathf.Deg2Rad;
         public const int originX = 649328;
         public const int originY = 665262;
         public static double Excentricity {get => System.Math.Sqrt((2 * f) - (f * f));}
 
         static double MLower { get => M(lowerLatitude);}
         static double MUpper { get => M(upperLatitude);}
 
         static double M(double latitude)
         {
             return System.Math.Cos(latitude) / System.Math.Sqrt(1 - (Excentricity * Excentricity * System.Math.Pow(System.Math.Sin(latitude), 2)));
         }
 
         static double TLower { get => T(lowerLatitude); }
         static double TUpper { get => T(upperLatitude); }
         static double TOrigin { get => T(originLatitude); }
 
         static double T(double latitude)
         {
             return System.Math.Tan(Mathf.PI / 4 - latitude / 2) / System.Math.Pow((1 - Excentricity * System.Math.Sin(latitude)) / (1 + Excentricity * System.Math.Sin(latitude)), Excentricity / 2);
         }
 
         static double N { get => (System.Math.Log(MLower) - System.Math.Log(MUpper)) / (System.Math.Log(TLower) - System.Math.Log(TUpper)); }
 
         static double G { get => MLower / (N * System.Math.Pow(TLower, N)); }
 
         static double ROrigin { get => R(TOrigin); }
 
         static double R (double t)
         {
             return a * G * System.Math.Pow(t, N);
         }
 
         public static Vector2 FromGeographic(Vector2 coordinates)
         {
 
             double t = T((double)coordinates.x * Mathf.Deg2Rad);
             double r = R(t);
             double angle = N * ((double)coordinates.y * Mathf.Deg2Rad - originLongitude);
             Vector2 lambertCoord = new Vector2
             {
                 x = (float) (originX + r * System.Math.Sin(angle)),
                 y = (float) (originY + ROrigin - r * System.Math.Cos(angle))
             };
             return lambertCoord;
 
         }
     }
 
Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Bunny83 · Jun 27, 2019 at 12:59 PM 0
Share

I would highly recommend that you convert all your static readonly properties into static fields. You add a lot unnecessary calculations to your "FromGeographic" method. All of those static properties are based on static data that never changes. At the moment you recalculate all of them each time it's called. Also there's quite a bit method nesting going on. Also since you use double for most of your calculations you should get rid or all those $$anonymous$$athf constants like PI or Deg2Rad which are defined in single precision FP and are converted to double each time. You may also pre define some constants as double like PI/4.


Note that the C# compiler is smart enough to order the field initializers of static fields in the right order automatically as long as there are not circular references in which case you get a compiler error anyways.

avatar image
2

Answer by Bunny83 · Jun 24, 2019 at 04:14 PM

Your question does not have a valid answer since in-game coordinates are arbitrary virtual coordinates. You have to give them some meaning / relation to the real world. In your case it entirely depends on where your "map" comes from, what projection it uses and what coordinate system it uses. Most maps are WGS84 based but don't have to. The most common map projection is the Mercator projection but again it doesn't have to be. Finally if you have only a tiny patch of map you have to know specific reference points on your map (the 4 corners) in order to do any conversion.


Like Casiell said GPS isn't really that precise to begin with and the accuracy depends heavily on various factors (like how many satellites are in view, how much the signals are distorted due to atmospheric effects or other obstacles, ...). That's why for higher precision geo location DGPS is used (which requires realtime access to the differential data from a DGPS network). For indoor navigation GPS is never a good choice due to the shielding of the walls and ceilings. That's why there are seperate IPS systems


Finally I don't quite get what your code is supposed to calculate. GPS coordinates represent a polar coordinate system. So the latitude and longitude represent angles. You convert the angles from degrees into radians and then multiply be the earthRadius? What do you expect as a result? Keep in mind that the Mercator projection get more and more distorted on the longitude the further you get north or south.


So there's a lot details missing on your side without that we can't really answer your question.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image jeango · Jun 25, 2019 at 07:56 AM 0
Share

I edited the post with more info as well as some progress made in my implementation

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

109 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Do unity3d have GPS interface? 1 Answer

adding gps google map in my app in unity3d 0 Answers

Detect car acceleration with device motion sensors and GPS 0 Answers

Does ARCore have something equivalent to ARKit's CoreLocation? 0 Answers

App asking for Camera permissions but not Location permissions? 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges