Create a random CLLocationCoordinate in a certain area - ios

I've got an MKMapRect.
How do I create a random CLLocationCoordinate inside there?
I know there is arc4random(), but how can I use it for GPS Coordinates?

#define ARC4RANDOM_MAX 0x100000000
...
//val is a double between 0 and 1
double xOffset = ((double)arc4random() / ARC4RANDOM_MAX);
double yOffset = ((double)arc4random() / ARC4RANDOM_MAX);
MKMapPoint randomPoint;
randomPoint.x = maprect.origin.x + xOffset*maprect.size.width;
randomPoint.y = maprect.origin.y + yOffset*maprect.size.height;
CLLocationCoordinate2D randomCoordinate = MKCoordinateForMapPoint(randomPoint);

From the MapRect, you could got MKMapPoint origin and MKMapSize size, then the random CLLocationCoordinate should be {origin.x + [0 ~ size.width], origin.y + [0 ~ size.height]}
typedef struct {
MKMapPoint origin;
MKMapSize size;
} MKMapRect;
the code like this:
#define ARC4RANDOM_MAX 0x100000000
- (double)createRandomsizeValueFloat:(double)fromFloat toFloat:(double)toFloat
{
if (toFloat < fromFloat) {
return toFloat;
} else if (toFloat == fromFloat) {
return fromFloat;
}
return ((double)arc4random() / ARC4RANDOM_MAX) * (toFloat - fromFloat) + fromFloat;
}
//CLLocationDegrees lat = mapRect.origin.x + [self createRandomsizeValueFloat:0 toFloat:mapRect.size.width];
//CLLocationDegrees lng = mapRect.origin.y + [self createRandomsizeValueFloat:0 toFloat:mapRect.size.height];

Just set the latitude and longitude properties of your CLLocationCoordinate instance.
Take care about ranges : -90 < latitude < 90, -180 < longitude < 180.
Hope this helps.

Related

Create perpendicular lat long from single cllocation coordinate of X meter

I have user current location i.e. CLLocation Coordinate (location lat & long) and user is on race track pointing to one direction with the help of user current location i created one region now I want some more race track coordinate(say 2m , 4m , 6m away from race track in perpendicular direction) and the track is 10 m long. Please check the image and the red points are on the track.
Please check this image
/**
* Returns the destination point from initial point having travelled the given distance on the
* given initial bearing (bearing normally varies around path followed).
*
* #param {double} distance - Distance travelled, in same units as earth radius (default: metres).
* #param {double} bearing - Initial bearing in degrees from north.
*
* #returns {CLLocationCoordinate} Destination point.
*/
#define kEarthRadius 6378137
- (CLLocationCoordinate2D)destinationPointWithStartingPoint:(MKMapPoint)initialPoint distance:(double)distance andBearing:(double)bearing {
CLLocationCoordinate2D location = MKCoordinateForMapPoint(initialPoint);
double delta = distance / kEarthRadius;
double omega = [self degreesToRadians:bearing];
double phi1 = [self degreesToRadians:location.latitude];
double lambda1 = [self degreesToRadians:location.longitude];
double phi2 = asin(sin(phi1)*cos(delta) + cos(phi1) * sin(delta) * cos(omega));
double x = cos(delta) - sin(phi1) * sin(phi2);
double y = sin(omega) * sin(delta) * cos(phi1);
double lambda2 = lambda1 + atan2(y, x);
return CLLocationCoordinate2DMake([self radiansToDegrees:phi2], ([self radiansToDegrees:lambda2]+540)%360-180);
}
- (CLLocationCoordinate2D)rhumbDestinationPointForInitialPoint:(MKMapPoint)initialPoint distance:(double)distance andBearing:(double)bearing {
CLLocationCoordinate2D location = MKCoordinateForMapPoint(initialPoint);
double delta = distance / kEarthRadius;
double omega = [self degreesToRadians:bearing];
double phi1 = [self degreesToRadians:location.latitude];
double lambda1 = [self degreesToRadians:location.longitude];
double delta_phi = delta * cos(omega);
double phi2 = phi1 + delta_phi;
// check for some daft bugger going past the pole, normalise latitude if so
if (fabs(phi2) > M_PI / 2) {
phi2 = phi2 > 0 ? M_PI-phi2 : -M_PI-phi2;
}
double delta_gamma = log(tan(phi2/2+M_PI/4)/tan(phi1/2+M_PI/4));
double q = fabs(delta_gamma) > 10e-12 ? delta_phi / delta_gamma : cos(phi1);
double delta_lambda = delta*sin(omega)/q;
double lambda2 = lambda1 + delta_lambda;
return CLLocationCoordinate2DMake([self radiansToDegrees:phi2], ([self radiansToDegrees:lambda2]+540)%360-180);
}
- (double)degreesToRadians:(double)degrees {
return degrees * M_PI / 180.0;
}
- (double)radiansToDegrees:(double)radians {
return radians * 180.0 / M_PI;
}
Adapted from : http://www.movable-type.co.uk/scripts/latlong.html
More information on bearing : https://en.wikipedia.org/wiki/Bearing_(navigation)
And rhumb line : https://en.wikipedia.org/wiki/Rhumb_line

