Search Unity

How can I show real-time GPS coordinates on a terrain created at unity?

Discussion in 'World Building' started by esoob, Mar 12, 2019.

  1. esoob

    esoob

    Joined:
    Mar 12, 2019
    Posts:
    10
    I get a terrain on terrain.map and created it in unity. I have a gps device and I want to show the real-time location information I received from this device on this terrain. Is this possible? How can I do if possible? Thank you from now.
     
  2. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Most GPS devices can be connected to, via TCP/IP, at which point the send data in NMEA format. You'd just need to decode the position sentences, convert global coordinates to your terrain in whatever way makes sense, and display accordingly.
     
  3. TerraUnity

    TerraUnity

    Joined:
    Aug 3, 2012
    Posts:
    1,251
    If you have the GPS track file, this is what you are looking for. This can be converted to a real-time app to show exact coordinates/position of the device on a streaming 3D map with its built-in automatic objects placement on terrain tiles.

     
  4. esoob

    esoob

    Joined:
    Mar 12, 2019
    Posts:
    10
    has terraland a GPS track file? because i will buy terraland
     
  5. TerraUnity

    TerraUnity

    Joined:
    Aug 3, 2012
    Posts:
    1,251
    The video above shows a custom enterprise project we've been working on for a company but the whole project is based on TerraLand's public streaming features and the custom part is that we've written a wrapper to convert GPS coords from a GPX file into Unity's world position and stream terrains around the player. Let me know if you need the solution and we'll negotiate on that.
     
  6. andrew-lukasik

    andrew-lukasik

    Joined:
    Jan 31, 2013
    Posts:
    249
    Imagine world X axis representing longitude and Z latitude. Then figure out what lon/lat Rect is your terrain representing. The rest is just simple arithmetic.
     
  7. esoob

    esoob

    Joined:
    Mar 12, 2019
    Posts:
    10
    İs there any tool like this? İ didn't see this before.
     
  8. andrew-lukasik

    andrew-lukasik

    Joined:
    Jan 31, 2013
    Posts:
    249
    No, it's just my own project-specific tools. But here, take a look at those value types I use for this, you may find these helpful in some capacity:

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. using Unity.Mathematics;
    4.  
    5.  
    6. [System.Serializable]
    7. public struct Coordinate
    8. {
    9.     #region FIELDS
    10.  
    11.  
    12.     public float latitude;
    13.     public float longitude;
    14.    
    15.  
    16.     #endregion
    17.     #region OPERATORS
    18.  
    19.  
    20.     public static Coordinate operator + ( Coordinate a , Coordinate b ) => new Coordinate{ latitude = a.latitude + b.latitude , longitude = a.longitude + b.longitude };
    21.     public static Coordinate operator - ( Coordinate a , Coordinate b ) => new Coordinate{ latitude = a.latitude - b.latitude , longitude = a.longitude - b.longitude };
    22.     public static Coordinate operator * ( Coordinate coord , float f ) => new Coordinate{ latitude = coord.latitude * f , longitude = coord.longitude * f };
    23.     public static bool operator == ( Coordinate a , Coordinate b ) => a.latitude==b.latitude && a.longitude==b.longitude;
    24.     public static bool operator != ( Coordinate a , Coordinate b ) => a.latitude!=b.latitude && a.longitude!=b.longitude;
    25.  
    26.  
    27.     #endregion
    28.     #region PUBLIC METHODS
    29.  
    30.  
    31.     public override bool Equals ( object obj )
    32.     {
    33.         if( obj==null || (obj is Coordinate)==false ) { return false; }
    34.         return this==(Coordinate)obj;
    35.     }
    36.  
    37.     override public string ToString () => JsonUtility.ToJson( this );
    38.  
    39.     public override int GetHashCode ()
    40.     {
    41.         unchecked
    42.         {
    43.             int hash = 17;
    44.             hash = hash * 31 + this.latitude.GetHashCode();
    45.             hash = hash * 31 + this.longitude.GetHashCode();
    46.             return hash;
    47.         }
    48.     }
    49.    
    50.     /// <summary> Calculates metric distance between two coordinates </summary>
    51.     public static double HaversineDistance ( Coordinate A , Coordinate B )
    52.     {
    53.         double DegreesToRadians ( double degrees ) { return (math.PI / 180d) * degrees; }
    54.         double R = 6371e3d;//metres
    55.         double φ1 = DegreesToRadians( A.latitude );
    56.         double φ2 = DegreesToRadians( B.latitude );
    57.         double Δφ = DegreesToRadians( B.latitude - A.latitude );
    58.         double Δλ = DegreesToRadians( B.longitude - A.longitude );
    59.         double a = math.sin( Δφ / 2d ) * math.sin( Δφ / 2d ) +
    60.                 math.cos( φ1 ) * math.cos( φ2 ) *
    61.                 math.sin( Δλ / 2d ) * math.sin( Δλ / 2d );
    62.         double c = 2d * math.atan2( math.sqrt( a ) , math.sqrt( 1d - a ) );
    63.         double d = R * c;
    64.         return d;
    65.     }
    66.  
    67.     #endregion
    68. }
    69.  
    70. [System.Serializable]
    71. public struct CoordinateRect
    72. {
    73.     #region FIELDS
    74.    
    75.    
    76.     public Coordinate a;
    77.     public Coordinate b;
    78.  
    79.    
    80.     #endregion
    81.     #region PROPERTIES
    82.  
    83.  
    84.     public Coordinate center { get{ return a + (b-a)*0.5f; } }
    85.  
    86.     public Coordinate cornerBottomLeft { get{ return new Coordinate{ latitude = math.min( a.latitude , b.latitude ) , longitude = math.min( a.longitude , b.longitude ) }; } }
    87.     public Coordinate cornerTopLeft { get{ return new Coordinate{ latitude = math.max( a.latitude , b.latitude ) , longitude = math.min( a.longitude , b.longitude ) }; } }
    88.     public Coordinate cornerTopRight { get{ return new Coordinate{ latitude = math.max( a.latitude , b.latitude ) , longitude = math.max( a.longitude , b.longitude ) }; } }
    89.     public Coordinate cornerBottomRight { get{ return new Coordinate{ latitude = math.min( a.latitude , b.latitude ) , longitude = math.max( a.longitude , b.longitude ) }; } }
    90.    
    91.     public float width { get{ return math.abs( a.longitude - b.longitude ); } }
    92.     public float height { get{ return math.abs( a.latitude - b.latitude ); } }
    93.     public float area { get{ return width * height; } }
    94.  
    95.     public float heightMeters { get{ return (float)Coordinate.HaversineDistance( this.cornerTopRight , this.cornerBottomRight ) ; } }
    96.     public float widthMeters { get{ return (float)Coordinate.HaversineDistance( this.cornerBottomLeft , this.cornerBottomRight ) ; } }
    97.     public float areaMeters { get{ return widthMeters * heightMeters; } }
    98.    
    99.  
    100.     #endregion
    101.     #region OPERATORS
    102.  
    103.  
    104.     public static CoordinateRect operator - ( CoordinateRect A , CoordinateRect B ) { return new CoordinateRect { a = A.cornerBottomLeft - B.cornerBottomLeft , b = A.cornerTopRight - B.cornerTopRight }; }
    105.     public static CoordinateRect operator - ( CoordinateRect rect , Coordinate point ) { return new CoordinateRect { a = rect.cornerBottomLeft - point , b = rect.cornerTopRight - point }; }
    106.     public static CoordinateRect operator + ( CoordinateRect A , CoordinateRect B ) { return new CoordinateRect { a = A.cornerBottomLeft + B.cornerBottomLeft , b = A.cornerTopRight + B.cornerTopRight }; }
    107.     public static CoordinateRect operator + ( CoordinateRect rect , Coordinate point ) { return new CoordinateRect { a = rect.cornerBottomLeft + point , b = rect.cornerTopRight + point }; }
    108.  
    109.     #endregion
    110.     #region PUBLIC METHODS
    111.  
    112.    
    113.     override public string ToString () { return JsonUtility.ToJson( this ); }
    114.  
    115.     public override int GetHashCode ()
    116.     {
    117.         unchecked
    118.         {
    119.             int hash = 17;
    120.             hash = hash * 31 + this.a.GetHashCode();
    121.             hash = hash * 31 + this.b.GetHashCode();
    122.             return hash;
    123.         }
    124.     }
    125.  
    126.    
    127.     public void Encapsulate ( CoordinateRect other )
    128.     {
    129.         var encapsulated = Encapsulate( this , other );
    130.         this.a = encapsulated.a;
    131.         this.b = encapsulated.b;
    132.     }
    133.     public static CoordinateRect Encapsulate ( CoordinateRect A , CoordinateRect B )
    134.     {
    135.         Coordinate bottomLeftA = A.cornerBottomLeft;
    136.         Coordinate bottomLeftB = B.cornerBottomLeft;
    137.         Coordinate topRightA = A.cornerTopRight;
    138.         Coordinate topRightB = B.cornerTopRight;
    139.         CoordinateRect result = new CoordinateRect {
    140.             a = new Coordinate {
    141.                 latitude = math.min( bottomLeftA.latitude , bottomLeftB.latitude ) ,
    142.                 longitude = math.min( bottomLeftA.longitude , bottomLeftB.longitude )
    143.             } ,
    144.             b = new Coordinate {
    145.                 latitude = math.max( topRightA.latitude , topRightB.latitude ) ,
    146.                 longitude = math.max( topRightA.longitude , topRightB.longitude )
    147.             }
    148.         };
    149.         return result;
    150.     }
    151.  
    152.    
    153.     public void Overlap ( CoordinateRect other )
    154.     {
    155.         var overlaped = Overlap( this , other );
    156.         this.a = overlaped.a;
    157.         this.b = overlaped.b;
    158.     }
    159.     public static CoordinateRect Overlap ( CoordinateRect A , CoordinateRect B )
    160.     {
    161.         Coordinate bottomLeftA = A.cornerBottomLeft;
    162.         Coordinate bottomLeftB = B.cornerBottomLeft;
    163.         Coordinate topRightA = A.cornerTopRight;
    164.         Coordinate topRightB = B.cornerTopRight;
    165.         CoordinateRect result = new CoordinateRect {
    166.             a = new Coordinate {
    167.                 latitude = math.max( bottomLeftA.latitude , bottomLeftB.latitude ) ,
    168.                 longitude = math.max( bottomLeftA.longitude , bottomLeftB.longitude )
    169.             } ,
    170.             b = new Coordinate {
    171.                 latitude = math.min( topRightA.latitude , topRightB.latitude ) ,
    172.                 longitude = math.min( topRightA.longitude , topRightB.longitude )
    173.             }
    174.         };
    175.         return result;
    176.     }
    177.  
    178.    
    179.     public bool Overlaps ( CoordinateRect other )
    180.     {
    181.         return Overlaps( this , other );
    182.     }
    183.     public static bool Overlaps ( CoordinateRect A , CoordinateRect B )
    184.     {
    185.         Coordinate Ac = A.center;
    186.         Coordinate Bc = B.center;
    187.         return ( math.abs(Ac.longitude - Bc.longitude) * 2f < (A.width + B.width)) && ( math.abs(Ac.latitude - Bc.latitude) * 2f < (A.height + B.height));
    188.     }
    189.  
    190.  
    191.     /// <summary> Calculates overlap relative to primary rect, results is normalized (according to primary width/height) </summary>
    192.     public FloatRange2 RelativeOverlap ( CoordinateRect secondary )
    193.     {
    194.         return RelativeOverlap( this , secondary );
    195.     }
    196.     /// <summary> Calculates overlap relative to primary rect, results is normalized (according to primary width/height) </summary>
    197.     public static FloatRange2 RelativeOverlap ( CoordinateRect primary , CoordinateRect secondary )
    198.     {
    199.         CoordinateRect overlap = Overlap( primary , secondary );
    200.         CoordinateRect overlapRelativeToPrimary = overlap - primary.cornerBottomLeft;
    201.         Coordinate overlapBottomLeft = overlapRelativeToPrimary.cornerBottomLeft;
    202.         Coordinate overlapTopRight = overlapRelativeToPrimary.cornerTopRight;
    203.         float primaryWidth = primary.width;
    204.         float primaryHeight = primary.height;
    205.         var result = new FloatRange2 {
    206.             x = new FloatRange {
    207.                 min = overlapBottomLeft.longitude / primaryWidth ,
    208.                 max = overlapTopRight.longitude / primaryWidth
    209.             } ,
    210.             y = new FloatRange {
    211.                 min = overlapBottomLeft.latitude / primaryHeight ,
    212.                 max = overlapTopRight.latitude / primaryHeight
    213.             }
    214.         };
    215.       return result;
    216.     }
    217.  
    218.  
    219.     #endregion
    220. }
    221.  
    222. [System.Serializable]
    223. public struct FloatRange
    224. {
    225.     public float min, max;
    226.     public float range => max - min;
    227.     override public string ToString () { return $"{ '{' }{ UnityEngine.JsonUtility.ToJson( this ) }{ '}' }"; }
    228. }
    229.  
    230. [System.Serializable]
    231. public struct FloatRange2
    232. {
    233.     public FloatRange x, y;
    234.    
    235.     public float width => x.max - x.min;
    236.     public float height => y.max - y.min;
    237.  
    238.     override public string ToString () { return UnityEngine.JsonUtility.ToJson( this ); }
    239. }
    240.  
     
  9. esoob

    esoob

    Joined:
    Mar 12, 2019
    Posts:
    10
    thank you soo much, I will examine in detail.
     
  10. TerraUnity

    TerraUnity

    Joined:
    Aug 3, 2012
    Posts:
    1,251
  11. andrew-lukasik

    andrew-lukasik

    Joined:
    Jan 31, 2013
    Posts:
    249
    As @TerraUnity pointed out - yup, these are a naive calculations to get you off the ground and will only work for small terrain samples. These were totally enough in my case but may become unusable in cases where more precision is required.

    Hey @esoob , you may want to check this solution grabbed directly from my project (requires struct types from posts above)
    Code (CSharp):
    1. public static Vector3 CoordinateToWorldPosition ( Terrain terrain , CoordinateRect terrainRect , Coordinate coordinate )
    2. {
    3.     var size = terrain.terrainData.bounds.size;
    4.     var center = terrainRect.center;
    5.     var localPosition = new Vector3
    6.     {
    7.         z = ( size.z / terrainRect.height ) * ( coordinate.latitude - center.latitude ) ,
    8.         x = ( size.x / terrainRect.width ) * ( coordinate.longitude - center.longitude )
    9.     };
    10.     return terrain.transform.TransformPoint( localPosition );
    11. }
    12.  
    Code (CSharp):
    1. public static Coordinate WorldPositionToCoordinate ( Terrain terrain , CoordinateRect terrainRect , Vector3 worldPosition )
    2. {
    3.     var localPosition = terrain.transform.InverseTransformPoint( worldPosition );
    4.     var extents = terrain.terrainData.bounds.extents;
    5.     var center = terrainRect.center;
    6.     return new Coordinate
    7.     {
    8.         latitude = center.latitude + (localPosition.z / extents.z) * (terrainRect.height * 0.5f) ,
    9.         longitude = center.longitude + (localPosition.x / extents.x) * (terrainRect.width * 0.5f)
    10.     };
    11. }
     
    esoob and TerraUnity like this.
  12. TerraUnity

    TerraUnity

    Joined:
    Aug 3, 2012
    Posts:
    1,251
    FYI, there is a geo-referencing scene in TerraLand now which outputs very accurate world positions in Mercator projection even in areas above 1000 km.
     
  13. esoob

    esoob

    Joined:
    Mar 12, 2019
    Posts:
    10
    Thank you for your help, I get my gps coordinate and ı create a terrain with @TerraUnity and now İ will show my position on the terrain. actually i hope i can..
     
  14. TerraUnity

    TerraUnity

    Joined:
    Aug 3, 2012
    Posts:
    1,251
    In TerraLand package, find the scene "LatLon2UnityWorldSpace" in the Scenes directory in project and load the scene to see the implementation and source code of the Mercator version of geo-coding and its comparison with the less accurate one. https://twitter.com/TerraUnity/status/1119866346714669057
     
  15. esoob

    esoob

    Joined:
    Mar 12, 2019
    Posts:
    10
    yes, I see this before, but when i want to add a build on specific coordinate ı used "LatLon2UnityWorldSpace" te build come to right coordinate but under the terrain.
     
  16. TerraUnity

    TerraUnity

    Joined:
    Aug 3, 2012
    Posts:
    1,251
    The geo-referencing script does not take into account the surface height when places objects and only sets x & z axis on the object transform but returning terrain/surface height under object is simple which you can add that feature like we did in the above video.
     
  17. Akhil1195

    Akhil1195

    Joined:
    Aug 19, 2019
    Posts:
    3
     
  18. WayneVenter

    WayneVenter

    Joined:
    May 8, 2019
    Posts:
    56
    Hi @TerraUnity I bought your TeraWorld asset and wanted to confirm if the LatLon2UnityWorldSpace is available in TerraWorld or only in TerraLand?
     
  19. TerraUnity

    TerraUnity

    Joined:
    Aug 3, 2012
    Posts:
    1,251
    It's only available in TerraLand but if you own TerraLand, you can use that script in any other projects like TerraWorld to do geo-referencing as it's a helper script which works in any scenes as long as you know the info it needs.