GroundOverlay made with a Canvas in Google Maps Android API v2 - android

I'm also try to draw arc (I'm referencing on this and this questions). I'll get from web service following:
Lat and Lng
Radius (in meters)
Start angle (end angle is startA + 60 degrees)
Now I encounter on following problem because I do not have two LatLng, just one, and in new map api v2 there is no radius = Projection.metersToEquatorPixels method for providing to RectF.set(point.x - radius,...)
Do you have code example, links, etc?
Also what about performances of App, because I'll have up to 500 arcs on map?

Starting from a LatLng point you can calculate another LatLng point in a given distance (radius) and a given angle as follows:
private static final double EARTHRADIUS = 6366198;
/**
* Move a LatLng-Point into a given distance and a given angle (0-360,
* 0=North).
*/
public static LatLng moveByDistance(LatLng startGp, double distance,
double angle) {
/*
* Calculate the part going to north and the part going to east.
*/
double arc = Math.toRadians(angle);
double toNorth = distance * Math.cos(arc);
double toEast = distance * Math.sin(arc);
double lonDiff = meterToLongitude(toEast, startGp.latitude);
double latDiff = meterToLatitude(toNorth);
return new LatLng(startGp.latitude + latDiff, startGp.longitude
+ lonDiff);
}
private static double meterToLongitude(double meterToEast, double latitude) {
double latArc = Math.toRadians(latitude);
double radius = Math.cos(latArc) * EARTHRADIUS;
double rad = meterToEast / radius;
double degrees = Math.toDegrees(rad);
return degrees;
}
private static double meterToLatitude(double meterToNorth) {
double rad = meterToNorth / EARTHRADIUS;
double degrees = Math.toDegrees(rad);
return degrees;
}

Related

Get Latitude Longitude after x kilometer on Google Map without destination?

