Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draw a Geographically Accurate Arc on a Map for Android

I would like to draw an arc with a center GPS point and two end GPS points. I can use any mapping software that can be used with android.

So far I have tried Google Maps for android. Mapbox for android. ARCGIS for android. None of them seem to be able to do this simple task.

I'm guessing I need some-sort of overlay?

enter image description here enter image description here

like image 302
Reafidy Avatar asked Mar 13 '16 01:03

Reafidy


People also ask

Can I Draw on Google Maps Android?

You can trace a path or highlight an area on your map by drawing lines and shapes.

How do I Draw an arc in Google Earth?

Click (click, don't drag) on the map at the center point of your circle (eg: Vancouver) Move your mouse until the circle radius is the distance you want (eg: 750km) Click the map again to complete the circle. In the Ruler window, click the "Save" button.

How do you Draw a mobile map?

My Maps in a browser: Plot the points > Draw a line > Add Driving Route. Use mouse to draw route. Mark current location: Create a map; type your address in the search bar. The Android My Maps app is no longer available; however, you can use My Maps in a mobile browser on your device.


2 Answers

Unfortunately, I can't really give you a complete answer right now as this question requires heavy math and I'm unable to fully understand the data you have shown in the table. I assume you are trying to have an end result that looks something like this. If that is the case, you have a center point, radius, and the arc starting LatLng and end LatLng (This could also be calculated from the center point with additional math). I'll try and update this answer if I get a chance to write some code handling the math side. As far as I know, none of the map libraries (Google Maps, Mapbox) include this.

Basically, I'd write a method that returns a bunch of latlng points following the arc you wish to draw. From this, i'd draw a line using the addPolyline method.

// Draw line from list of LatLng called pointsArray
mapView.addPolyline(new PolylineOptions()
        .add(pointsArray)
        .color(Color.parseColor("#3bb2d0"))
        .width(2));

Hopefully this helps you out, at least with getting started and like I said, I'll try and add the math bits later on if I get a chance.

like image 165
cammace Avatar answered Oct 09 '22 22:10

cammace


First of all, you have to change the geodata representation.

From this:

36°46'02.5"S    174°50'03.6"E    GRC
36°56'18.3"S    174°33'09.7"E    CWA    36°52'19.2"S    174°29'23.5"E    5.0'    NM
36°48'19.8"S    174°25'37.7"E    GRC
36°41'06.1"S    174°37'32.9"E    CCA    36°39'54.5"S    174°38'40.7"E    1.5'    NM
36°41'00.3"S    174°39'57.1"E    GRC
36°39'49.4"S    174°41'32.3"E    CCA    36°38'43.5"S    174°40'15.7"E    1.5'    NM
36°39'17.5"S    174°41'59.7"E    GRC
36°39'38.6"S    174°44'37.7"E    GRC
36°37'08.8"S    174°47'27.4"E    CWA    36°42'03.8"S    174°46'17.0"E    5.0'    NM

To this:

-36.76736    174.83433    GRC
-36.93842    174.55269    CWA    -36.87200    174.48986    0.08333    NM
-36.80550    174.42714    GRC
-36.68503    174.62581    CCA    -36.66514    174.64464    0.02500    NM
-36.68342    174.66586    GRC
-36.66372    174.69231    CCA    -36.64542    174.67103    0.02500    NM
-36.65486    174.69992    GRC
-36.66072    174.74381    GRC
-36.61911    174.79094    CWA    -36.70106    174.77139    0.08333    NM

Then you can use them to build a path (e.g., SVG path):

<svg
  ...>
  <g
     transform="matrix(1250,0,0,1250,46206.909,-217995.49)"
     ...>
    <path
       d=" M -36.76736,174.83433 L -36.93842,174.55269 A 0.08333,0.08333 0 0,1 -36.80550,174.42714 L -36.68503,174.62581 A 0.02500,0.02500 0 0,0 -36.68342,174.66586 L -36.66372,174.69231 A 0.02500,0.02500 0 0,0 -36.65486,174.69992 L -36.66072,174.74381 L -36.61911,174.79094 A 0.08333,0.08333 0 0,1 -36.76736,174.83433 Z"
       .../>
  </g>
</svg>

SVG example

Actually, there is no API to create curves, arcs, etc. in GMaps/OSMDroid, so, you should draw them as many small lines. It means doing some math, but this math can be made by GeographicLib library:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


    MapView map = (MapView) findViewById(R.id.map);
    map.setTileSource(TileSourceFactory.MAPNIK);
    map.setBuiltInZoomControls(true);
    map.setMultiTouchControls(true);


    IMapController mapController = map.getController();
    mapController.setZoom(9);
    GeoPoint startPoint = new GeoPoint(-36.66372, 174.69231);
    mapController.setCenter(startPoint);

    Polygon polyline = new Polygon(this);
    List<GeoPoint> points = new LinkedList<>();

    // I filled the data manually, but it can be done more clever, of course.
    GRC(points, new GeoPoint(-36.76736, 174.83433));
    CWA(points, new GeoPoint(-36.93842, 174.55269),
                new GeoPoint(-36.87200, 174.48986),
                new GeoPoint(-36.80550, 174.42714),
                0.08333);
    CCA(points, new GeoPoint(-36.68503, 174.62581),
                new GeoPoint(-36.66514, 174.64464),
                new GeoPoint(-36.68342, 174.66586),
                0.02500);
    CCA(points, new GeoPoint(-36.66372, 174.69231),
                new GeoPoint(-36.64542, 174.67103),
                new GeoPoint(-36.65486, 174.69992),
                0.02500);
    GRC(points, new GeoPoint(-36.66072, 174.74381));
    CWA(points, new GeoPoint(-36.61911, 174.79094),
                new GeoPoint(-36.70106, 174.77139),
                new GeoPoint(-36.76736, 174.83433), //close shape going to the start point
                0.08333);

    polyline.setPoints(points);
    polyline.setFillColor(0xA0FF00FF);
    polyline.setStrokeColor(Color.BLACK);
    polyline.setStrokeWidth(2f);
    map.getOverlays().add(polyline);
    map.invalidate();
}