Find closest point on line from a particular point

I'm using Google Maps iOS to set up Geofencing around a building complex. I've created a polyline around the complex and if the user taps outside of the polyline it will move the marker to the closest point that's on the polyline, otherwise it will just place the marker. This seems to work relatively well using this method.
However I've noticed that this method only seems to work when the point in question is perpendicular to a point on the line, otherwise it comes up with strange results. I've posted my code and some screenshots below.
-(CLLocationCoordinate2D) findClosestPointWithinFence:(CLLocationCoordinate2D) pointToTest {
CLLocationDistance smallestDistance = 0;
CLLocationCoordinate2D closestPoint = pointToTest;
for(int i = 0; i < [geoFencePoints count] - 1; i++) {
CGPoint point = [[geoFencePoints objectAtIndex:i] CGPointValue];
CGPoint point2 = [[geoFencePoints objectAtIndex:i + 1] CGPointValue];
CLLocationCoordinate2D locationA = CLLocationCoordinate2DMake(point.x, point.y);
CLLocationCoordinate2D locationB = CLLocationCoordinate2DMake(point2.x, point2.y);
CLLocationCoordinate2D myLoc = [self findClosestPointOnLine:locationA secondPoint:locationB fromPoint:pointToTest];
if(GMSGeometryIsLocationOnPath(myLoc, dealershipParameters.path, YES)) {
if(smallestDistance == 0) {
smallestDistance = GMSGeometryDistance(myLoc, pointToTest);
closestPoint = myLoc;
} else {
if(smallestDistance > GMSGeometryDistance(myLoc, pointToTest)) {
smallestDistance = GMSGeometryDistance(myLoc, pointToTest);
closestPoint = myLoc;
}
}
}
}
return closestPoint;
}
-(CLLocationCoordinate2D) findClosestPointOnLine:(CLLocationCoordinate2D)locationA secondPoint:(CLLocationCoordinate2D)locationB fromPoint:(CLLocationCoordinate2D) pointToTest {
CGPoint aToP = CGPointMake(pointToTest.latitude - locationA.latitude, pointToTest.longitude - locationA.longitude);
CGPoint aToB = CGPointMake(locationB.latitude - locationA.latitude, locationB.longitude - locationA.longitude);
float atb2 = (aToB.x * aToB.x) + (aToB.y * aToB.y);
float atp_dot_atb = (aToP.x * aToB.x) + (aToP.y * aToB.y);
float t = atp_dot_atb / atb2;
CLLocationCoordinate2D myLoc = CLLocationCoordinate2DMake(locationA.latitude + aToB.x * t, locationA.longitude + aToB.y * t);
return myLoc;
}
-(BOOL)testIfInsideGeoFence:(CLLocationCoordinate2D) pointToTest {
return GMSGeometryContainsLocation(pointToTest, dealershipParameters.path, YES) || GMSGeometryIsLocationOnPath(pointToTest, dealershipParameters.path, YES);
}
Below the first screenshot shows the marker successfully finding the closest point, the marker off the blue line is where I initially tapped, and the marker on the blue line is the point it found. The second shows the marker failing to find the closest point. The marker on the screen is where I initially tapped, since it is unable to find a proper solution it doesn't place a second marker.
Screenshot 1
Screenshot 2
I ran into a similar issue. I think what is happening is that you are treating the line segment as a line. Since the segment does not extend to a point that would be perpendicular to the point, the closest point on the segment would be one of it endpoints, not an extension of the segment.
Here is a method I am using. It takes the endpoint of the segment and returns a struct containing the nearest point on the segment and the distance from the giving point. The key difference being the if-else statements that check whether the solution is on the segment or not. You may need to rework a few things for your purposes.
The other thing to note is that I have had more accurate results performing the math on MKMapPoints rather than CLLocationCoordinate2D objects. I think it has something to do with the earth being round or some such nonsense.
+ (struct TGShortestDistanceAndNearestCoordinate)distanceFromPoint:(CLLocationCoordinate2D)p
toLineSegmentBetween:(CLLocationCoordinate2D)l1
and:(CLLocationCoordinate2D)l2 {
return [[self class] distanceFromMapPoint:MKMapPointForCoordinate(p)
toLineSegmentBetween:MKMapPointForCoordinate(l1)
and:MKMapPointForCoordinate(l2)];
}
+ (struct TGShortestDistanceAndNearestCoordinate)distanceFromMapPoint:(MKMapPoint)p
toLineSegmentBetween:(MKMapPoint)l1
and:(MKMapPoint)l2 {
double A = p.x - l1.x;
double B = p.y - l1.y;
double C = l2.x - l1.x;
double D = l2.y - l1.y;
double dot = A * C + B * D;
double len_sq = C * C + D * D;
double param = dot / len_sq;
double xx, yy;
if (param < 0 || (l1.x == l2.x && l1.y == l2.y)) {
xx = l1.x;
yy = l1.y;
}
else if (param > 1) {
xx = l2.x;
yy = l2.y;
}
else {
xx = l1.x + param * C;
yy = l1.y + param * D;
}
struct TGShortestDistanceAndNearestCoordinate result;
MKMapPoint nearestPoint = MKMapPointMake(xx, yy);
result.shortestDistance = MKMetersBetweenMapPoints(p, nearestPoint);
result.nearestCoordinate = MKCoordinateForMapPoint(nearestPoint);
return result;
}
A very elegant solution. But I'm not sure about your test in the line "if param < 0 ... ". l1.x == l2.x iff the segment is vertical, and l1.y == l2.y iff it is horizontal. So how can this conjunction ever be true? (except when l1, l2 are identical)