I am creating an Android app which requires finding a coordinate on the same route after X kilometers.
I have two coordinates x1,y1 & x2,y2 on a road. Now, my requirement is to find coordinate x3,y3 after some 3 kilometers (i.e., coordinate after x2,y2 not between x1,y1 & x2,y2) on the same road.
How can this be achieved ?
If you know the bearing, you can calculate the destination coordinate.
Sample Code:
private LatLng getDestinationPoint(LatLng source, double brng, double dist) {
dist = dist / 6371;
brng = Math.toRadians(brng);
double lat1 = Math.toRadians(source.latitude), lon1 = Math.toRadians(source.longitude);
double lat2 = Math.asin(Math.sin(lat1) * Math.cos(dist) +
Math.cos(lat1) * Math.sin(dist) * Math.cos(brng));
double lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(dist) *
Math.cos(lat1),
Math.cos(dist) - Math.sin(lat1) *
Math.sin(lat2));
if (Double.isNaN(lat2) || Double.isNaN(lon2)) {
return null;
}
return new LatLng(Math.toDegrees(lat2), Math.toDegrees(lon2));
}
Sample usage:
double radiusInKM = 10.0;
double bearing = 90;
LatLng destinationPoint = getDestinationPoint(new LatLng((25.48, -71.26), bearing, radiusInKM);
Or you can use heading between your pointA and pointB instead of bearing:
LatLng destinationPoint = getDestinationPoint(new LatLng(37.4038194,-122.081267), SphericalUtil.computeHeading(new LatLng(37.7577,-122.4376), new LatLng(37.4038194,-122.081267)), radiusInKM);
The SphericalUtil.computeHeading(p1, p2); method is from the Android Google Maps Utility library.
This is based on the Javascript method from this Stackoverflow answer.
If you want the point on same road, you might checkout this PHP answer.

Android alternative to iOS Google Maps API GMSGeometryOffset

I am working on an Android version of an Ios app I have developed and are running into problems with differences in the Google Maps API on the two platforms. In Ios I can use the method: GMSGeometryOffset. However, it is not present in the Android API. Therefore, I am looking for an alternative to this method so that I can calculate a new location based on the current location, a direction/bearing and a distance/radius.
I am using it to Draw a round circle while avoiding the egg shape. My code so far looks like the following. However, it gives me an egg shape unless the current location is directly on top of equator.
for(double angle = 0; angle < 2*Math.PI; angle = angle+ Math.PI/resolutionCircle)
{
latitude = position.latitude + (radiusCircle * Math.sin(angle));
longitude = position.longitude + (radiusCircle * Math.cos(angle));
inner.add(new LatLng(latitude, longitude));
}
There is a computeOffset method in the Google Maps Android API Utility Library.
It is a static method:
public static LatLng computeOffset(LatLng from,
double distance,
double heading)
It returns the LatLng resulting from moving a distance from an origin in the specified heading (expressed in degrees clockwise from north).
You can refer this documentation for more detail about Google Maps Android API Utility Library.
Google Maps' GitHub page also provide its detail implementation:
public static LatLng computeOffset(LatLng from, double distance, double heading) {
distance /= EARTH_RADIUS;
heading = toRadians(heading);
// http://williams.best.vwh.net/avform.htm#LL
double fromLat = toRadians(from.latitude);
double fromLng = toRadians(from.longitude);
double cosDistance = cos(distance);
double sinDistance = sin(distance);
double sinFromLat = sin(fromLat);
double cosFromLat = cos(fromLat);
double sinLat = cosDistance * sinFromLat + sinDistance * cosFromLat * cos(heading);
double dLng = atan2(
sinDistance * cosFromLat * sin(heading),
cosDistance - sinFromLat * sinLat);
return new LatLng(toDegrees(asin(sinLat)), toDegrees(fromLng + dLng));
}

Android Google Map : Heading is drawn wrongly, when I draw a line with specific length and heading on Google Map

I have a GoogleMap in my project. It's set in zoom level 21. I want to draw a line that is 5 meter in length with a specific heading. I used this code:
private LatLng drawHeadingOnMap(LatLng centre, double radius, double heading)
{
double EARTH_RADIUS = 6378100.0;
// Convert to radians.
double lat = Math.toRadians(centre.latitude );
double lon = Math.toRadians(centre.longitude);
// y
double latPoint = lat + (radius / EARTH_RADIUS) * Math.sin(Math.toRadians(heading));
// x
double lonPoint = lon + (radius / EARTH_RADIUS) * Math.cos( Math.sin(Math.toRadians(heading)) / Math.cos(lat));
LatLng point =new LatLng(latPoint * 180.0 / Math.PI, lonPoint * 180.0 / Math.PI);
return point;
}
I run it by:
LatLng ll = drawHeadingOnMap(origin, 5, 90);
LatLng lll = drawHeadingOnMap(origin, 5, 0);
googleMap.addPolyline(new PolylineOptions().add(Mabda).add(ll).color(Color.BLUE).width(3));
googleMap.addPolyline(new PolylineOptions().add(Mabda).add(lll).color(Color.BLUE).width(3));
It draw 0 degree very well!! but others are wrong. for example this pic is shown the above code :
When I want to draw 90 degree, It draw sth like this pic! and after 90 , it get back to 0 degree (When I write drawHeadingOnMap(origin, 5, 180), It draw 0 degree!). How can I fix it? I'm so confused !!!...
Updated:
I tried it for origin= (12,12)...
I got this result:
ll.Latitude = 12.000898320495335
ll.Longitude = 12.00046835742835
lll.latitude = 12.0
lll.longitude = 12.000898320495335
ll is result for moving of (12,12) for 1 meter in direction of 90 degree.
lll is result for moving of (12,12) for 1 meter in direction of 0 degree.
the method is just OK for 0 degree ...
If you have a center point (10, 20), and you want to find the other point (x, y) to its 20 degree with radius 5, you can do the following math:
x = 10 + 5 * Math.sin(Math.toRadians(20));
y = 20 + 5 * Math.cos(Math.toRadians(20));
Not sure why you did Math.cos( Math.sin(Math.toRadians(heading)) / Math.cos(lat)) for your lonPoint.
To understand exact math I suggest reading this link.
If a working implementation is all you need use this function (adopted from Maps SphericalUtil):
/**
* #param loc location to transale (creates a copy)
* #param distance in meters
* #param heading in degrees, where 0 is NORTH, clockwise
* #return new location
*/
public static LatLng translate(LatLng loc, double distance, double heading){
double EARTH_RADIUS = 6378100.0;
heading = Math.toRadians(heading);
distance = distance/EARTH_RADIUS;
// http://williams.best.vwh.net/avform.htm#LL
double fromLat = Math.toRadians(loc.latitude);
double fromLng = Math.toRadians(loc.longitude);
double cosDistance = Math.cos(distance);
double sinDistance = Math.sin(distance);
double sinFromLat = Math.sin(fromLat);
double cosFromLat = Math.cos(fromLat);
double sinLat = cosDistance * sinFromLat + sinDistance * cosFromLat * Math.cos(heading);
double dLng = Math.atan2(
sinDistance * cosFromLat * Math.sin(heading),
cosDistance - sinFromLat * sinLat);
return new LatLng(Math.toDegrees(Math.asin(sinLat)), Math.toDegrees(fromLng + dLng));
}

Determinate a Geopoint from another, a distance, and a polar angle

I'm working on an Android app that uses Geopoints and I want to determinate a Geopoint from another Geopoint, a distance (in any format) and a polar angle. For example, I want to get coordinates of a place 100 meters in the North-North-East (22,5 degres) of my location got by the GPS in my phone.
The only method I've found is Location.distanceBetween(...).
Implementation for Android. This code is great for Unit Testing in your aplication:
public double radiansFromDegrees(double degrees)
{
return degrees * (Math.PI/180.0);
}
public double degreesFromRadians(double radians)
{
return radians * (180.0/Math.PI);
}
public Location locationFromLocation(Location fromLocation, double distance, double bearingDegrees)
{
double distanceKm = distance / 1000.0;
double distanceRadians = distanceKm / 6371.0;
//6,371 = Earth's radius in km
double bearingRadians = this.radiansFromDegrees(bearingDegrees);
double fromLatRadians = this.radiansFromDegrees(fromLocation.getLatitude());
double fromLonRadians = this.radiansFromDegrees(fromLocation.getLongitude());
double toLatRadians = Math.asin( Math.sin(fromLatRadians) * Math.cos(distanceRadians)
+ Math.cos(fromLatRadians) * Math.sin(distanceRadians) * Math.cos(bearingRadians) );
double toLonRadians = fromLonRadians + Math.atan2(Math.sin(bearingRadians)
* Math.sin(distanceRadians) * Math.cos(fromLatRadians), Math.cos(distanceRadians)
- Math.sin(fromLatRadians) * Math.sin(toLatRadians));
// adjust toLonRadians to be in the range -180 to +180...
toLonRadians = ((toLonRadians + 3*Math.PI) % (2*Math.PI) ) - Math.PI;
Location result = new Location(LocationManager.GPS_PROVIDER);
result.setLatitude(this.degreesFromRadians(toLatRadians));
result.setLongitude(this.degreesFromRadians(toLonRadians));
return result;
}
Take a look at great-circle formulas: http://en.wikipedia.org/wiki/Great-circle_distance
This should give You some hints on how to calculate the distances.
For a point in a given distance and heading, check http://williams.best.vwh.net/avform.htm#LL
Those formulas look quite complicated, but are easy to implement ;)

