Get all annotations around another annotation - objective-c

I'm trying to get all annotations around another annotation on a specified area, but I can't figure how to do it. Now I'm trying with:
MKMapRect mapRect = MKMapRectMake(annotation.coordinate.longitude, annotation.coordinate.latitude, 10.0, 10.0);
NSSet *nearbyAnnotations = [map annotationsInMapRect:mapRect];
but nearbyAnnotations is empty. I tried by swapping longitude with latitude and also with bigger numbers for the 3rd and 4th parameters, but still no result. How I should do this?

An MKMapRect uses MKMapPoint units which are not the same thing as CLLocationDegrees.
The MKMapRectMake function needs the top-left MKMapPoint and then the width and height (again in MKMapPoint units).
Basically, you need to use the the MKMapPointForCoordinate function to help you do this conversion from degrees to MKMapPoint units.
First, you could construct an MKCoordinateRegion and then convert it to an MKMapRect.
For example:
//create a region 10km around the annotation...
MKCoordinateRegion mapRegion = MKCoordinateRegionMakeWithDistance
(annotation.coordinate, 10000, 10000);
//convert the MKCoordinateRegion to an MKMapRect...
MKMapRect mapRect = [self mapRectForCoordinateRegion:mapRegion];
The mapRectForCoordinateRegion method is something you have to write.
For an example of one way to write it, see this answer:
How to make the union between two MKCoordinateRegion
By the way, note that in your case, annotationsInMapRect will include the annotation that you are searching around (since you are using it as the center).

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.

Google Maps iOS SDK: How do I get accurate latitude and longitude coordinates from a camera's visibleRegion?

