Geo-Fencing using Google Map in iPhone - ios

I am trying to Geo-fence using Google Map for iPhone app.
A lot of tutorials can be found for MKMapView. But can't find for the GMSMapView.
The basic thing is how to convert the screen coordinate (x,y) to the MapCoordinate lat/lng.
Is there any API available for Google Map in iOS for that conversion?
Thanks

You can use something like this:
GMSMapView* mapView = ...;
CGPoint point = ...;
...
CLLocationCoordinate2D coordinate =
[mapView.projection coordinateForPoint: point];
UPDATE:
The comments on the projection property in GMSMapView.h are:
/**
* 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).
*/
#property (nonatomic, readonly) GMSProjection *projection;
Therefore you can only access the .projection property after the map has rendered. It will be nil if you try to access it during loadView or viewDidLoad.
I don't know if there is a better way to tell if the map has been rendered, but I noticed that the mapView:didChangeCameraPosition: method is called once after the map view is first displayed, and that the map's projection property is valid there.
So, in your view controller's header, add GMSMapViewDelegate:
#interface ViewController : UIViewController <GMSMapViewDelegate>
When you allocate the map view, assign the delegate:
_map = [GMSMapView mapWithFrame: CGRectMake(0, 0, width, height) camera: camera];
_map.delegate = self;
[self.view addSubview: _map];
Then add the delegate method:
- (void)mapView: (GMSMapView*)mapView
didChangeCameraPosition: (GMSCameraPosition*)position
{
CGPoint point = CGPointMake(x, y);
CLLocationCoordinate2D coordinate =
[_map.projection coordinateForPoint: point];
}
Note that mapView:didChangeCameraPosition: is called every time the user changes the camera, so you'd probably need to use a flag, so that you only do your calculations the first time mapView:didChangeCameraPosition: is called.

No need to convert x,y to lat,long.
GMSCircle *fence = [GMSCircle circleWithPosition:locationCord radius:fenceRadius];
[fence setFillColor:[UIColor colorWithRed:102.0/255 green:178.0/255 blue:255.0/255 alpha:0.3]];
[fence setZIndex:100];
[fence setMap: _map];
Add this code when you are making GMSMapView and geo fence will be shown with your location marker.

Related

How to put iOS Magnifying Glass effect on Google Maps (GMSMapKit)

How to put the UITextView texting editing Magnifying Glass on the Google Maps GMSMapView
For example I have a GMSMapView to show my current location
I want to trigger a overlay Magnifying Glass view when calling delegate methods
mapView:didChangeCameraPosition: and mapView:willMove: in GMSMapViewDelegate
The purpose is to provide an overlay zooming subView according to the user tapping coordinates (like github.com/acoomans/iOS-MagnifyingGlass did on ImageView)
Please let me know if this is possible for Google Maps for iOS or if iOS MapKit can support this kind of customization
Update #2: mapView.addSubView(mapSubView) works now. But it pollutes the Main GMSMapView
Update #1: I tried mapView.addSubView, it seems does not work for GMSMapView although inherited from UIView
The intention of below code snippet is to retrieve user's touch point at the map and converts it into CGPoint for creating a second GMSMapView
func mapView(mapView: GMSMapView!, didTapAtCoordinate coordinate: CLLocationCoordinate2D) {
println("Tapping at (\(coordinate.latitude), \(coordinate.longitude))")
// 1. retrieve the user touch position as CLLocationCoordinate2D
let cameraPosition = GMSCameraPosition.cameraWithLatitude(coordinate.latitude, longitude: coordinate.longitude, zoom: 20)
// 2. convert it into CGPoint
let screenTouchPoints = mapView.projection.pointForCoordinate(coordinate)
// 3. set the CGRect for init the mapSubView
let frame = CGRectMake(screenTouchPoints.x, screenTouchPoints.y, 100, 100)
mapSubView = GMSMapView.mapWithFrame(frame, camera: cameraPosition)
// 4. Finally add to the main Map View
mapView.addSubview(mapSubView)
}
It seems plausible with a GMSMapView. Maybe have a second GMSMapView on top of the original(high corner radius to create a circle?) and animate the alpha and scale along with the zoom level within the second map. Do this whenever mapView:didChangeCameraPosition etc is called.
By taking reference to this Github Project, GMSMapView can also be magnified by putting the view hierarchy in this way:
View Controller > Magnifying View > The View want to be zoomed
The core rendering mechanism is
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, self.frame.size.width/2, self.frame.size.height/2 );
CGContextScaleCTM(context, scale, scale);
CGContextTranslateCTM(context, -touchPoint.x, -touchPoint.y + (self.scaleAtTouchPoint? 0 : self.bounds.size.height/2));
[self.viewToMagnify.layer renderInContext:context];
}
loupe = ACLoupe()
magnifyingGlass = ACMagnifyingGlass()
magnifyingView = ACMagnifyingView(frame: self.view.frame)
magnifyingView.magnifyingGlass = loupe
magnifyingView.addSubview(Your_Subview_here)
by this method the magnifying view can capture current frame context, because Magnifying View is the container of other views so that the capturing can show the current UI situation and zoom by 1.5 times (default scale factor)