Sort list of lon\lat points, start with nearest

I have location from GPS (lon_base, lat_base).
I have a list of locations (lon1, lat1|lon2, lat2|lon3, lat3...)
This list is very long and is around the world.
My questions are:
1. How do I get from that list only the lon\lat that are 1 mile from my lon_base\lat_base?
2. How do I sort them from closest to farthest?
Thanks in advance!
public static List<Location> sortLocations(List<Location> locations, final double myLatitude,final double myLongitude) {
Comparator comp = new Comparator<Location>() {
#Override
public int compare(Location o, Location o2) {
float[] result1 = new float[3];
android.location.Location.distanceBetween(myLatitude, myLongitude, o.Lat, o.Long, result1);
Float distance1 = result1[0];
float[] result2 = new float[3];
android.location.Location.distanceBetween(myLatitude, myLongitude, o2.Lat, o2.Long, result2);
Float distance2 = result2[0];
return distance1.compareTo(distance2);
}
};
Collections.sort(locations, comp);
return locations;
}
Where the List of Locations is a list containing your own Location class, not the android.location.Location.
You may use the great circle distance to calculate the distance between two points whose you know the latitude-longitude coordinates. The formulae are quite easy to code:
static double distance(double fromLat, double fromLon, double toLat, double toLon) {
double radius = 6378137; // approximate Earth radius, *in meters*
double deltaLat = toLat - fromLat;
double deltaLon = toLon - fromLon;
double angle = 2 * Math.asin( Math.sqrt(
Math.pow(Math.sin(deltaLat/2), 2) +
Math.cos(fromLat) * Math.cos(toLat) *
Math.pow(Math.sin(deltaLon/2), 2) ) );
return radius * angle;
}
You want to define your own Comparator that, in general, looks something like this:
LonLat myHouse = /* whatever */ ;
Comparable comp = new Comparable () {
LonLat a;
int compareTo (Object b) {
int aDist = calcDistance(a, myHouse) ;
int bDist = calcDistance(b, myHouse) ;
return aDist - bDist;
}
};
myLonLatList.sort(lonLatList, comp);
where calcDistance() simply calculates the distance between the two points. If you're on Android, I think Google Maps has a function somewhere in their API that will do this for you.
EDIT : You'll want your calcDistance() function to look like ChrisJ's distance function.
-tjw
You can use followig approximation (since 1 mile is much smaller than the radius of the earth) to calculate the distances from your base:
dx = cos(phi_base) * (theta - theta_base)
dy = phi - phi_base
dist = sqrt(dx*dx+dy*dy)
with: phi = latitude and theta = longitude
The result is in units of 60 nautical miles if theta and phi are given in degrees.
The results will be quite wrong for points that have a latitude that is much different from your base latitude, but this doesn't matter if you just want to know wich points are about 1 mile from your base.
For most programming languages you have to convert phi_base to radians (multiply by pi/180) in order to use it for cos().
(Attention: You have to take special care if your base longitude is very close to 180° or -180°, but probably that is not the case :-)
Use the calculated distances as sorting key to sort your points.
If you have to be more exact (e.g. if you want to know all points that are about 2000 miles from your home), than you must use the formula for Great Circle Distance to calculate the exact distance of two points on a sphere.
According to this link
i made working method. The answer above was wrong, because it doesn't convert lat/lng degrees to radians.
private double getDistance(double fromLat, double fromLon, double toLat, double toLon){
double radius = 6371; // Earth radius in km
double deltaLat = Math.toRadians(toLat - fromLat);
double deltaLon = Math.toRadians(toLon - fromLon);
double lat1 = Math.toRadians(fromLat);
double lat2 = Math.toRadians(toLat);
double aVal = Math.sin(deltaLat/2) * Math.sin(deltaLat/2) +
Math.sin(deltaLon/2) * Math.sin(deltaLon/2) * Math.cos(lat1) * Math.cos(lat2);
double cVal = 2*Math.atan2(Math.sqrt(aVal), Math.sqrt(1-aVal));
double distance = radius*cVal;
Log.d("distance","radius * angle = " +distance);
return distance;
}

Categories

Resources