MapView annotations: finding coordinates - objective-c

I have many MKMapViews, and each of them has an annotation. I am trying to retrieve the coordinates of each in this way:
for (MKMapView *map in MapViewArray)
{
// add textfield contents to array
NSString *latitude = [NSString stringWithFormat:#"%#", map.annotations];
[latitudes addObject: latitude];
}
I was looking for the right code instead of this:
map.annotations
I want to find the latitude here..
How can I do this??

Each map annotation is an object, so you'll have to get the coordinate value from the annotation instead. The annotations are stored in map.annotations, which is an array. If you only have one annotation per map, you can use this:
CLLocationCoordinate2D coordinate = [[map.annotations lastObject] coordinate];
NSString *latitude = [NSString stringWithFormat:#"%.2f", coordinate.latitude];
If you have multiple annotations, you'll obviously have to iterate through each one individually, then get the location data.

Related

MKMapPointForCoordinate returning invalid coordinates

I am working with MKMapView's, annotations, overlays, etc, but I'm having a pain in the butt issue with MKMapPointForCoordinate() returning an invalid coordinate.
Code:
MKMapPoint* pointArr;
for (Category* route in validRoutes){
NSString* routeID = [route routeid];
NSArray* pointData = [routes objectForKey:routeID];
pointArr = malloc(sizeof(MKMapPoint) * [pointData count]);
int i = 0;
for (NSDictionary* routeData in pointData) {
NSString* latitude = [routeData objectForKey:#"latitude"];
NSString* longitude = [routeData objectForKey:#"longitude"];
NSLog(#"L: %# L: %#",latitude, longitude);
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake([[f numberFromString:latitude] doubleValue], [[f numberFromString:longitude] doubleValue]);
NSLog(#"Coord: %f %f",coord.latitude,coord.longitude);
MKMapPoint point = MKMapPointForCoordinate(coord);
NSLog(#"Point: %f %f",point.x,point.y);
pointArr[i] = point;
i++;
}
MKPolyline *polyline = [MKPolyline polylineWithPoints:pointArr count: i];
polyline.title = [route name];
[routeOverlays setObject:polyline forKey: [route routeid]];
[map addOverlay:polyline];
free(pointArr);
}
Output Example:
L: 41.380840 L: -83.641319
Coord: 41.380840 -83.641319
Point: 71850240.204982 100266073.824832
I don't understand why the conversion to a MKMapPoint is destroying the values of my CLLocationCoordinate2D. The overlay doesn't show up on the map because the values are invalid...
EDIT: I got the point working by using MKMapPointMake instead, BUT, my overlay still isn't showing. This is the mapView: viewForOverlay: code:
-(MKOverlayView*)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay {
MKOverlayView *overlayView = nil;
//Checks if the overlay is of type MKPolyline
if([overlay isKindOfClass:[MKPolyline class]]){
MKPolylineView *routeLineView = [[MKPolylineView alloc] initWithPolyline:overlay];
routeLineView.strokeColor = [UIColor orangeColor];
routeLineView.lineWidth = 10;
return overlayView;
}
return nil;
}
The method gets called (Used a breakpoint to confirm), and I have annotations working (So the delegate has to be setup correctly, I assume)
Double edit: :facepalm: I was returning nil every time in the delegate code. That's what I get for copying and pasting the previous versions code ;P
An MKMapPoint is not a latitude/longitude in degrees (like CLLocationCoordinate2D).
They are not interchangeable and so you should not expect the MKMapPoint x,y values to show any obvious relation to the corresponding latitude and longitude.
An MKMapPoint is the conversion of latitude and longitude onto a flat projection using x,y values which are not in the same scale or range as latitude and longitude. Please see the Map Coordinate Systems section in the Location Awareness Programming Guide for a more detailed explanation.
By the way, if you have CLLocationCoordinate2D values, it's much easier to create a polyline using polylineWithCoordinates instead of polylineWithPoints. That way, you don't need to bother with any conversion.
See iOS SDK: MapKit MKPolyLine not showing for some more details and an example.

Load coordinates from text-file into NSMutableArray

Im generating a plain txt file from Physics editor. It contains all the vertices for my polygon. Because I want my polygon to be textured, im running it through a triangulation method located at: https://github.com/asinesio/cocos2d-PRKit/
And I need my data to come from an NSMutableArray to doso for it to work.
Physics editor can export .plist and .txt files, but for simplicity sake, I just want to get the vertices from the .txt file and turn them into CGPoints and then add them into a NSMutableArray
The txt file looks like this:
(53.4011993408203, -44.4011993408203)
, (74.4011993408203,
-38.4011993408203) , (-0.598802387714386,
0.598802387714386) , (-0.598802387714386,
-39.4011993408203) , ...
I think the method would be to:
Load the data from its source.
Scan the data excluding parenthesis and alphbetical characters.
Take all the data upto the comma and add it into the CGPoint (x(1),y(0)).
Then scan all the data upto the next comma and insert it into the CGPoint (x(1),y(1)).
Then add this CGPoint to a NSMutableArray.
Continue scanning the document until all coordinates have been added.
This method could then be used with different text-files to create simplicity. Etc:
Level1ground.txt, Level2ground.txt.. It would be fantastic if I could get it running.
Could someone please help me with this?
Much Appreciated,
Oliver.
This solution assumes that you have loded the file already into a string.
You can make use of pathForResource:ofType:inDirectory: of NSBundle class to load a file.
NSArray * rawPoints = [#"(53.4011993408203, -44.4011993408203) , (74.4011993408203, -38.4011993408203) , (-0.598802387714386, 0.598802387714386) , (-0.598802387714386, -39.4011993408203)" componentsSeparatedByString:#" , "];
for (NSString * rawPoint in rawPoints) {
NSString *tmp = [rawPoint stringByReplacingOccurrencesOfString:#"(" withString:#""];
tmp = [tmp stringByReplacingOccurrencesOfString:#"(" withString:#""];
NSArray * coordinates = [tmp componentsSeparatedByString:#", "];
CGPoint point;
for (NSString * coordinate in coordinates) {
point = CGPointMake([[coordinates objectAtIndex:0] floatValue],
[[coordinates objectAtIndex:1] floatValue]);
}
NSLog(#"x:%f, y:%f", point.x, point.y);
}
In this case, you probably want to use an NSScanner instance. See -scanUpToCharactersInSet: and -scanFloat.

NSMutableArray with NSDictionary to Labels without the surrounding brackets

I'm making a scoreboard for my game. And when I do a NSLog of the data it comes out as this:
{
name = TTY;
score = "3.366347";
}
So my question is how do I remove this brackets and also just grab the name (TTY) and score (3.36 without the quotations) and place them in variable for me to put into labels.
Currently I can place them in labels but they have the lingering curly braces "{" and "}".
Any hints would be helpful as I'm happy to search further I just don't know the vocab to search for it.
thanks
For NSDictionary if you want to get the values you use objectForKey: method;
[scoreDictionary objectForKey:#"name"];
In your case the method will return TTY
You can store this in a variable like normal:
NSString *entryName = [scoreDictionary objectForKey:#"name"];
For NSArray (and NSMutableArray) you use objectAtIndex: method;
[scoresArray objectAtIndex:0];
I'm guessing that you have many NSDictionary in the NSArray, in which case you can combine the two methods above and get;
[[scoresArray objectAtIndex:0] objectForKey:#"name"];
which will give you the value of name in the first dictionary of the array.
Also if you want to access multiple key values you can use;
NSDictionary *entry = [scoresArray objectAtIndex:0];
NSString *entryName = [entry objectForKey:#"name"];
NSString *entryScore = [entry objectForKey:#"score"];

Using CGPoints in an NSArray

I have been trying to create an array stating the location of a UIImageView in an app I've been working on. What I am trying to do is by using an array I can store the location of my "player" image by using its x,y and z coordinates. The script I am trying to accomplish would look like
NSArray *location[3];
-(IBAction)startup;{
[location addObject: player.center.x];
[location addObject: player.center.y];
[location addObject: playerheight];
}
So I will be able to access this array to move my "player" on the screen in "3-dimensions", but I don't know how to convert the CGpoint values to NSValues so they can be used in the array, is there a simple way to do this inside of the array?
To convert floating point values to objects, use NSNumber. NSValue has wrappers for geometric types like CGPoint. Either would work for you.
[NSValue valueWithCGPoint:player.center];
[NSNumber numberWithFloat:player.center.x];
[NSNumber numberWithFloat:player.center.y];
To addition for the first answer.
When you'll need to read CGPoint back from your array, you can use something like that:
CGPoint point = [(NSValue *)[pointsArray objectAtIndex:i] CGPointValue];
Also note that there's no addObject method for NSArray (you can't add objects to an NSArray after its been created); you want NSMutableArray.
Instead of:
NSArray *location[3];
you probably want something more like:
NSMutableArray *location = [NSMutableArray arrayWithCapacity:3];
Does it have to be an NSArray? Why not use an array of structs?
typedef struct {
CGPoint location;
CGFloat height;
} PlayerLocation;
PlayerLocation players[3];
players[0].location = player.center;
players[0].height = playerheight;
Or depending on your design it may make more sense to declare an objective-C class that contains the x,y,z coordinates as ivars and store those objects into an NSArray.
#interface PlayerLocation : NSObject {
CGPoint location;
CGFloat height;
}
#end

Comparing Touch Coordinates

Is it possible to compare touch coordinates made by the users on the UIView to the one store in a plist or txt format? The argument looks like this;
if (user touch coordinate == touch coordinate stored in plist or text)
then
(do something)
else
(do something)
If possible in what format should i write the coordinates in the list and how to associate it inside the program?
thanks in advance and sorry if you find my question a bit noobie.
Not sure if there's a one-liner solution.
On a UITouch instance, the locationInView: method returns a CGPoint struct (x and y coordinates, both of type float). So you can store the x and y coordinates in your plist, then compare them with your current touch's x and y coordinates.
EDIT:
Also, when comparing the coordinates, you probably want to use the distance between the two points to determine when you have a "hit".
EDIT:
Below is sample code for loading and writing to a property list, where the values are based on a NSDictionary:
- (NSMutableDictionary *)loadDictionaryFromPList: (NSString *)plistName
{
NSString *plistPath = [[NSBundle mainBundle] pathForResource:plistName ofType:#"plist"];
NSDictionary *immutableDictionary = [NSDictionary dictionaryWithContentsOfFile: plistPath];
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary: immutableDictionary];
return mutableDictionary;
}
- (void)saveDictionary: (NSDictionary *)mySettings toPList: (NSString *)plistName
{
NSString *plistPath = [[NSBundle mainBundle] pathForResource:plistName ofType:#"plist"];
[mySettings writeToFile: plistPath atomically: YES];
}
The method to calculate the distance between the two locations of the UITouches:
-(CGFloat) distanceBetween: (CGPoint) point1 and: (CGPoint)point2
{
CGFloat dx = point2.x - point1.x;
CGFloat dy = point2.y - point1.y;
return sqrt(dx*dx + dy*dy );
}
And finally, the code that uses the values in the property list to determine if the user hit the previous location:
CGPoint currentTouchLocation = [currentTouch locationInView:self];
// Lookup last Touch location from plist, and handle case when current Touch matches it:
NSMutableDictionary *mySettings = [self loadDictionaryFromPList: #"MySettings"];
NSNumber *lastXCoordinate = [mySettings objectForKey:#"lastXCoordinate"];
NSNumber *lastYCoordinate = [mySettings objectForKey:#"lastYCoordinate"];
if (lastXCoordinate && lastYCoordinate)
{
CGPoint lastTouchLocation = CGPointMake([lastXCoordinate floatValue], [lastYCoordinate floatValue]);
CGFloat distanceBetweenTouches = [self distanceBetween: currentTouchLocation and: lastTouchLocation];
if (distanceBetweenTouches < 25) // 25 is just an example
{
// Handle case where current touch is close enough to "hit" previous one
NSLog(#"You got a hit!");
}
}
// Save current touch location to property list:
[mySettings setValue: [NSNumber numberWithFloat: currentTouchLocation.x] forKey: #"lastXCoordinate"];
[mySettings setValue: [NSNumber numberWithFloat: currentTouchLocation.y] forKey: #"lastYCoordinate"];
[self saveDictionary:mySettings toPList: #"MySettings"];
The functions you're probably looking for are NSStringFromCGPoint() and CGPointFromString().
But two touch coordinates will almost certainly never be the exact same. You should almost never be comparing CGFloats with ==, let alone ones you get from such an analog input as a finger touch. You need to compare whether they are "close enough." See this blog for a good example of how to measure the distance between two points. You want that result to be less than some value (epsilon, or "a small number") that is appropriate for your purposes.