EDIT: This is now a confirmed bug with this SDK
I'm using version 1.1.1.2311 of the Google Maps for iOS SDK, and I'm looking to find the bounding latitude and longitude coordinates for the visible map on screen.
I'm using the following code to tell me what the current projection is:
NSLog(#"\n%#,%#\n%#,%#\n%#,%#\n%#,%#\n",
[NSNumber numberWithDouble:mapView.projection.visibleRegion.farLeft.latitude],
[NSNumber numberWithDouble:mapView.projection.visibleRegion.farLeft.longitude],
[NSNumber numberWithDouble:mapView.projection.visibleRegion.farRight.latitude],
[NSNumber numberWithDouble:mapView.projection.visibleRegion.farRight.longitude],
[NSNumber numberWithDouble:mapView.projection.visibleRegion.nearLeft.latitude],
[NSNumber numberWithDouble:mapView.projection.visibleRegion.nearLeft.longitude],
[NSNumber numberWithDouble:mapView.projection.visibleRegion.nearRight.latitude],
[NSNumber numberWithDouble:mapView.projection.visibleRegion.nearRight.longitude]);
From reading the headers, it seems that it may not be updated when the camera moves. Fair enough...
/**
* The GMSProjection currently used by this GMSMapView. This is a snapshot of
* the current projection, and will not automatically update when the camera
* moves. The projection may be nil while the render is not running (if the map
* is not yet part of your UI, or is part of a hidden UIViewController, or you
* have called stopRendering).
*/
But, it appears to update each time the delegate method is called, so I attempted to plot the coordinates to test them...
For the following on my phone:
The output of the NSLog from above gives me the following:
37.34209003645947,-122.0382353290915
37.34209003645947,-122.010769508779
37.30332095984257,-122.0382353290915
37.30332095984257,-122.010769508779
When plotting those coordinates using this I get a projection that seems off:
These coordinates are consistent across app launches which leads me to believe that I'm either consistently doing something wrong, I'm misunderstanding what visibleRegion is, or I've discovered a bug. Anyone care to help me figure out which one it is?
To get the bounding latitude and longitude you have to do the following steps:
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithRegion:self.googleMapsView.projection.visibleRegion];
CLLocationCoordinate2D northEast = bounds.northEast;
CLLocationCoordinate2D northWest = CLLocationCoordinate2DMake(bounds.northEast.latitude, bounds.southWest.longitude);
CLLocationCoordinate2D southEast = CLLocationCoordinate2DMake(bounds.southWest.latitude, bounds.northEast.longitude);
CLLocationCoordinate2D southWest = bounds.southWest;
Best regards
Robert
I saw your issue here. Hope that they fix this issue in next update.
But now we can take the real visible region like this:
CGPoint topLeftPoint = CGPointMake(0, 0);
CLLocationCoordinate2D topLeftLocation =
[_mapView.projection coordinateForPoint: topLeftPoint];
CGPoint bottomRightPoint =
CGPointMake(_mapView.frame.size.width, _mapView.frame.size.height);
CLLocationCoordinate2D bottomRightLocation =
[_mapView.projection coordinateForPoint: bottomRightPoint];
CGPoint topRightPoint = CGPointMake(_mapView.frame.size.width, 0);
CLLocationCoordinate2D topRightLocation =
[_mapView.projection coordinateForPoint: topRightPoint];
CGPoint bottomLeftPoint =
CGPointMake(0, _mapView.frame.size.height);
CLLocationCoordinate2D bottomLeftLocation =
[_mapView.projection coordinateForPoint: bottomLeftPoint];
GMSVisibleRegion realVisibleRegion;
realVisibleRegion.farLeft = topLeftLocation;
realVisibleRegion.farRight = topRightLocation;
realVisibleRegion.nearLeft = bottomLeftLocation;
realVisibleRegion.nearRight = bottomRightLocation;
[self drawPolylineWithGMSVisibleRegion:realVisibleRegion color:[UIColor redColor] width:10.0f forMap:mapView];
Drawing polyline method:
- (void)drawPolylineWithGMSVisibleRegion:(GMSVisibleRegion)visibleRegion
color:(UIColor*)color
width:(double)width
forMap:(GMSMapView*)mapView{
GMSPolylineOptions *rectangle = [GMSPolylineOptions options];
rectangle.color = color;
rectangle.width = width;
GMSMutablePath *path = [GMSMutablePath path];
[path addCoordinate:visibleRegion.nearRight];
[path addCoordinate:visibleRegion.nearLeft];
[path addCoordinate:visibleRegion.farLeft];
[path addCoordinate:visibleRegion.farRight];
[path addCoordinate:visibleRegion.nearRight];
rectangle.path = path;
[mapView addPolylineWithOptions:rectangle];
}
It works even for map with non-default bearing and angle.
The solution is to download the latest version of the SDK (1.2 at the time of this writing) as the issue has been fixed.
From the 1.2 release notes:
Resolved Issues:
- visibleRegion now reports correctly sized region on Retina devices
Download here.
Looks like the latitude and longitude coordinates you are printing out and manually plotting are possibly off a bit / being truncated. %f defaults to only print out to 6 decimal places.
Here's a related question that might help:
How to print a double with full precision on iOS?
Maybe you give the location Manager the wrong accuracy..
Try to increase it:
locationMgr.desiredAccuracy = kCLLocationAccuracyBest;
The battery is draining moreyy

How to generate CGPoint-Array out of UIBezierPath (to touch-slide object along given path) [duplicate]