Can't get Panoramio Data with API

I am trying to get panoramio picture around a given coordinate. However always my query returns zero photos. This is the code I am using.
const double WGS84_a = 6378137.0;
const double WGS84_b = 6356752.3;
double Deg2rad(double degrees) {
return degrees * M_PI / 180.0;
}
double Rad2deg(double radians) {
return radians * 180.0 / M_PI;
}
double WGS84EarthRadius(double lat)
{
double An = WGS84_a*WGS84_a * cos(lat);
double Bn = WGS84_b*WGS84_b * sin(lat);
double Ad = WGS84_a * cos(lat);
double Bd = WGS84_b * sin(lat);
return sqrt( (An*An + Bn*Bn)/(Ad*Ad + Bd*Bd) );
}
MapRect LatLonDestPoint(CLLocationCoordinate2D origin, double halfSideInKm) {
double lat = Deg2rad(origin.latitude);
double lon = Deg2rad(origin.longitude);
double halfSide = 1000*halfSideInKm;
double radius = WGS84EarthRadius(lat);
double pradius = radius*cos(lat);
double latMin = lat - halfSide/radius;
double latMax = lat + halfSide/radius;
double lonMin = lon - halfSide/pradius;
double lonMax = lon + halfSide/pradius;
return MKMapRectMake(Rad2deg(latMin), Rad2deg(lonMin), Rad2deg(latMax), Rad2deg(lonMax));
}
Now for a coordinate (60.1190935704,-149.439081366) I get the API like
http://www.panoramio.com/map/get_panoramas.php?set=public&from=0&to=20&minx=60.029034&miny=-149.619843&maxx=60.209152&maxy=-149.258316&size=medium&mapfilter=true
This always returns me zero results. Please help me with what I am doing wrong.
You have x and y coordinates the wrong way around.
Swapping these returns:-
{"count":379,"has_more":true,"map_location":{"lat":60.118290103595498,"lon":-149.45469385385852,"panoramio_zoom":6}
etc
ps Do not rely on the count being correct. Use the has_more flag.

Calculate distance from a lat/lon coord to a street

I have the coordinates for a street, for example:
CLLocationCoordinate2D street[3];
street[0] = CLLocationCoordinate2DMake(-17.3521, 145.5898);
street[1] = CLLocationCoordinate2DMake(-17.3518, 145.5910);
street[2] = CLLocationCoordinate2DMake(-17.3515, 145.5917);
And a location that is fairly close to the street (about 60 meters):
CLLocationCoordinate2D location = CLLocationCoordinate2DMake(-17.3525, 145.5911);
How can I calculate the distance between the location and position along the street's path?
I'm not looking for the distance to the closest point in the array, I want the distance to the closest position in between the points.
EDIT
It's easier to describe my question with a picture:
street is the three red dots
location is the blue dot
I want to calculate the length of the yellow line in meters.
Take a look at this site: link.
It shows different types of distance measuring with latitude and longitude coordinates and even some code examples (in javascript).
If you have the find the crow distance between two locations, make CLLocation object of two coords, then
CLLocationDistance meters = [newLocation distanceFromLocation:oldLocation];
and if you have find the actual road distance divide the two coords to several coords in straight line and find the distance and add them up.
Here is my attempt to solve this, but I'm not sure if it's the best way?
// http://www.cprogramto.com/c-program-to-find-shortest-distance-between-point-and-line-segment/
double FindDistanceToSegment(double x1, double y1, double x2, double y2, double pointX, double pointY)
{
double diffX = x2 - x1;
float diffY = y2 - y1;
if ((diffX == 0) && (diffY == 0))
{
diffX = pointX - x1;
diffY = pointY - y1;
return sqrt(diffX * diffX + diffY * diffY);
}
float t = ((pointX - x1) * diffX + (pointY - y1) * diffY) / (diffX * diffX + diffY * diffY);
if (t < 0)
{
//point is nearest to the first point i.e x1 and y1
diffX = pointX - x1;
diffY = pointY - y1;
}
else if (t > 1)
{
//point is nearest to the end point i.e x2 and y2
diffX = pointX - x2;
diffY = pointY - y2;
}
else
{
//if perpendicular line intersect the line segment.
diffX = pointX - (x1 + t * diffX);
diffY = pointY - (y1 + t * diffY);
}
//returning shortest distance
return sqrt(diffX * diffX + diffY * diffY);
}
-
CLLocationCoordinate2D street[3];
street[0] = CLLocationCoordinate2DMake(-17.3521, 145.5898);
street[1] = CLLocationCoordinate2DMake(-17.3518, 145.5910);
street[2] = CLLocationCoordinate2DMake(-17.3515, 145.5917);
CLLocationCoordinate2D location = CLLocationCoordinate2DMake(-17.3525, 145.5911);
CLLocationDegrees distanceDegrees = CGFLOAT_MAX;
for (NSUInteger nodeIndex = 1; nodeIndex < 3; nodeIndex++) {
CLLocationCoordinate2D nodeCoord = street[nodeIndex];
CLLocationCoordinate2D prevNodeCoord = street[nodeIndex - 1];
CLLocationDegrees distanceToCurrent = FindDistanceToSegment(prevNodeCoord.longitude, prevNodeCoord.latitude, nodeCoord.longitude, nodeCoord.latitude, location.longitude, location.latitude);
if (distanceToCurrent < distanceDegrees)
distanceDegrees = distanceToCurrent;
}
CLLocationDistance distance = distanceDegrees * 111111; // 1.0 degree is approximately 111,111 meters
NSLog(#"%f", distance); // 78.15 meters

converting isometric tile map coordinates to screen coordinates

I'm trying to convert isometric tile coordinates to screen coordinates.
I seem to have problem especially with the Y coordinates, looks like the X part works just fine. here is what I got so far.
// calculate screen coordinates from tile coordinates
- (CGPoint)positionForTileCoord:(CGPoint)pos {
float halfMapWidth = _tileMap.mapSize.width*0.5;
float mapHeight = _tileMap.mapSize.height;
float tileWidth = _tileMap.tileSize.width;
float tileHeight = _tileMap.tileSize.height;
int x = halfMapWidth*tileWidth + tileWidth*pos.x*0.5-tileWidth*pos.y*0.5;
int y = ............
return ccp(x, y);
my player is added as a child to the Tile map itself and the map is added to the layer at screenSize.x/2, scrrensize.y/2 with an anchor point of 0.5
I have done the same thing successfully with an orthogonal map but seem to struggle with the isometric one.
Thank you
really its look like this:
// calculate screen coordinates from tile coordinates
- (CGPoint)positionForTileCoord:(CGPoint)pos {
float halfMapWidth = _tileMap.mapSize.width*0.5;
float mapHeight = _tileMap.mapSize.height;
float tileWidth = _tileMap.tileSize.width;
float tileHeight = _tileMap.tileSize.height;
int x = halfMapWidth*tileWidth + tileWidth*pos.x*0.5-tileWidth*pos.y*0.5;
int y = (pos.y + (mapHeight * tileWidth/2) - (tileHeight/2)) - ((pos.y + pos.x) * tileHeight/2) + tileHeight;
return ccp(x, y);
}
// calculating the tile coordinates from screen location
-(CGPoint) tilePosFromLocation:(CGPoint)location
{
CGPoint pos = location;
float halfMapWidth = _tileMap.mapSize.width*0.5;
float mapHeight = _tileMap.mapSize.height;
float tileWidth = _tileMap.tileSize.width;
float tileHeight = _tileMap.tileSize.height;
CGPoint tilePosDiv = CGPointMake(pos.x/tileWidth, pos.y/tileHeight);
float invereseTileY = mapHeight - tilePosDiv.y;
// Cast int to make sure that result is in whole numbers
float posX = (int)(invereseTileY + tilePosDiv.x - halfMapWidth);
float posY = (int)(invereseTileY - tilePosDiv.x + halfMapWidth);
return CGPointMake(posX, posY);
}
int y = (pos.y + (mapHeight * tileWidth/2) - (tileHeight/2)) - ((pos.y + pos.x) * tileHeight/2) + tileHeight;

Resources