Comparing Touch Coordinates - objective-c

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.

Related

AnyObject To CGPoint

I cant seem to figure this out, I have a Objective-C function that returns an NSArray, I know for sure that data inside the NSArray contains CGPoint objects How in the world do I cast this to an Array
Here is the function
+(NSArray *)translatePoints:(NSArray *)points fromView:(UIView *)fromView toView:(UIView *)toView
{
NSMutableArray *translatedPoints = [NSMutableArray new];
// The points are provided in a dictionary with keys X and Y
for (NSDictionary *point in points) {
// Let's turn them into CGPoints
CGPoint pointValue = CGPointMake([point[#"X"] floatValue], [point[#"Y"] floatValue]);
// Now translate from one view to the other
CGPoint translatedPoint = [fromView convertPoint:pointValue toView:toView];
// Box them up and add to the array
[translatedPoints addObject:[NSValue valueWithCGPoint:translatedPoint]];
}
return [translatedPoints copy];
}
Your translatesPoints method returns an NSArray that contains NSValues that wrap CGPoints. Let's create such an array:
let arr:NSArray = [NSValue(CGPoint: CGPointMake(1,2)), NSValue(CGPoint: CGPointMake(3,4))]
You can get the values from this array and call CGPointValue() on them:
for val in arr as [NSValue] {
let point = val.CGPointValue()
println("CGPoint = (\(point.x), \(point.y))")
}
If you want, you can convert the entire NSArray to a Swift array of CGPoints like this:
let points = (arr as [NSValue]).map({$0.CGPointValue()})
Now points has the type [CGPoint].

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.

MapView annotations: finding coordinates

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.

Find the closest CCSprite

I am trying to find the closest "player" to a "ball" and each of these objects are CCSprite Objects. This is my first app, so if there's a better way to do this, feel free to suggest it :)
Here's my code so far:
for(CCSprite *currentPlayer in players) {
// distance formula
CGFloat dx = ball.position.x - currentPlayer.position.x;
CGFloat dy = ball.position.y - currentPlayer.position.y;
CGFloat distance = sqrt(dx*dx + dy*dy);
// add the distance to the distances array
[distances addObject:[NSNumber numberWithFloat:distance]];
NSLog(#"This happen be 5 times before the breakpoint");
NSLog(#"%#", [NSNumber numberWithInt:distance]);
}
So this seems to work well; it logs each distance of the player from the ball. But then when I loop through my "distances" array, like this:
for(NSNumber *distance in distances ) {
NSLog(#"Distance loop");
NSLog(#"%#", [NSNumber numberWithInt:distance]);
}
And this is logging a huge number each time, like 220255312. I declare my distances array like this:
// setting the distance array
NSMutableArray *distances = [[NSMutableArray alloc] init];
What am I doing wrong?
Thanks for your time!
Use distance for the #"%#" like this:
for(NSNumber *distance in distances ) {
NSLog(#"Distance loop");
NSLog(#"%#", distance);
}
[NSNumber numberWithInt:distance]
In your first part distance is a CGFloat.
In the second part distance is a NSNumber.
numberWithInt can't take a NSNumber as its argument.
Hope this helps!
CCSprite *nearestPlayer;
for(CCSprite *currentPlayer in players) {
if(nearestPlayer == nil){
nearestPlayer = currentPlayer;
}
if(ccpDistance(ball.position, currentPlayer.position) < ccpDistance(ball.position, nearestPlayer.position)){
nearestPlayer = currentPlayer;
}
}

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