This question already has an answer here:
Drag UIView around Shape Comprised of CGMutablePaths
(1 answer)
Closed 6 years ago.
I have a UIBezierPath (curved like an '8', with only 4 points in it) and I need to make some kind of CGPoint-Array out of it. Any ideas? thanx!
edit:
I have my bezier initlialized like that
-(void) initBezier
{
theBezierPath = [UIBezierPath bezierPath];
[theBezierPath moveToPoint:P(211.00, 31.00)];
[theBezierPath addCurveToPoint:P(870.00, 191.00) controlPoint1:P(432.00, -11.00) controlPoint2:P(593.00, 209.00)];
[theBezierPath addCurveToPoint:P(731.00, 28.00) controlPoint1:P(1061.95, 178.53) controlPoint2:P(944.69, 5.78)];
[theBezierPath addCurveToPoint:P(189.00, 190.00) controlPoint1:P(529.00, 49.00) controlPoint2:P(450.00, 189.00)];
[theBezierPath addCurveToPoint:P(211.00, 31.00) controlPoint1:P(-33.01, 190.85) controlPoint2:P(71.00, 37.00)];
}
and I animate an object on it with
anim = [CAKeyframeAnimation animationWithKeyPath:#"emitterPosition"];
anim.path = theBezierPath.CGPath;
anim.calculationMode = kCAAnimationCubicPaced;
anim.repeatCount = HUGE_VALF;
anim.duration = tme;
I want to animate the object on the path pixel by pixel (via touch-position). I want the object to "snap" a given coordinate of a touch to the nearest point on the curve so it touch-slides the object along the path.
Use the CGPathApply() function to iterate over all elements in a path. As one of the arguments, you have to specify a pointer to a function that will then be called for each path element. The path element data structure (of type CGPathElement) then contains the point(s) that describe it.
Use NSValue as a wrapper to add the points to an NSMutableArray.
Neither UIBezierPath nor CGPath provide a way to evaluate the points along an arbitrary Bezier path, or a way to find the nearest point on the path. You'll have to write that code yourself.
Fortunately, this is a very well-studied topic. This tutorial has a lot of useful information, to get you started. You're interested in "cubic" or "third-order" Bezier curves.

NSPoint and IMKCandidate Window Placement

I am using the inputmethodkit and trying to place a window underneath some text.
_currentClient is an IMKTextInput instance
candidates is an IMKCandidates instance
// Get the current location to place the window
NSRect tempRect = NSMakeRect(0, 0, 0, 0);
NSDictionary* clientData = [_currentClient attributesForCharacterIndex:0 lineHeightRectangle:&tempRect];
NSPoint* windowInsertionPoint = (NSPoint*)[clientData objectForKey:#"IMKBaseline"];
...
[candidates setCandidateFrameTopLeft:*windowInsertionPoint];
[candidates showCandidates];
Now, I know that the windowInsertionPoint variable is fine, when I debug I can see it's value, eg: NSPoint: {647,365}
However when I use this, the candidate window just shows in the bottom left corner of the screen. I haven't worked with screen placement of stuff before, so help is appreciated.
If I pass in arbitrary static values to setCandidateFrameTopLeft, it gets placed in the screen. The following works:
[candidates setCandidateFrameTopLeft:NSMakePoint(401, 354)];
Is it a pointer problem?
OK, the solution to this is that I am an idiot. Here is the code you need:
NSRect tempRect;
NSDictionary* clientData = [_currentClient attributesForCharacterIndex:0 lineHeightRectangle:&tempRect];
NSPoint windowInsertionPoint = NSMakePoint(NSMinX(tempRect), NSMinY(tempRect));
The documentation for IMKTextInput attributesForCharacterIndex says
lineRect: On return, a rectangle that frames a one-pixel wide rectangle with the height of the line. This rectangle is oriented the same way the line is oriented.
This means it returns an NSRect into the variable your passed it for the lineHeightRectangle value. The important point is that the location of that NSRect is the location of the character you are searching for. So, then you need to just make a point from that rectangle and use NSMinY for the Y value. The rectangle is only a single pixel wide so Min/Max for X are basically the same.
You probably don't have this issue anymore, but this works too, for future:
[candidates show:kIMKLocateCandidatesBelowHint];

How to recognize if CGPoint is included in shape?

I'm a beginner in quartz.
I'm wonderring a way that recognize if CGPoint is included in shape.
Please give me a help of Expert.
Follow is concept diagram.
In above three case,
Result I want is YES, Because three RED CGPoint is included in shape.
It is possible like follow way?
CGPoint RedPoint1 = {200,100};
CGPoint RedPoint2 = {200,200};
CGPoint RedPoint3 = {350,300};
BOOL includeRect;
includeRect = CGRectContainsPoint(RectCase, RedPoint1);
BOOL includeCircle;
includeCircle = CG ? ContainsPoint(CircleCase, RedPoint2)
BOOL includeBoldLine;
includeBoldLine = CG ? ContainsPoint(BoldLineCase, RedPoint3);
The ease of this all depends on how your shapes are defined.
If you have these as CGPathRefs or NSBezierPaths there is a containsPoint: method you could use.
If these are CGRects that have a transform applied to them, you can use the CGAffineTransformPoint methods to move the point into the same coordinate space and then use CGRectContainsPoint