Merge all MKMapRects to single MKPolygon - iphone

I want to draw corridor using MKPolygon over MKMap using Mapkit. I have one route from station A to B.
I have MKMapRects around route for drawing corridor. Now i want to merge all rectangles in single Polygon and that is my Corridor along with route. How to join all the rectangles in single Polygon .
No.of rectangles : 160
Here i am attaching sample image indicating what i needed.
Here is code snippet.
for(int i=0;i<[self.boundingRectsArr count];i++) {
lat1 = [[[self.boundingRectsArr objectAtIndex:i] valueForKey:#"xLT"] doubleValue];
long1 = [[[self.boundingRectsArr objectAtIndex:i] valueForKey:#"yLT"] doubleValue];
lat2 = [[[self.boundingRectsArr objectAtIndex:i] valueForKey:#"xRT"] doubleValue];
long2 = [[[self.boundingRectsArr objectAtIndex:i] valueForKey:#"yRT"] doubleValue];
lat3 = [[[self.boundingRectsArr objectAtIndex:i] valueForKey:#"xRB"] doubleValue];
long3 = [[[self.boundingRectsArr objectAtIndex:i] valueForKey:#"yRB"] doubleValue];
lat4 = [[[self.boundingRectsArr objectAtIndex:i] valueForKey:#"xLB"] doubleValue];
long4 = [[[self.boundingRectsArr objectAtIndex:i] valueForKey:#"yLB"] doubleValue];
CLLocationCoordinate2D rect[5];
rect[0] = CLLocationCoordinate2DMake(lat1, long1);
rect[1] = CLLocationCoordinate2DMake(lat2, long2);
rect[2] = CLLocationCoordinate2DMake(lat3, long3);
rect[3] = CLLocationCoordinate2DMake(lat4, long4);
rect[4] = CLLocationCoordinate2DMake(lat1, long1);
MKPolygon* polyCorridor = [MKPolygon polygonWithCoordinates:rect count:5];
polyCorridor.title = #"Colorado";
[self.map addOverlay:polyCorridor];
}
Thanks in Advance. Welcome to your answers.
Regards, Sagar P.

So, to be fast:
Draw corrigor: draw second thick line.
Highlight objects in corridor: calculate them without a polygon union, but with distance-to-route approach.
You could draw two lines in your overlay implementation, one, thin, for route, and one for a corridor - thiiick and semi-transparent, you could try to calculate point to km ratio using data MKMapView provides and calculate the thick line width. And for the objects on map you want to highlight - you could use different approaches, there are number of algos for finding points near curve or a straight line. You even could be rather straightforward: split the route into straight lines and check the distance of all the objects - that would be very slow, but it will work (sure you'll need to google for those complex algos for that).

Simple, first convert the MKMapRects to MKPolygons, then create the union of all the MKPolygons using this library:
https://github.com/SunGard-Labs/MKPolygon-GPC unfortunately its not free.

Related

CLLocation distanceFromLocation

I am using CLLocation to work out the distance from the current user location, and an annotation. However I just wanted to know if this would be correct. I am currently using iPhone Simulator for this and according to the MKMapView the iPhone Simulator is situated here:
Lat: 0 Long: -1067024384
The annotation's position is:
workingCoordinate.latitude = 40.763856;
workingCoordinate.longitude = -73.973034;
However if you take a look in google maps you will find out how close these distances are, yet so far apart according to CLLocation. I am using the following code to determine the distance between them both.
CLLocation *loc = [[CLLocation alloc] initWithLatitude:annotation.coordinate.latitude longitude:annotation.coordinate.longitude];
CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:self.mapView.userLocation.coordinate.latitude longitude:self.mapView.userLocation.coordinate.longitude];
CLLocationDistance dist = [loc distanceFromLocation:loc2];
int distance = dist
NSLog(#"%i", distance);
The distance being NSLogged is 12769908. I believe that this is incorrect, and therefore there must be a problem with my code.
If there is please can you point it out!
You have two bad habits.
You should not depend on simulator in situations need hardware censor status. Especially when you want correct test.
You're handling types incorrectly. So you can't check values correctly. How is the longitude -1067024384? Longitude value is degrees. This means it's valid range is limited -90.0 ~ +90.0 by definition of longitude.
Your longitude value is out of range. This means one of these. You printed the value wrongly or the real value was wrong. Simulator can print wrong value. Or you printed the value with wrong method. You have to try:
Test on real device which has real hardware censors.
If bad result continues after that,
Review ALL of your application code.
Especially for printing, handling values. Check you're using correct types and castings in > each situations. Because you may did buggy operation in somewhere habitually.
And also, I recommend checking all of intermediate values like this.
CLLocationCoordinate2D annocoord = annotation.coordinate;
CLLocationCoordinate2D usercoord = self.mapView.userLocation.coordinate;
NSLog(#"ANNO = %f, %f", annocoord.latitude, annocoord.longitude);
NSLog(#"USER = %f, %f", usercoord.latitude, usercoord.longitude);
CLLocation *loc = [[CLLocation alloc] initWithLatitude:annotation.coordinate.latitude longitude:annotation.coordinate.longitude];
CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:self.mapView.userLocation.coordinate.latitude longitude:self.mapView.userLocation.coordinate.longitude];
NSLog(#"LOC = %f, %f", loc.coordinate.latitude, loc.coordinate.longitude);
NSLog(#"LOC2 = %f, %f", loc2.coordinate.latitude, loc2.coordinate.longitude);
CLLocationDistance dist = [loc distanceFromLocation:loc2];
NSLog(#"DIST: %f", dist); // Wrong formatting may show wrong value!
Try #"%f" and don't cast it that way.
In CLLocation.h
typedef double CLLocationDistance;

How To Declare an MKPolygon

Ey guys, so a seemingly simple problem but apparently too complicated for me. I am trying to create one instance of MKPolygon and it ain't going too well. Here is the code:
MKMapPoint point1 = {38.53607,-121.765793};
MKMapPoint point2 = {38.537606,-121.768379};
MKMapPoint point3 = {38.53487,-121.770578};
NSArray *mapPointArr = [[NSArray alloc] initWithObjects:point1,point2,point3,nil count:3]; //errors here
MKPolygon *polygon = [MKPolygon polygonWithPoints:mapPointArr count:3];
I am getting a bunch of errors on the line at which I initialize the array(incompatible type for argument 1...). Any idea what's wrong? Thanks in advance!
MKMapPoint is a plain c-structure and you can't add it to objective-c container directly.
In your case you do not need to do that as +polygonWithPoints: requires not a NSArray, but a c-array as 1st parameter. Proper way to create polygon will be:
MKMapPoint points[3] = {{38.53607,-121.765793}, {38.537606,-121.768379}, {38.53487,-121.770578}};
MKPolygon *polygon = [MKPolygon polygonWithPoints:points count:3];

How to use iPhone method -(CLLocationDistance)distanceFromLocation:(const CLLocation *)location

I am a new iPhone developer learning Objective-C, and am trying to dynamically calculate the distances between the users latitude/longitude coordinates, with latitude/longitude coordinates in a SQLite table. I know that we can use CLLocations method:
(CLLocationDistance)distanceFromLocation:(const CLLocation *)location
to do this, but I'm not sure how to use it given the data that I have. How does one use the above method using pairs of latitude/longitude coordinates, considering the above method only deals with location objects of type CLLocation? Can anyone give me a simple example of how to use this method using two pairs of latitude/longitude coordinates?
Just create CLLocation objects from your data:
// Assumption: lat1, lon1 and lat2, lon2 are double values containing the coordinates
CLLocation *firstLocation = [[[CLLocation alloc] initWithLatitude:lat1 longitude:lon1] autorelease];
CLLocation *secondLocation = [[[CLLocation alloc] initWithLatitude:lat2 longitude:lon2] autorelease];
CLLocationDistance distance = [secondLocation distanceFromLocation:firstLocation];

Determining distance using mapkit

How is a 1000ft or 1/2 mile distance determined with mapkit? Either a radius from some pin or the distance between two pins.
For example, I center the map on pin A. Pins B, C, and D are also on the map at various distances from pin A. B and C are within 1/2 mile from A but D is 1 mile away. I'd like to know that B and C are within 1/2 mile from A. How can I calculate that?
Since you've stated that the two different points are "pins", I'm going to assume you're using MKPinAnnotationView (or some other annotation view). If not, you're going to have to get the location some other way.
If you have pointers to the annotation objects for these locations, then you can easily call -coordinate on them, create CLLocations from these coordinates (using -initWithLatitude:longitude:), and then use the method -getDistanceFrom to retrieve the distance in meters. From there, it's an easy conversion to miles. All told, the code would look something like this:
CLLocationCoordinate2D pointACoordinate = [pointAAnnotation coordinate];
CLLocation *pointALocation = [[CLLocation alloc] initWithLatitude:pointACoordinate.latitude longitude:pointACoordinate.longitude];
CLLocationCoordinate2D pointBCoordinate = [pointBAnnotation coordinate];
CLLocation *pointBLocation = [[CLLocation alloc] initWithLatitude:pointBCoordinate.latitude longitude:pointBCoordinate.longitude];
double distanceMeters = [pointALocation getDistanceFrom:pointBLocation];
double distanceMiles = (distanceMeters / 1609.344);
You'll end up with the distance in miles, and can compare it from there. Hope this helps.
getDistanceFrom is now deprecated so here's an alternative answer for anyone looking to do this.
CLLocationCoordinate2D pointACoordinate = [pointAAnnotation coordinate];
CLLocation *pointALocation = [[CLLocation alloc] initWithLatitude:pointACoordinate.latitude longitude:pointACoordinate.longitude];
CLLocationCoordinate2D pointBCoordinate = [pointBAnnotation coordinate];
CLLocation *pointBLocation = [[CLLocation alloc] initWithLatitude:pointBCoordinate.latitude longitude:pointBCoordinate.longitude];
float distanceMeters = [pointALocation distanceFromLocation:pointBLocation];
float distanceMiles = (distanceMeters / 1609.344);
[pointALocation release];
[pointBLocation release];
As above, you could use float instead of double and you could cast the results to an int if you don't require the precision of the float like so:
int distanceCastToInt = (int) [pointALocation distanceFromLocation:pointBLocation];
The int is handy if you wanted to give a rough idea of distance in the annotation like so:
pointAAnnotation.title = #"Point A";
pointAAnnotation.subtitle = [NSString stringWithFormat: #"Distance: %im",distanceCastToInt];
The subtitle of the annotation would read "Distance: 50m" for example.
This is Swift 3 equivalent of the given answer:
let pointACoordinate = pointAAnnotation.coordinate
let pointALocation = CLLocation(latitude: pointACoordinate.latitude, longitude: pointACoordinate.longitude)
let pointBCoordinate = pointBAnnotation.coordinate
let pointBLocation = CLLocation(latitude: pointBCoordinate.latitude, longitude: pointBCoordinate.longitude)
let distanceMeters = pointALocation.distance(from: pointBLocation)
let distanceMiles = (distanceMeters / 1609.344)

iphone why is he using valueForKeyPath

I found some mapkit code on the internet that looks like this:
- (void)recenterMap {
NSArray *coordinates = [self.mapView valueForKeyPath:#"annotations.coordinate"];
CLLocationCoordinate2D maxCoord = {-90.0f, -180.0f};
CLLocationCoordinate2D minCoord = {90.0f, 180.0f};
for(NSValue *value in coordinates) {
CLLocationCoordinate2D coord = {0.0f, 0.0f};
[value getValue:&coord];
if(coord.longitude > maxCoord.longitude) {
maxCoord.longitude = coord.longitude;
}
--omitted the rest
I want to know why valueForKeypath is used to get the coordinate data, instead of just
[self.mapView.annotations]
Has it something to do with speed?
He's using the valueForKeyPath: construct to return an array of all the coordinates for all of the annotations.
Assuming that self.mapView is an MKMapView then it has an annotations property which returns an array of objects conforming to the MKAnnotation protocol. That means that every object in that array should implement the coordinate property. By issuing a call to [self.mapView valueForKeyPath:#"annotations.coordinate"] he is immediately getting an array of all of the coordinates without having to iterate over each individual annotation item in the array.
Without using the KVC construct here he'd have to do something similar to this:
NSMutableArray *coordinates = [NSMutableArray array];
for (id<MKAnnotation> annotation in self.mapView.annotations)
[coordinates addObject:annotation.coordinate];
In all, it just makes for simpler, easier to read code.