Ayaz Alavi
Ayaz Alavi

Reputation: 4835

ios: lat/long within rectangle

I have got CLLocation object which contains current location of user and I have got 4 lat/long pairs for each corner of a rectangle which can be angled. Now I want to check whether CLLocation coordinates are within that rectangle.

Following are the coordinates of the rectangle

#define NorthEast_LAT 51.514894
#define NorthEast_LNG -0.135306
#define SouthEast_LAT 51.514831
#define SouthEast_LNG -0.135153
#define NorthWest_LAT 51.514719
#define NorthWest_LNG -0.135858
#define SouthWest_LAT 51.514556
#define SouthWest_LNG -0.135714

I have tried following code but I think it will only work when angle of rectangle is 0 deg.

 BOOL withinRect = [delegate.CLController latlngWithInBox:location 
                                                    point1:CLLocationCoordinate2DMake(NorthEast_LAT, NorthEast_LNG) 
                                                    point2:CLLocationCoordinate2DMake(SouthEast_LAT, SouthEast_LNG) 
                                                    point3:CLLocationCoordinate2DMake(NorthWest_LAT, NorthWest_LNG)
                                                    point4:CLLocationCoordinate2DMake(SouthWest_LAT, SouthWest_LNG)];

 - (BOOL) latlngWithInBox:(CLLocation *)position point1:(CLLocationCoordinate2D)point1 point2:(CLLocationCoordinate2D)point2 point3:(CLLocationCoordinate2D)point3 point4:(CLLocationCoordinate2D)point4 {

if (position.coordinate.latitude >= point3.latitude && position.coordinate.latitude <= point2.latitude
    && position.coordinate.longitude >= point3.longitude && position.coordinate.longitude <= point2.longitude) {
    return YES;
}
return NO;

}

Upvotes: 1

Views: 3424

Answers (3)

SVGreg
SVGreg

Reputation: 2368

Another way to determine whether some point is within map rectangle is to use MKMapKit's functions:

  1. MKMapPointForCoordinate - convert coordinate to map point
  2. MKMapRectMake - to create rect using these points
  3. MKMapRectContainsPoint - determine if specified map point lies within the rectangle

The advantage is that MKMapKit (MKMapPoint, MKMapRect) uses Mercator projection of the map, so you do not need to provide spheroid calculations. But some of these functions available in iOS 4.0 and later.

UPDATE:

// 1 ------- 2
// |         |
// |      x  |
// |         |
// 3 ------- 4    

// 1 = topLeftCorner
// 4 = bottomRightCorner
// x = targetCoordinate

CLLocationCoordinate2D topLeftCorner = /* some coordinate */, bottomRightCorner = /* some coordinate */;
CLLocationCoordinate2D targetCoordinate = /* some coordinate */;
MKMapPoint topLeftPoint = MKMapPointForCoordinate(topLeftCorner);
MKMapPoint bottomRightPoint = MKMapPointForCoordinate(bottomRightCorner);
MKMapRect mapRect = MKMapRectMake(topLeftPoint.x, topLeftPoint.y, bottomRightPoint.x - topLeftPoint.x, bottomRightPoint.y - topLeftPoint.y);
MKMapPoint targetPoint = MKMapPointForCoordinate(targetCoordinate);   

BOOL isInside = MKMapRectContainsPoint(mapRect, targetPoint);

Upvotes: 8

Ayaz Alavi
Ayaz Alavi

Reputation: 4835

- (BOOL) latlngWithInBox:(CLLocation *)position point1:(CLLocationCoordinate2D)point1 point2:(CLLocationCoordinate2D)point2 point3:(CLLocationCoordinate2D)point3 point4:(CLLocationCoordinate2D)point4 {
    //&& position.coordinate.latitude >= [[point4 objectAtIndex:0] floatValue] && position.coordinate.latitude <= [[point1 objectAtIndex:0] floatValue] && position.coordinate.longitude <= [[point4 objectAtIndex:1] floatValue] && position.coordinate.longitude >= [[point1 objectAtIndex:1] floatValue]
    if (PointInTriangle(position.coordinate, point1, point2, point3) || PointInTriangle(position.coordinate, point2, point3, point4)) {
        return YES;
    }
    return NO;
}

float sign(CLLocationCoordinate2D p1, CLLocationCoordinate2D p2, CLLocationCoordinate2D p3)
{
    return (p1.longitude - p3.longitude) * (p2.latitude - p3.latitude) - (p2.longitude - p3.longitude) * (p1.latitude - p3.latitude);
}

bool PointInTriangle(CLLocationCoordinate2D pt, CLLocationCoordinate2D v1, CLLocationCoordinate2D v2, CLLocationCoordinate2D v3)
{
    bool b1, b2, b3;

    b1 = sign(pt, v1, v2) < 0.0f;
    b2 = sign(pt, v2, v3) < 0.0f;
    b3 = sign(pt, v3, v1) < 0.0f;

//    NSLog(@"b1-%@", [NSNumber numberWithBool:b1]);
//    NSLog(@"b2-%@", [NSNumber numberWithBool:b2]);
//    NSLog(@"b3-%@", [NSNumber numberWithBool:b3]);

    return ((b1 == b2) && (b2 == b3));
}

Upvotes: 0

DarkDust
DarkDust

Reputation: 92316

Let's ignore that the rectangle for geo-coordinates is on a spheroid (math is difficult there). So you want to find out whether a point is within a quadrangle.

Easiest way is to first add a restriction: the points have to be given in a certain order (NE, NW, SE, SW). Then, treat them as normal 2D-coordinates (longitude = x, latitude = y).

Next step is to reduce the problem: let the coordinates form 2 triangles, for example NE-NW-SE and NW-SE-SW. Then check whether your point is within one of those two triangles.

Upvotes: 1

Related Questions