tags:

views:

473

answers:

3

Hi,

I have a static map image with a bunch of circles and squares on it that depict cities. I have loaded the image into an imageView that is sub-classed under a scrollView so that I can capture user touches and zoom/scroll across the map. My challenge is that I want to pop-up a label whenever a user touches one of these circles/squares for a city to tell them which city it is and possibly load a detail view for the city. I figured I could pre-load all the relative CGPoints for the cities based on the imageView map into a dictionary so I can reference them during a "touchesBegan" event, but I'm quickly getting in over my head and possibly going about this the wrong way.

So far everything is working and I can capture the CGPoint x and y coordinates of touches. The biggest issue I have is determining the proximity of the user touches to a discrete point I may have in the dictionary. In other words if the dictionary has "Boston = NSPoint: {235, 118};" how can I tell when a user is close to that point without making them repeat the touch until it is exact? Is there an easy way to determine if a user touch is "close" to a pre-existing point? Am I going about this the right way?

Any advice or slaps in the back of the head are welcome.

Thanks, Mike

A: 

you can either use an R-Tree, or you can calculate the proximity of the touch to each visible point in the current view. To calculate the proximity you would normally use the Pythagorean theorem but in this case you can skip the square-root because you're only comparing the relative sizes. Also you can declare a distance cut off if you like say 50 pixels squared to 2500. So you'd put the result into an object containing distance and reference point and put the objects in an NSMutableArray, not adding the results under your cutoff, and select the minimum result.

So if you have a touched point pT, then for each point pN, you'd calculate:

d=(pT.x-pN.x)*(pT.x-pN.x) + (pT.y-pN.y)*(pT.y-pN.y); //d is the squared distance

The point pN with the minimum d is the point that was closest to pT. And like I said if you want only touches within 10 pixels to count, you can test that d <= 10*10;

The method of testing for touches within a 20x20 square area works too, except if two points are within 20 pixels of each other, then you need to know which is the closest touched point.

dlamblin
mehal
A: 

You could use UIButtons to represent the cities. Then you'll get the standard touch, highlight, etc, behaviors with less effort. Adding the buttons as subviews on your map should cause them to scale and scroll along with the map.

Mark Bessey
I thought about that, but figured with 50+ city points, it would be crazy to declare/manage so many objects. Thanks for responding though - Mike.
mehal
While it might seem crazy, you could just iterate through your dictionary, pull out the city's point, create a new button about 15px by 15px, and then setCenter with the point of the city. The other thing you'd need to do is wire up the button to a method (addTarget:action:forControlEvent:), and make sure you have a way of recognizing which button corresponds to which city. One way to do that is to set the tag property of the button to be the index of the city in an array.
Dave DeLong
Thanks Dave, that is basically what I did. I iterate through a dictionary of points doing a compound if statement compare (+/- 10) and then when I find a point within tolerance, I pull the name of the city from the dictionary and create/display a view with the city name and a few buttons for user actions. - Thanks again, Mike
mehal
Thanks to everyone who responded, my solution is posted above in response to Dave's suggestions. - Mike
mehal
A: 

if i understand it correctly, you want to know if the point at which the user tapped is "close" enough to a point that is marked as a city.

you would have to quantify close i.e. set a threshold value after which the tap is farther, before which the tap is closer.

once you do that, calculate the cartesian coordinate distance sqrt ( (x1-x2)^2 + (y1-y2)^2) for each element ( read dictionary with x,y values for cities) in the array and store the results in another array. then take the minimum of the result. the index of that result is the city that is closest to the tap if it is lesser than the said threshold.