Search code examples
androidfluttergoogle-mapsmathgps

Convert GPS Coordinates to Match Custom 2d outdoor layout Image


I don't know if this is possible, but I am trying to take the image of a custom outdoor football field layout and have the players' GPS coordinates correspond to the image xand y position. This way, it can be viewed via the app to show the players' current location on the field as a sort of live tracking.

I have also looked into this Convert GPS coordinates to coordinate plane. The problem is that I don't know if this would work and wanted to confirm beforehand. The image provided in the post was for indoor location, and it was from 11 years ago.

I used Location and Google Maps packages for flutter. The player's latitude and longitude correspond to the actual latitude and longitude that the simulator in the android studio shows when tested.

The layout in question and a close comparison to the result I am looking for.

enter image description here

Edit:

After looking more at the matter I tried the answer of this post GPS Conversion - pixel coords to GPS coords, but it wasn't working as intended. I took some points on the image and the correspond coordinates, and followed the same logic that the answer used, but reversed it to give me the actual image X, Ypositions.

The formula that was given in the post above:

screenY0 //Screen origin (pixel corresponding to zero degrees latitude)
worldY0 //World origin (zero degrees latitude)
screenYscale //Screen scale (distance between 2 pixels)
worldYscale //World scale (distance between two latitude lines)
screenYpoint //Screen point (pixel y location)
worldYpoint //World point (latitude on the ground)   

screenY0 + screenYscale * screenYpoint = worldY0 + worldYscale * worldYpoint.

The post said there would be some inaccuracy about 7.4 meters. The solution provided works only for the points or areas close to the chosen point. When a player would move a bit more, the marker for that player would jump outside of the image area or be very far off.

Edit2:

I have tried the solution from this post Convert GPS coordinates to coordinate plane with the following formula to calculate the Xposition:

delta_long to be the differences, in degrees, in the GPS of the fields corners. delta_xis the width of the image.

horizontal_scale = delta_x/(cos(latitude)*delta_long) and then x = ( lon - lon_origin ) * horizontal_scaleThe issue that I am facing right now is that the marker moves at the opposite x-axis like this, where the black arrow is how the actual player moves and the red arrow shows how the player moves inside the app.

enter image description here


Solution

  • First of All, Yes you can do this with high accuracy if the GPS coordinates are accurate.

    Second, the main problem is rotation if the field are straight with lat lng lines this would be easy and straightforward (no bun intended).

    The easy way is to convert coordinate to rotated image similar to the real field then rotated every X,Y point to the new straight image. (see the image below)

    enter image description here

    Here is how to rotate x,y knowing the angel:

    double x,y;
    double newX,newY;
    double angle;
    
    //Test values:
    x=1;
    y=1;
    angle = 45;
    
    double rad = angle*M_PI/180;
    
    newX = x * cos(rad) - y * sin(rad);
    newY = y * cos(rad) + x * sin(rad);
    

    UPDATE

    long double lat1,lat2,lng1,lng2; //fill these with GPS coordinates
    double x1,x2,y1,y2;//fill these of rectangle coordinate in the image
    
    long double realWidth = distance(lat1, long1,lat2,long1);// distance btween the upper left corner & the upper right corner
    long double realHieght = distance(lat1, long1,lat1,long2);// distance btween the upper left corner & the lower left corner
    
    double image1Width = abs(x2-x1);
    double image1Hieght = abs(y2-y1);
    
    long double playerLat,playerLng;//fill the player lat lng GPS coordiantes 
    
    POINT imagePlayerXY = convertGPS2xy(lat1,  lng1, playerLat,  playerLng, realWidth, realHieght, image1Width, image1Hieght);
    //NOW rotate imagePlayerXY.x & imagePlayerXY.y to the final image
    
    POINT convertGPS2xy(long double latOrigin, long double lngOrigin,long double playerLat, long double playerLng,long double realWidth,long double realHieght, double image1Width,double image1Hieght)
    {
        double lngRatio2Width = distance(playerLat,playerLng, playerLat,lngOrigin ) / realWidth; //horizantal distance from the player place to rectangle origin (then compute the width ratio)
        double lngRatio2Hieght = distance(playerLat,playerLng, latOrigin,playerLng ) / realHieght; //virtical distance from the player place to rectangle origin (then compute the Hieght ratio)
    
        POINT imageXY;
        imageXY.x = image1Width * lngRatio2Width;
        imageXY.y = image1Hieght * lngRatio2Hieght;
    
        return imageXY;
    }
    
    
    long double distance(long double lat1, long double long1,
                         long double lat2, long double long2)
    {
        // Convert the latitudes
        // and longitudes
        // from degree to radians.
        lat1 = toRadians(lat1);
        long1 = toRadians(long1);
        lat2 = toRadians(lat2);
        long2 = toRadians(long2);
         
        // Haversine Formula
        long double dlong = long2 - long1;
        long double dlat = lat2 - lat1;
     
        long double ans = pow(sin(dlat / 2), 2) +
                              cos(lat1) * cos(lat2) *
                              pow(sin(dlong / 2), 2);
     
        ans = 2 * asin(sqrt(ans));
     
        // Radius of Earth in
        // Kilometers, R = 6371
        // Use R = 3956 for miles
        long double R = 6371;
         
        // Calculate the result
        ans = ans * R;
     
        return ans;
    }