I have never done this sort of thing before,but what I am doing is making a 3D sphere (which has earth like texture) like shape where I want to plot locations onto it using the latitude and longitude from google maps of specific locations.Now I am wondering , my sphere radius is obviously smaller than earths radius, would this still effect the position of the latitude and longitude values to xyz given the following formula:
tx = radiusOfSphere * cos(latitude) * cos(longitude);
ty = radiusOfSphere * -sin(latitude);
tz = radiusOfSphere * cos(latitude) * sin(longitude);
Yes.
tx^2 + ty^2 + tz^2 = radius^2 & math = radius^2, so you are on your sphere.
if latitude=0, then ty = 0, so you are on a circle parallel to the equator.
if longitude=0, then tz = 0 so you are on the a meridian.
Just check that you are in xyz not xzy or zyx, and that North is x>0 and East y>0, or whatever signs are compatible with point of view of your 3D rendering soft.
Related
In my iOS app I have a lat and long that gives me my location. I want to be able to calculate the bounding box that satisfies a certain distance d from my location. How can I do this?
TRY 1:
So I tried the solution given by #Neeku. I can see how it's supposed to return the right information but unfortunately it's off. So I don't think I can use it.
The code I wrote is this and I pass in 1000 meters:
MKCoordinateRegion startRegion = MKCoordinateRegionMakeWithDistance(center, meters, meters);
CLLocationCoordinate2D northWestCorner, southEastCorner;
northWestCorner.latitude = startRegion.center.latitude + .5 * startRegion.span.latitudeDelta;
northWestCorner.longitude = startRegion.center.longitude - .5 * startRegion.span.longitudeDelta;
southEastCorner.latitude = startRegion.center.latitude - .5 * startRegion.span.latitudeDelta;
southEastCorner.longitude = startRegion.center.longitude - .5 * startRegion.span.longitudeDelta;
NSLog(#"CENTER <%#,%#>", #(center.latitude),#(center.longitude));
NSLog(#"NW <%#,%#>, SE <%#,%#>",#(northWestCorner.latitude),#(northWestCorner.longitude),#(southEastCorner.latitude),#(southEastCorner.longitude));
So then the result is:
CENTER <38.0826682,46.3028721>
NW <38.08717278501047,46.29717303828632>, SE <38.07816361498953,46.29717303828632>
I then put that in google maps and get this: (see screenshot)
So then to my understanding the 1000 meters should go from the center to the sides of the box. The map is measuring the corner which should be OVER 1000 meters and it's actually just over 800 meters. This is the problem I am trying to solve.
I tried this method before and the distances simply aren't accurate. So, this solution has not worked for me. If you have more suggestions or maybe want to point out what is done wrong here please let me know.
Thank you
Let's say that your desired distance is 111 meters. Then you use the following code:
// 111 kilometers / 1000 = 111 meters.
// 1 degree of latitude = ~111 kilometers.
// 1 / 1000 means an offset of coordinate by 111 meters.
float offset = 1.0 / 1000.0;
float latMax = location.latitude + offset;
float latMin = location.latitude - offset;
// With longitude, things are a bit more complex.
// 1 degree of longitude = 111km only at equator (gradually shrinks to zero at the poles)
// So need to take into account latitude too, using cos(lat).
float lngOffset = offset * cos(location.latitude * M_PI / 180.0);
float lngMax = location.longitude + lngOffset;
float lngMin = location.longitude - lngOffset;
latMax, latMin, lngMax, lngMin will give you your bounding box coordinates.
(You can change this code pretty easily if you need distance other than 111 meters. Just update offset variable accordingly).
You can add/subtract half of the span from the latitude and longitude respectively and you get the values that you need:
CLLocationCoordinate2D centerCoord = CLLocationCoordinate2DMake(38.0826682, 46.3028721);
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(centerCoord, 1000, 1000);
double latMin = region.center.latitude - .5 * startRegion.span.latitudeDelta;
double latMax = region.center.latitude + .5 * startRegion.span.latitudeDelta;
double lonMin = region.center.longitude - .5 * startRegion.span.longitudeDelta;
double lonMax = region.center.longitude + .5 * startRegion.span.longitudeDelta;
Just remember that:
latitudeDelta
The amount of north-to-south distance (measured in degrees) to display on the map. Unlike longitudinal distances, which vary based on
the latitude, one degree of latitude is always approximately 111
kilometers (69 miles).
longitudeDelta
The amount of east-to-west distance (measured in degrees) to display for the map region. The number of kilometers spanned by a
longitude range varies based on the current latitude. For example, one
degree of longitude spans a distance of approximately 111 kilometers
(69 miles) at the equator but shrinks to 0 kilometers at the poles.
I'd like to make a Geographic Bounding box Calculation in iOS.
It can be aprox.
Input Parameters:
Current Location (Example: 41.145495, −73.994901)
Radius In Meters: (Example: 2000)
Required Output:
MinLong: (Example: 41.9995495)
MinLat: (Example: −74.004901)
MaxLong: (Example: 41.0005495)
MaxLat: (Example: −73.004901)
Requirement:
No Network Call
Any Ideas?
Mapkit / CoreLocation does not seem to offer this type of thing?
Any other Geographic SDK that i could use?
Thanks
I think you can use standard MapKit functions: MKCoordinateRegionMakeWithDistance, this will return a MKCoordinateRegion, which is really just a center point (lat, lon) and the spans in the latitudal and longitudal direction in degrees. Add/subtract half of the span from the latitude and longitude respectively and you have the values you're looking for.
CLLocationCoordinate2D centerCoord = CLLocationCoordinate2DMake(41.145495, −73.994901);
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(centerCoord, 2000, 2000);
double latMin = region.center.latitude - .5 * startRegion.span.latitudeDelta;
double latMax = region.center.latitude + .5 * startRegion.span.latitudeDelta;
double lonMin = region.center.longitude - .5 * startRegion.span.longitudeDelta;
double lonMax = region.center.longitude + .5 * startRegion.span.longitudeDelta;
By the way: this is only representative for the longitude for small spans, in the order of a couple of kilometers. To quote Apple:
latitudeDelta
The amount of north-to-south distance (measured in degrees) to use for the span. Unlike longitudinal distances, which vary based on the latitude, one degree of latitude is approximately 111 kilometers (69 miles) at all times.
longitudeDelta
The amount of east-to-west distance (measured in degrees) to use for the span. The number of kilometers spanned by a longitude range varies based on the current latitude. For example, one degree of longitude spans a distance of approximately 111 kilometers (69 miles) at the equator but shrinks to 0 kilometers at the poles.
I know I'm a bit late to the party, but I just built a class GTBoundingBox that might (or might not) help:
https://github.com/wpearse/ios-geotools
i have a list of gps coordinates (long,lat) and i have my current position (long,lat).
i found out that by subtracting the two coordinates i find the relative coordinates from my position, and that coordinates i use in my AR app to draw the pois in the opengl world.
the problem is that far-away coordinates will still be too far to "see", so i want an equation to translate everything to be close to my position, but with their original relative position.
double kGpsToOpenglCoorRatio = 1000;
- (void)convertGlobalCoordinatesToLocalCoordinates:(double)latitude x_p:(double *)x_p longitude:(double)longitude y_p:(double *)y_p {
*x_p = ((latitude - _userLocation.coordinate.latitude) * kGpsToOpenglCoorRatio);
*y_p = ((longitude - _userLocation.coordinate.longitude) * kGpsToOpenglCoorRatio);
}
i tried applying Square root in order to give them a "distance limit", but their positions got messed up relatively to their original position.
This might be because GPS uses a spherical(ish) coordinate system, and you're trying to directly map it to a cartesian coordinate system (a plane).
What you could to do is convert your GPS coordinates to a local reference plane, rather than map them directly. If you consider your own location the origin of your coordinate system, you can get the polar coordinates of the points on the ground plane relative to the origin and true north by using great circle distance (r) and bearing (theta) between your location and the remote coordinate, and then covert that to cartesian coordinates using (x,y) = (r*cos(theta), r*sin(theta)).
Better again for your case, once you have the great circle bearing, you can just foreshorten r (the distance). That will drag the points closer to you in both x and y, but they'll still be at the correct relative bearing, you'll just need to indicate this somehow.
Another approach is to scale the size of the objects you're visualizing so that they get larger with distance to compensate for perspective. This way you can just directly use the correct position and orientation.
This page has the bearing/distance algorithms: http://www.movable-type.co.uk/scripts/latlong.html
I ended up solving it using the equation of the gps coordinate intercepted with the circle i want all the pois to appear on, it works perfectly. I didn't use bearings anywhere.
here is the code if anyone interested:
- (void)convertGlobalCoordinatesToLocalCoordinates:(double)latitude x_p:(double *)x_p longitude:(double)longitude y_p:(double *)y_p {
double x = (latitude - _userLocation.coordinate.latitude) * kGpsToOpenglCoorRatio;
double y = (longitude - _userLocation.coordinate.longitude) * kGpsToOpenglCoorRatio;
y = (y == 0 ? y = 0.0001 : y);
x = (x == 0 ? x = 0.0001 : x);
double slope = x / ABS(y);
double outY = sqrt( kPoiRadius / (1+pow(slope,2)) );
double outX = slope * outY;
if (y < 0) {
outY = -1 * outY;
}
*x_p = outX;
*y_p = outY;
}
I need a function that maps gps positions to x/y values like this:
getXYpos(GeoPoint relativeNullPoint, GeoPoint p){
deltaLatitude=p.latitude-relativeNullPoint.latitude;
deltaLongitude=p.longitude-relativeNullPoint.longitude;
...
resultX=latitude (or west to east) distance in meters from p to relativeNullPoint
resultY=longitude (or south to north) distance in meters from p to relativeNullPoint
}
i have seen some implementations of "distance of two geoPoints" but they all just calculate the air-line distance.
i think the deltaLongitude can be transformed into meters directly but the deltaLatitude depends in the Longitude. does anyone know how this problem can be solved?
To start with, I think you have your latitude and longitude reversed. Longitude measures X, and latitude measures Y.
The latitude is easy to turn into a north-south distance. We know that 360 degrees is a full circle around the earth through the poles, and that distance is 40008000 meters. As long as you don't need to account for the errors due to the earth being not perfectly spherical, the formula is deltaLatitude * 40008000 / 360.
The tricky part is converting longitude to X, as you suspected. Since it depends on the latitude you need to decide which latitude you're going to use - you could choose the latitude of your origin, the latitude of your destination, or some arbitrary point in between. The circumference at the equator (latitude 0) is 40075160 meters. The circumference of a circle at a given latitude will be proportional to the cosine, so the formula will be deltaLongitude * 40075160 * cos(latitude) / 360.
Edit: Your comment indicates you had some trouble with the longitude formula; you might have used degrees instead of radians in the call to cos, that's a common rookie mistake. To make sure there's no ambiguity, here's working code in Python.
def asRadians(degrees):
return degrees * pi / 180
def getXYpos(relativeNullPoint, p):
""" Calculates X and Y distances in meters.
"""
deltaLatitude = p.latitude - relativeNullPoint.latitude
deltaLongitude = p.longitude - relativeNullPoint.longitude
latitudeCircumference = 40075160 * cos(asRadians(relativeNullPoint.latitude))
resultX = deltaLongitude * latitudeCircumference / 360
resultY = deltaLatitude * 40008000 / 360
return resultX, resultY
I chose to use the relativeNullPoint latitude for the X calculation. This has the benefit that if you convert multiple points with the same longitude, they'll have the same X; north-south lines will be vertical.
Edit again: I should have pointed out that this is a very simple formula and you should know its limitations. Obviously the earth is not flat, so any attempt to map it to XY coordinates will involve some compromises. The formula I derived above works best when the area you're converting is small enough to consider flat, and where the slight curvature and non-parallelism of north-south lines can be ignored. There's a whole science to map projections; if you want to see some possibilities a good place to start would be Wikipedia. This specific projection is known as the Equirectangular projection, with some added scaling.
Harvesine function is what you need.
Check it out at moveable-types There are Distance, Bearing, Midpoint and other stuff Javascript implementation working really good.
UPDATE
I've found a Java implementation of Harvesine function in another stackoverflow question
There are libraries on jstott.me.uk for PHP, Java and Javascript which do this, e.g.
var lld1 = new LatLng(40.718119, -73.995667); // New York
document.write("New York Lat/Long: " + lld1.toString() + "<br />");
var lld2 = new LatLng(51.499981, -0.125313); // London
document.write("London Lat/Long: " + lld2.toString() + "<br />");
var d = lld1.distance(lld2);
document.write("Surface Distance between New York and London: " + d + "km");
Suppose I have a map, for example from openstreetmaps.org.
I know the WGS-84 lat/lon of the upper left and lower right corner of the map.
How can I find other positions on the map from given WGS-84 lat/lon coordinates?
If the map is roughly street/city level, uses a mercator projection (as openstreetmap.org seems to), and isn't too close to the poles, linear interpolation may be accurate enough. Assuming the following:
TL = lat/lon of top left corner
BR = lat/lon of bottom right corner
P = lat/lon of the point you want to locate on the map
(w,h) = width and height of the map you have (pixels?)
the origin of the map image, (0,0), is at its top-left corner
, we could interpolate the (x,y) position corresponding to P as:
x = w * (P.lon - TL.lon) / (BR.lon - TL.lon)
y = h * (P.lat - TL.lat) / (BR.lat - TL.lat)
Common gotcha's:
The lat/lon notation convention lists the latitude first and the longitude second, i.e. "vertical" before "horizontal". This is opposite to the common x,y notation of image coordinates.
Latitude values increase when going in a north-ward direction ("up"), whereas y coordinates in your map image may be increasing when doing down.
If the map covers a larger area, linear interpolation will not be as accurate for latitudes. For a map that spans one degree of latitude and is in the earth's habitable zones (e.g. the bay area), the center latitude will be off by 0.2% or so, which is likely to by less than a pixel (depending on size)
If that's precise enough for your needs, you can stop here!
The more precise math for getting from P's latitude to a pixel y position would start with the mercator math. We know that for a latitude P.lat, the Y position on a projection starting at the equator would be as follows (I'll use a capital Y as unlike the y value we're looking for, Y starts at the equator and increases towards the north):
Y = k * ln((1 + sin(P.lat)) / (1 - sin(P.lat)))
The constant k depends on the vertical scaling of the map, which we may not know. Luckily, it can be deduced observing that y(TL) - y(BR) = h. That gets us:
k = h / (ln((1 + sin(TL.lat)) / (1 - sin(TL.lat))) - ln((1 + sin(BR.lat)) / (1 - sin(BR.lat))))
(yikes! that's four levels of brackets!) With k known, we now have the formula to find out the Y position of any latitude. We just need to correct for: (1) our y value starts at TL.lat, not the equator, and (2) y grows towards the south, rather than to the north. This gets us:
Y(TL.lat) = k * ln((1 + sin(TL.lat)) / (1 - sin(TL.lat)))
Y(P.lat) = k * ln((1 + sin(P.lat )) / (1 - sin(P.lat )))
y(P.lat) = -(Y(P.lat) - Y(TL.lat))
So this gets you:
x = w * (P.lon - TL.lon) / (BR.lon - TL.lon) // like before
y = -(Y(P.lat) - Y(TL.lat)) // where Y(anything) depends just on h, TL.lat and BR.lat