I want to create android application "Points of interest". I've read many different tutorials, and I do not understand why I need to convert GPS coordinates to ECEF and then to ENU. Can you explain, please?
Thanks!
Geospatial coordinate systems are a big topic, but the main choice between systems such as ECEF and ENU is about whether you want to describe a large region of the Earth's surface or just a small region.
When Android provides a geolocation via the LocationListener API, it typically does this using latitude/longitude/altitude which is ideal for representing any point over the Earth's surface, but is a "polar" or "geodetic" coordinate system that isn't ideal for plotting 2D locations. Standard techniques allow this coordinate system to be converted into ECEF, which is another coordinate system which is suitable for the whole globe, but is "cartesian" so can be rotated and scaled using much simpler mathematical operations than the original latitude/longitude/altitude coordinates.
Earth-Centred Earth Fixed (ECEF) uses a coordinate system with its origin at the Earth's centre, so that any point on the ground will have coordinate values that are typically in the millions of metres. This is great for describing satellite orbits, or locations that span multiple continents, but not very convenient for 2D plots of points of interest within a town or city.
If you want to draw a 2D map of a small region of the Earth's surface, then the East-North-Up coordinate system may be much more convenient. To use this, you need a reference location (such as the centre of a particular city) about which the local East/North/Up directions can be defined. Those then provide a set of x/y/z axes, where the x & y axes might be directly converted into the 2D screen coordinates. Obviously, as the region of interest grows larger (e.g. more than 100km), the effects of the Earth's curvature become more noticeable, and an ENU coordinate system will be less useful. See wikipedia for more info.
Moving from an ECEF to ENU coordinate system can be done by a simple set of matrix additions & multiplications which can be computed from the ECEF location of the centre of the map, and the unit vectors in the east/north/up directions.
You can do it this way on Java
public List<Double> convertGpsToECEF(double lat, double longi, float alt) {
double a=6378.1;
double b=6356.8;
double N;
double e= 1-(Math.pow(b, 2)/Math.pow(a, 2));
N= a/(Math.sqrt(1.0-(e*Math.pow(Math.sin(Math.toRadians(lat)), 2))));
double cosLatRad=Math.cos(Math.toRadians(lat));
double cosLongiRad=Math.cos(Math.toRadians(longi));
double sinLatRad=Math.sin(Math.toRadians(lat));
double sinLongiRad=Math.sin(Math.toRadians(longi));
double x =(N+0.001*alt)*cosLatRad*cosLongiRad;
double y =(N+0.001*alt)*cosLatRad*sinLongiRad;
double z =((Math.pow(b, 2)/Math.pow(a, 2))*N+0.001*alt)*sinLatRad;
List<Double> ecef= new ArrayList<>();
ecef.add(x);
ecef.add(y);
ecef.add(z);
return ecef;
}
public List<Double> convertECEFtoENU(List<Double> ecefUser, List<Double> ecefPOI, double lat, double longi){
double cosLatRad=Math.cos(Math.toRadians(lat));
double cosLongiRad=Math.cos(Math.toRadians(longi));
double sinLatRad=Math.sin(Math.toRadians(lat));
double sinLongiRad=Math.sin(Math.toRadians(longi));
List<Double> vector = new ArrayList<>();
vector.add(ecefUser.get(0)-ecefPOI.get(0));
vector.add(ecefUser.get(1)-ecefPOI.get(1));
vector.add(ecefUser.get(2)-ecefPOI.get(2));
double e= vector.get(0)*(-sinLongiRad)+vector.get(0)*(cosLongiRad);
double n= vector.get(0)*(-sinLatRad)*(cosLongiRad)+vector.get(1)*(-sinLatRad)*(sinLongiRad)+vector.get(2)*cosLatRad;
double u= vector.get(0)*(cosLatRad)*(cosLongiRad)+vector.get(1)*(cosLatRad)*(sinLongiRad)+vector.get(2)*sinLatRad;
List<Double> enu= new ArrayList<>();
enu.add(e);
enu.add(n);
enu.add(u);
return enu;
}
Related
First read Question carefully ...
I need straight distance, not by walking,car,or etc.
Take a look to this image which given below,
Google provide us distance by car and driving.
But I don't want it, I want straight distance between two location (latitude - longitude).
Which is displayed as as RED LINE.
NOTE : I don't want to put red line on Google map, just want the Distance in Units(mile,km,etc.)
ANDROID
double distance
Location locationA = new Location(“point A”)
locationA.setLatitude(latA);
locationA.setLongitude(lngA);
Location locationB = new Location(“point B”);
locationB.setLatitude(latB);
LocationB.setLongitude(lngB);
distance = locationA.distanceTo(locationB);
MATHEMATICALY
a = distance in degrees //meterConversion = 1609;
b = 90 - latitude of point 1
c = 90 - latitude of point 2
l = longitude of point 1 - longitude of point 2
Cos(a) = Cos(b)Cos(c) + Sin(b)Sin(c)Sin(l)
d = circumference of Earth * a / 360 // circumference of Earth = 3958.7558657440545D km
The Haversine function is used to find the distance between two points on a sphere.
It's fairly straightforward to extend this to finding the straight line distance between two points on the Earth. The Earth is not a perfect sphere, but this is still a good approximation using a standard measurement (called WGS84) for the radius at the equator.
As CommonsWare has said, you can do this very simply by using distanceBetween(), which uses the Haversine function and the WGS84 radius.
For better understanding of implementation/math, take a look at this sample code in Python.
Distance you find with following code.
You just need to get two geoPoint's latitude and longitude.
and use that in following calculation to get distance.
R = 6371; // km
d = Math.acos(Math.sin(lat1)*Math.sin(lat2) +
Math.cos(lat1)*Math.cos(lat2) *
Math.cos(lon2-lon1)) * R;
That will be return distance after all calculation.
R is the radius of surface in KM, need to use in calculation and you try this. I hope it is useful for you.
I am trying to calculate intersection GPS coordinate by 2 vectors.
Vector#1 is created by (longitude#1, latitude#1) and (longitude#2, latitude#2).
Vector#2 is created by (longitude#3, latitude#3) and (longitude#4, latitude#4).
My main point is finding intersection by above 2 vectors. I've tried to calculate intersection on X,Y/longitude, latitude/ coordinate system. But it was not accurate location.
Can you help you for my issue ?
findIntersection(double long1, double lati1, double long2, double lati2, double long3, double lati3, double long4, double lati4) {
//...find intersection.
return intersectionLong, intersectionLati;
}
See this website: http://www.movable-type.co.uk/scripts/latlong.html
There is a section called Intersection of two paths given start points and bearings which is what you want.
I want to know how much meters is a certain pixel distance, at a given zoom level.
Reason: I want to know the radius, in meters, of a circle in the mapView, which fits perfectly in the mapView -> radiusPixels = mapView.getWidth()/2;
I found the method mapView.getProjection().metersToEquatorPixels(radiusMeters), which does the opposite of that what I need. But there's no inverse for this method or anything else useful.
My (probably naive) approach to solve it is as follows:
private double getFittingRadiusInMeters() {
return getMeters(mapView.getWidth() / 2);
}
private double getMeters(int pixels) {
Projection proj = mapView.getProjection();
Point mapCenterPixels = new Point(mapView.getWidth() / 2, mapView.getHeight() / 2);
//create 2 geopoints which are at pixels distance
GeoPoint centerGeoPoint = proj.fromPixels(mapCenterPixels.x, mapCenterPixels.y);
GeoPoint otherGeoPoint = proj.fromPixels(mapCenterPixels.x + pixels, mapCenterPixels.y);
Location loc = new Location("");
loc.setLatitude(centerGeoPoint.getLatitudeE6() / 1E6);
loc.setLongitude(centerGeoPoint.getLongitudeE6() / 1E6);
Location loc2 = new Location("");
loc2.setLatitude(otherGeoPoint.getLatitudeE6() / 1E6);
loc2.setLongitude(otherGeoPoint.getLongitudeE6() / 1E6);
return loc.distanceTo(loc2);
}
But it doesn't work well. I always get circles which are far smaller than the mapView - the radius is too small.
I know the distanceTo method says "approximate" but the radius differ significantly from the expected size. Should not be an effect of the approximation.
Thanks.
There is a small mistake in your approach.
You are calculating the value for screen half with at screen center level. The distance found is only valid to draw a circle at the same Latitude value (the Longitude may change without problem).
Because earth is shperic, the distance for the same number of pixels calculated at different Latitude levels, produces different results. Moving from Equador level to position closer to Pole level, same number of pixels result a in smaller distance in meters.
However, this will only be noticable if you call getFittingRadiusInMeters() with map positioned in a very distant Latitude from where you draw the circle.
Otherwise, it should work fine.
Solution
The method getMeters() should receive as parameter a GeoPoint (or at least the Latitude) that should be used to calculate the distance.
Regards.
I have an application of augmented reality in which I have stored information such us metro, gas stations, places of interest, etc. with the corresponding latitude and longitude.
Now, according to the orientation of the device, I would show a marker for each site in the camera view of the device. Similar to Layar and Wikitude.
It takes three days searching without stopping and have not found anyone to explain how to solve this problem.
Since information on this topic is very sparse, and I recently solved this problem on the iPhone, I thought I would share my method for anyone that can make it work with Android (there's nothing really specific to iPhone in this answer except for the Math functions sin, cos, and fmod, which can be found in java.lang.Math). These are the steps I took:
Obtain your own lat/lon and your current compass heading (lat1, lon1 and heading). On the iPhone, CLLocation returns these in degrees, but for these calculations they MUST be in radians (i.e. multiply by PI/180)
Obtain lat/lon of Points of Interest (POI) in radians (lat2 and lon2).
Calculate the distance between lat1/lon1 and lat2/lon2 using formula found here: http://www.movable-type.co.uk/scripts/latlong.html
Calculate angle to lat2/lon2 in relation to north. This is also described in the link above but I had a little bit of trouble getting this to work, here is C code for this:
double latDelta = (lat2 - lat1);
double lonDelta = (lon2 - lon1);
double y = sin(lonDelta) * cos(lat2);
double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2)* cos(lonDelta);
double angle = atan2(y, x); //not finished here yet
double headingDeg = compass.currentHeading;
double angleDeg = angle * 180/PI;
double heading = headingDeg*PI/180;
angle = fmod(angleDeg + 360, 360) * PI/180; //normalize to 0 to 360 (instead of -180 to 180), then convert back to radians
angleDeg = angle * 180/PI;
Using standard trigonometry, I calculate x and y. Remember, these coordinates are in 3D space, so we are not finished here yet because you still have to map them to 2D:
x = sin(angle-heading) * distance;
z = cos(angle-heading) * distance; //typically, z faces into the screen, but in our 2D map, it is a y-coordinate, as if you are looking from the bottom down on the world, like Google Maps
Finally, using the projection formula, you can calculate screen x ( I didn't do y because it was not necessary for my project, but you would need to get accelerator data and figure out if the device is perpendicular to the ground). The projection formula is found here (scroll to the very bottom): http://membres.multimania.fr/amycoders/tutorials/3dbasics.html
double screenX = (x * 256) / z
Now you can use this x coordinate to move an image or a marker on your screen. Remember a few points:
Everything must be in radians
The angle from you to the POI relative to North is angleBeteweenPoints - currentHeading
(For some reason I can't properly format the code on this computer, so if anyone wants to edit this answer, feel free).
I have a MapView that I'm displaying a "useful radius" (think accuracy of coordinate) in. Using MapView's Projection's metersToEquatorPixels, which is admittedly just for equatorial distance) isn't giving me an accurate enough distance (in pixels). How would you compute this if you wanted to display a circle around your coordinate, given radius?
So, Google Maps uses a Mercator projection. This means that the further you get from the equator the more distorted the distances become. According to this discussion, the proper way to convert for distances is something like:
public static int metersToRadius(float meters, MapView map, double latitude) {
return (int) (map.getProjection().metersToEquatorPixels(meters) * (1/ Math.cos(Math.toRadians(latitude))));
}
mMap.addCircle(
new CircleOptions().center(
new LatLng(
bounds.getCenter().latitude,
bounds.getCenter().longitude
)
)
.radius(50000)
.strokeWidth(0f)
.fillColor(0x550000FF)
);
projection.toPixels(GeoP, pt);
float radius = projection.metersToEquatorPixels(50);
Try this and see... i used it on my MapRadius and it seems to be working