Need to add a Fixed Overlay like on mapview in IOS

I need to create a map view interface, which is something similar to the OLA Cabs Application in iOS. What I exactly wanna do is to fix an overlay on mapView and allow the user to scroll the map view across it. So that the overlay can be fixed at any location the User wants it to, I searched a lot about overlays, in iOS and MapKit, but couldn't make it possible. If some one can give me tips for achieving this I would be really grateful. Here is a snapshot of the screen
Here the annotation remains fixed and you can move the map view across it, So that when you stop the mapview, the overlay will be pointing to the new location, where you stopped
Click here to download demo...
Create a fix MKAnnotation and image view object to animating the location change effect in Map view.
#property (nonatomic, strong) CustomAnnotation *fixAnnotation;
#property (nonatomic, strong) UIImageView *annotationImage;
Add this code in viewDidLoad() method:
// Fix annotation
_fixAnnotation = [[CustomAnnotation alloc] initWithTitle:#"Fix annotation" subTitle:#"Location" detailURL:nil location:self.mapView.userLocation.coordinate];
[self.mapView addAnnotation:self.fixAnnotation];
// Annotation image.
CGFloat width = 64;
CGFloat height = 64;
CGFloat margiX = self.mapView.center.x - (width / 2);
CGFloat margiY = self.mapView.center.y - (height / 2) - 32;
// 32 is half size for navigationbar and status bar height to set exact location for image.
_annotationImage = [[UIImageView alloc] initWithFrame:CGRectMake(margiX, margiY, width, height)];
[self.annotationImage setImage:[UIImage imageNamed:#"mapannotation.png"]];
Now have to remove image when you drag a map view and add image which looks like an annotation. And after completion of that add annotation and remove image from Map View.
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
NSLog(#"Region will changed...");
[self.mapView removeAnnotation:self.fixAnnotation];
[self.mapView addSubview:self.annotationImage];
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
NSLog(#"Region did changed...");
[self.annotationImage removeFromSuperview];
CLLocationCoordinate2D centre = [mapView centerCoordinate];
self.fixAnnotation.coordinate = centre;
[self.mapView addAnnotation:self.fixAnnotation];
}
Its not an map annotation overlay, its a normal UIImageView which has been placed over MKMapView, and it always used to get the lat-long for the center point of the map.
Hope this would be an easy way to achieve your goal.
#Kampai has added the same code for you.

MKMapView setRegion not working

I'm trying to set a custom starting region in an iOS app using MKMapView's setRegion. The app runs fine, and a map appears, but no matter what I try I can't get the region to change. I've tried many tutorials and solutions, but none are working. Here's my code:
-(void)viewDidAppear:(BOOL)animated{
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta = 0.001;
span.longitudeDelta = 0.001;
region.span = span;
region.center.latitude = 100;
region.center.longitude = 100;
[mapView setRegion:(region) animated:(TRUE)];
}
I have the MKMapView and Core Location frameworks added to the projects properly, I import MapKit.h, and I declare mapView, so I don't know why it's not working.
Thank you,
Jacob
It sounds like the map view's IBOutlet is not connected to the map view control in the xib/storyboard.
If it's not connected, the mapView variable will be nil and calling methods on it will do nothing.
In the xib/storyboard, right-click on View Controller and connect the mapView outlet to the map view control.
Additionally, although not necessary for just setting the region, also connect the map view's delegate outlet to the View Controller. This will be required if you later implement any map view delegate methods. If this is not done, the delegate methods won't get called.
Another separate point:
In your first code example, you are setting the region's center to 100, 100. Please note that this is an invalid coordinate. If the map view was actually connected, setting the center to this would have caused a crash with "Invalid Region". Latitude must be from -90 to +90 (longitude must be from -180 to +180).
By the way, the new coordinate you're trying in the code posted in the comment (26, 80) is in India. Since you're setting the span to a relatively small value, you'll need to zoom out a lot to see this.
However it was set as answered, I will let here an example of what worked for me, when I had no clue why setRegion was not working at all. In my case the problem was the I've initiated the MKMapView without a frame, e.g.:
override func viewDidLoad() {
...
self.mapView = MKMapView() // Wrong!
...
self.mapView.setRegion(...) // Does not work!
}
It looks like that the whole region thing is calculated with regards the the initial (CGRect). It worked for me by doing:
override func viewDidLoad() {
...
self.mapView = MKMapView(frame: CGRect(0, 108, self.mapView.bounds.width, self.mapView.bounds.height))
self.mapView.setRegion(...) // Oh, it works!
}
This problem was described here too.

New foursquare venue detail map

I really love the way foursquare designed venue detail view. Especially the map with venue location in the "header" of view ... How was it done? Details are obviously some uiscrollview (maybe uitableview?) and behind it (in the header) there is a map so when you scroll up the map is beeing uncovered as the scroll view bounces... does anyone has an idea how to do this?
Here's the way I manage to reproduce it:-
You need a UIViewController with a UIScrollView as its view. Then, the content of the UIView you add to your scrollview should look like this :-
- The frame of the MKMapView have a negative y position. In this case, we can only see 100pts of the maps in the default state (before dragging).
- You need to disable zooming and scrolling on your MKMapView instance.
Then, the trick is to move down the centerCoordinate of the MKMapView when you drag down, and adjust its center position.
For that, we compute how much 1point represent as a delta latitude so that we know how much the center coordinate of the map should be moved when being dragged of x points on the screen :-
- (void)viewDidLoad {
[super viewDidLoad];
UIScrollView* scrollView = (UIScrollView*)self.view;
[scrollView addSubview:contentView];
scrollView.contentSize = contentView.frame.size;
scrollView.delegate = self;
center = CLLocationCoordinate2DMake(43.6010, 7.0774);
mapView.region = MKCoordinateRegionMakeWithDistance(center, 1000, 1000);
mapView.centerCoordinate = center;
//We compute how much latitude represent 1point.
//so that we know how much the center coordinate of the map should be moved
//when being dragged.
CLLocationCoordinate2D referencePosition = [mapView convertPoint:CGPointMake(0, 0) toCoordinateFromView:mapView];
CLLocationCoordinate2D referencePosition2 = [mapView convertPoint:CGPointMake(0, 100) toCoordinateFromView:mapView];
deltaLatFor1px = (referencePosition2.latitude - referencePosition.latitude)/100;
}
Once those properties are initialized, we need to implement the behavior of the UIScrollViewDelegate. When we drag, we convert the move expressed in points to a latitude. And then, we move the center of the map using the half of this value.
- (void)scrollViewDidScroll:(UIScrollView *)theScrollView {
CGFloat y = theScrollView.contentOffset.y;
// did we drag ?
if (y<0) {
//we moved y pixels down, how much latitude is that ?
double deltaLat = y*deltaLatFor1px;
//Move the center coordinate accordingly
CLLocationCoordinate2D newCenter = CLLocationCoordinate2DMake(center.latitude-deltaLat/2, center.longitude);
mapView.centerCoordinate = newCenter;
}
}
You get the same behavior as the foursquare app (but better: in the foursquare app, the maps recenter tends to jump, here, changing the center is done smoothly).
The example above is nice. If you need more help, I think they're using something very similar to RBParallaxTableViewController. https://github.com/Rheeseyb/RBParallaxTableViewController
It's essentially the same effect that Path uses for its header photo.
Yonel's answer is nice, but I found a problem as I have a pin at the center of the map. Because the negative Y, the point is hidden under my UINavigationBar.
Then, I didn't set the Negative Y, and I correct my mapView.frame according the scroll offset.
My mapView is 320 x 160
_mapView.frame = CGRectMake(0, 160, 320, -160+y);
Hope this helps someone.

calling a method with parameters

i`m using MapKit framework and i want to ask you about something :
+ (NSUInteger)zoomLevelForMapRect:(MKMapRect)mRect withMapViewSizeInPixels:(CGSize)viewSizeInPixels
{
NSUInteger zoomLevel = MAXIMUM_ZOOM; // MAXIMUM_ZOOM is 20 with MapKit
MKZoomScale zoomScale = mRect.size.width / viewSizeInPixels.width; //MKZoomScale is just a CGFloat typedef
double zoomExponent = log2(zoomScale);
zoomLevel = (NSUInteger)(MAXIMUM_ZOOM - ceil(zoomExponent));
return zoomLevel;
}
this method..how can i know the value of mRect and viewSizeInPixels parameters to be able to call it?? thx in advance :)
The map view's current MKMapRect is the visibleMapRect property and the view size would be in frame.size (since MKMapView is a subclass of UIView) so the method would be called using something like:
NSUInteger zoomLevel = [UtilityClass
zoomLevelForMapRect:mapView.visibleMapRect
withMapViewSizeInPixels:mapView.frame.size];
UtilityClass is whatever class that method is in and replace mapView with whatever you map view is actually named.
By the way, the MapKit Framework Reference and the Location Awareness Programming Guide are worth looking at.

Resources