implementing a simple geofence in objective-C
I am trying to implement somewhat of a simple geofence algorithm that basically does the following:
开发者_运维问答
- Say I have two point A and B (each point has a latitude and longitude value in earth).
- I can draw a straight line from point A to point B
- I can set a perimeter, which is a rectangle, around that line (see drawing below for more clarity)
What I want to do is as follows, if the phone current location is outside of this red perimeter then it triggers something, basically a delegate. The perimeter size should be able to be adjusted to a percentage size, so 5% would be a small perimeter around the line and 70% would be a large perimeter around the line. Be aware that the perimeter should be a rectangle, not circle with radius. I am guessing that there will be a bunch of if statements involved in building this... if anyone could come up with a simple and elegant solution to this (would be great if I can see code in objective-C) that would be awesome. Or any guidance would be helpful as well
You can create a path from the four points of the rectangle and then use CGPathContainsPoint
to check whether the current location is inside the path.
As for the conversion of latitude and longitude to planar x, y coordinates, the simplest solution is to use Mercator projection using Map Kit. Check Understanding Map Geometry for more info.
Here's an example:
// create four rectangle points from A, B
dx = (B.x - A.x) * 0.05; // 5% of the A-B length
dy = (B.y - A.y) * 0.05;
// topmost corner, above B
points[0].x = B.x + dx - dy;
points[0].y = B.y + dy + dx;
//rightmost corner, to the right from B
points[1].x = B.x + dx + dy;
points[1].y = B.y + dy - dx;
...
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, points[0].x, points[0].y);
CGPathAddLineToPoint(path, NULL, points[1].x, points[1].y);
CGPathAddLineToPoint(path, NULL, points[2].x, points[2].y);
CGPathAddLineToPoint(path, NULL, points[3].x, points[3].y);
CGPathCloseSubpath(path);
// convert latitude, longitude to planar coordinates
MKMapPoint location = MKMapPointForCoordinate([newLocation coordinate]);
BOOL inside = CGPathContainsPoint(path, NULL, CGPointMake(location.x, location.y), YES);
CGPathRelease(path);
Note: This code expects that the current location is a point, while in reality, it is a point and a radius of accuracy, which is effectively a circle. This complicates things a bit because now you need to define how to handle situations when the current location is not known exactly, but you only know that it's somewhere in the circle. If the rectangle is large (say 5 km), then you may simply require radius of accuracy less than 50m, do the calculation as if the current location was exact and ignore the small inaccuracy of the computation. If the rectangle is smaller (say 50m), you may also do the calculation as if the current location was exact, but then the false positives probability would be higher (e.g. sometimes you would be detected as in the rectangle while you would be standing outside of it).
Or you may want to go for the "perfect" solution and do circle-rectangle intersection, which is more complex and may result not only in YES and NO answers but also in "with this accuracy it cannot be determined whether you are inside or outside of the rectangle".
You need to find the nearest point on the main A-B line to the users location. Look at the following link for more information... Point Line
Now given that you can find the nearest point on a line from users point (current location) you can check if the distance between their location and the nearest point is within the threshold you are interested in, if it exceeds it then they are 'outside' of the zone around the line.
精彩评论