private void CCA(List<GeoPoint> points, GeoPoint startPoint, GeoPoint centerPoint, GeoPoint endPoint, double radius) {
    points.add(startPoint);

    GeodesicData f = Geodesic.WGS84.Inverse(centerPoint.getLatitude(), centerPoint.getLongitude(), startPoint.getLatitude(), startPoint.getLongitude());
    GeodesicData t = Geodesic.WGS84.Inverse(centerPoint.getLatitude(), centerPoint.getLongitude(), endPoint.getLatitude(), endPoint.getLongitude());

    double ffaz = f.azi1;
    double tfaz = t.azi1;

    final int decrement = 1;
    while (Math.abs((int)ffaz) != Math.abs((int)tfaz)) {
        GeodesicData llb = Geodesic.WGS84.Direct(centerPoint.getLatitude(), centerPoint.getLongitude(), ffaz,  f.s12);
        points.add(new GeoPoint(llb.lat2, llb.lon2));
        ffaz -= decrement;
        if (ffaz <0) {
            ffaz += 360;
        }
    }

    points.add(endPoint);
}

private void CWA(List<GeoPoint> points, GeoPoint startPoint, GeoPoint centerPoint, GeoPoint endPoint, double radius) {
    points.add(startPoint);

    GeodesicData f = Geodesic.WGS84.Inverse(centerPoint.getLatitude(), centerPoint.getLongitude(), startPoint.getLatitude(), startPoint.getLongitude());
    GeodesicData t = Geodesic.WGS84.Inverse(centerPoint.getLatitude(), centerPoint.getLongitude(), endPoint.getLatitude(), endPoint.getLongitude());

    double ffaz = f.azi1;
    double tfaz = t.azi1 > 0 ? t.azi1 : 360 + t.azi1;

    final int increment = 1;
    while (Math.abs((int)ffaz) != Math.abs((int)tfaz)) {
        GeodesicData llb = Geodesic.WGS84.Direct(centerPoint.getLatitude(), centerPoint.getLongitude(), ffaz, f.s12);
        points.add(new GeoPoint(llb.lat2, llb.lon2));
        ffaz += increment;
        if (ffaz>360) {
            ffaz -= 360;
        }
    }

    points.add(endPoint);
}

private void GRC(List<GeoPoint> points, GeoPoint geoPoint) {
    points.add(geoPoint);
}

I used osmdroid+OSMBonusPack, but the code is quite universal and can be used with Google Maps easily.

The full source code.

Result:

osmdroid and OSMBonusPack together

Also, would you mind telling what kind of geodata you posted? The shape on the map looks like an allowed flight zone, I guess.

like image 4
Mikalai Daronin Avatar answered Oct 09 '22 22:10

Mikalai Daronin