I have an iPad app that has a feature that shows a region in a MKMapView along with the user's location. This used to work fine, but now it always displays the entire U.S. as the region no matter what I set it as. It does however correctly show the user's location.
The code that sets the region is...
MKCoordinateSpan span = {.latitudeDelta = latSpan, .longitudeDelta = longSpan};
MKCoordinateRegion mapRegion = {center, span};
[self.mapView setRegion:mapRegion];
The values for these variables are...
center = {latitude = 37.525553000000002, longitude = -121.9351005}
latSpan = 0.0029800000000008708
longSpan = 0.011071000000001163
I've double checked, and the center is exactly the location I want, but it doesn't matter what values I put for any of these, I always just get the entire U.S. as the region.
Any ideas what has changed or what I overlooked?
I would really appreciate any help as this driving me crazy...
MapKit will be unable to zoom into the user's location if authorization is not provided by the user.
The result can be that only a display of the United States is shown.
Request permission using:
let locationManager = CLLocationManager()
locationManager.requestWhenInUseAuthorization()
Also add the key NSLocationWhenInUseUsageDescription to your target's Info.plist. The type is a string and is shown to the user during the authorization request.
Not to put too fine a point on it: you're lying. I ran your code with your values and it works perfectly:
The code for this app consists entirely of your values and your code:
#import "ViewController.h"
#import MapKit;
#interface ViewController ()
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
CLLocationCoordinate2D center = {37.525553000000002, -121.9351005};
double latSpan = 0.0029800000000008708;
double longSpan = 0.011071000000001163;
MKCoordinateSpan span = {.latitudeDelta = latSpan, .longitudeDelta = longSpan};
MKCoordinateRegion mapRegion = {center, span};
[self.mapView setRegion:mapRegion];
}
#end
So clearly you are not telling the truth; you're leaving out something important about what you're doing, because when I do what you say you're doing, I get the right result.
Related
i am using here maps in my app and works fine. i pass destination coordinate from one view controller to another viewcontroller which contains here map and its methods. i tried to get the current location inside the method in the second view controller to calculate the roue, but current location always returns 0,0.please advice how to get current location inside the method where i pass the values from first viewcontroller
viewcontroller1:
- (IBAction)btn_navigate:(id)sender
{
NSLog(#"%#",_POiarray);
_VC=[[NaviMeVC alloc]init];
[_VC GetPoi:_POiarray];
[self.navigationController pushViewController:_VC animated:YES];
}
mapviewcontroller:
-(void)GetPoi:(NSMutableArray *)anArray
{
//get current location
NMAGeoPosition * position=[[NMAGeoPosition alloc]init];
position = [[NMAPositioningManager sharedPositioningManager] currentPosition];
_StartCoordinate=[[NMAGeoCoordinates alloc]initWithLatitude:position.coordinates.latitude longitude:position.coordinates.longitude];
//not working returns nil
[[NMAMapLoader sharedMapLoader] setDelegate:self];
_SelectedPOi=[[NSMutableArray alloc]init];
_SelectedPOi=anArray;
NSString *lat=[anArray valueForKey:#"latitude"];
CLLocationDegrees latitu=[lat doubleValue];
NSString *longi=[anArray valueForKey:#"longitude"];
CLLocationDegrees longit=[longi doubleValue];
_DestinationCoordinate=[[NMAGeoCoordinates alloc]initWithLatitude:latitu longitude:longit];
NSLog(#"%f %f",_DestinationCoordinate.latitude,_DestinationCoordinate.longitude);
NSNumber *lati = [NSNumber numberWithDouble:latitu];
NSNumber *longitu = [NSNumber numberWithDouble:longit];
NSDictionary *userLocation=#{#"lat":lati,#"long":longitu};
NMARoutingMode* routingMode = [[NMARoutingMode alloc] initWithRoutingType:NMARoutingTypeShortest
transportMode:NMATransportModeCar
routingOptions:0];
[self CalculateRoute:routingMode];
}
To start receiving positioning updates you need to call NMAPositioningManager startPositioning which I don't see in your sample code. More details in user guide link below. Please read the other instructions on that page to see if anything helps.
Another thing to check: have you added NSLocationWhenInUseUsageDescription into your projects Info.plist file to ensure your app can receive user location from CLLocationManager?
Also, this may seem obvious but please keep in mind that you will only be able to receive a valid value for currentPosition if you have a position fix.
Positioning User Guide
NMAPositioningManager Doxygen
I'm trying to code in a basic ArcGIS workflow into my iOS project. I am new to this platform and can use some pointers. My workflow is as follows.
1.) Create mapView displaying satellite (world style) map.
2.) Add a public webMap from my user account on ArcGIS Online as an overlay/layer on the satellite map.
What I've tried
//.h
#import <ArcGIS/ArcGIS.h>
#interface ViewController : UIViewController <AGSWebMapDelegate>
#property (strong, nonatomic) IBOutlet AGSMapView *mapView;
//.m
// Add basemap
NSURL* url = [NSURL URLWithString:#"http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"];
AGSTiledMapServiceLayer *tiledLayer = [AGSTiledMapServiceLayer tiledMapServiceLayerWithURL:url];
[self.mapView addMapLayer:tiledLayer withName:#"Basemap Tiled Layer"];
//If I run this part alone, I'll get the satellite map.
AGSWebMap* webmap = [[AGSWebMap alloc] initWithItemId:#"bb9b8c172e8142f995526bf658078f54" credential:nil];
webmap.delegate = self;
[webmap openIntoMapView:self.mapView];
//When I add this webMap code and run the project, I get a blank white screen.
//.m cont.
- (void)mapViewDidLoad:(AGSMapView *) mapView {
NSLog(#"mapView didLoad");
}
- (void) webMapDidLoad:(AGSWebMap*) webMap {
NSLog(#"webmap added successfully");
}
//Neither of these logs get called.
Questions.
1.) Is it right to use AGSTiledMapServiceLayer as my basemap? Also, is it right to use AGSWebMap for my ArcGIS Online map?
2.) My goal is to be able to add and remove multiple layers to and from a satellite basemap, one at a time. Am I on the right track?
I'm currently using MapBox to achieve this but I'm starting to experiment with ArcGIS SDK and it's features.
Thanks in advance.
You are almost there. Make sure all 3 of these items are in the proper pace.
From the discussion from https://developers.arcgis.com/ios/objective-c/guide/viewing-web-map.htm.
Make these calls where you made them before (presumably viewDidLoad)
instantiate an AGSWebMap object // 1
An instance of your class must then be set as the web map's delegate // 2
// 1
AGSWebMap* webmap = [[AGSWebMap alloc] initWithItemId:#"bb9b8c172e8142f995526bf658078f54" credential:nil];
// 2
webmap.delegate = self;
Then update the handler webMapDidLoad() // 3
// open the web map into a map view in the delegate handler
- (void) webMapDidLoad:(AGSWebMap*) webMap {
// 3
[webmap openIntoMapView:self.mapView];
NSLog(#"webmap added successfully");
}
Hey so I have a map view that zooms in on the users location upon view load. Currently I find the users location using the CLLocationManager and initialize the map in the didUpdateLocations delegate method. However, as this is called multiple times I use a global BOOL that is set to true after the map is set once and then never set it again. Here is the code:
Define global BOOL and set it to false in the viewDidLoad:
#implementation MainMapViewController
{
BOOL hasInitializedMap;
}
- (void)viewDidLoad
{
[super viewDidLoad];
hasInitializedMap = NO;
}
I then get the user's location and set the maps zoom inside the (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations delegate method:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *location = [locations lastObject];
[self initializeMainMapView:location.coordinate.longitude latitude:location.coordinate.latitude];
}
- (void)initializeMainMapView:(float)longitude latitude:(float)latitude
{
if (!hasInitializedMap)
{
CLLocationCoordinate2D zoomLocation;
zoomLocation.latitude = latitude;
zoomLocation.longitude = longitude;
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation, 1500, 1500);
[mainMapView setRegion:viewRegion animated:YES];
hasInitializedMap = YES;
}
}
This code works but has left me wondering if there is a better way to do this. I hate using global flags like this as it can make your code confusing and is sloppy at best. Is there a better way to do what I am trying to do? Is there a delegate method that only gets called when the users position is updated for the first time? Can I do this with just the MKMapView and forget CoreLocation altogether?
I've done it a few ways... in fact the framework has been changed a few times so I can't remember how I settled on it. The MKMapkit does have a method for showing user location, developer doc:
This property does not indicate whether the user’s position is actually visible on the map, only whether the map view should try to display it. Setting this property to YES causes the map view to use the Core Location framework to find the current location and try to display it on the map. As long as this property is YES, the map view continues to track the user’s location and update it periodically. The default value of this property is NO.
Showing the user’s location does not guarantee that the location is visible on the map. The user might have scrolled the map to a different point, causing the current location to be offscreen. To determine whether the user’s current location is currently displayed on the map, use the userLocationVisible property.
The user's location will appear as an annotation. You can get the annotation and zoom in on that. what would be better would be to use that flag in conjunction with the MKMapViewDelegate which has a method -mapView:DidUpdateUserslocation:
delegate documentation
Maybe after you get the first one you can change the map's tracking mode to none (i'm not sure if that removes the user location annotation or not, if it does, you can easily drop a map pin there with the proper skin). -setUserTrakingMode:animated: is the method on MKMap can use for that.
One thing I would caution on, in writing apps that work with user location in the past, it take a few seconds to get an accurate location. You might want to let the GPS ping a few times first before you lock in on a position. I've found that the first few ticks can be wildly inaccurate. Hope that helps.
I've a tableViewController that presents a list of places sorted by name!
This list is retrieved from my MySQL database using the query
SELECT Name FROM Places ORDER BY Name.
But my goal is to sort them by location according to userLocation.
So, Any Place in the database has the fields "latitude" and "longitude". How do I order them by latitude and longitude based on the userLocation?
SELECT Name FROM Places ORDER BY ???.
Clearly latitude and longitude of each places are already inserted into the db. I give the user location as a parameter in the string (and I already have saved in a plist):
[NSString stringWithFormat: # "SELECT Name FROM ORDER BY Places% #,% #", _myLatitude, _myLongitude "];
Please help me!
First, I suggest you to use a DTO. Something like this:
#interface Place : NSObject
#property(nonatomic, strong) NSString * name;
#property(nonatomic, strong) CLLocationCoordinate2D * coord;
#end
Then use a DAO to get all the places in an NSArray like Anna Karenina suggest you.
#interface PlaceDAO : NSObject
- (NSArray *) places;
- (id) sharedInstance;
#end
Finally you can sort with that:
1. Create a Category of CLLocation to calculate what coord is nearest to a reference coord.
//CLLocation+DistanceComparison.h
static CLLocation * referenceLocation;
#interface CLLocation (DistanceComparison)
- (NSComparisonResult) compareToLocation:(CLLocation *)other;
#end
//CLLocation+DistanceComparison.m
#implementation CLLocation (DistanceComparison)
- (NSComparisonResult) compareToLocation:(CLLocation *)other {
CLLocationDistance thisDistance = [self distanceFromLocation:referenceLocation];
CLLocationDistance thatDistance = [other distanceFromLocation:referenceLocation];
if (thisDistance < thatDistance) { return NSOrderedAscending; }
if (thisDistance > thatDistance) { return NSOrderedDescending; }
return NSOrderedSame;
}
#end
2. Add a compare method to your Place DAO.
- (NSComparisonResult)compare:(Place *)otherObject {
return [self.coord compareToLocation:otherObject.coord];
}
3. Finally sort the array like this.
NSArray * places = [[PlacesDAO sharedInstance] places];
referenceLocation = userLocation;
NSArray * mySortedPlaces = [places sortedArrayUsingSelector:#selector(compare:)];
referenceLocation = nil;
Don't forget add include the category.
Since you already have the latitude and longitude of the places, send the user location (lat & lng) to the stored procedure which you have created. Calculate the distance and try ordering them by the distance.
Refer this article for distance formula.
Ideally, you want to keep this in SQL for speed. You want the Euclidian distance between points, which is basically what Bharadwaj linked -- using the hypotenuse to figure out distances (distance is the square root of the x and y deltas each squared and summed). This is far faster than loading all data out of your MySQL instance and using CLLocation comparisons.
Euclidian distance isn't perfectly accurate -- it refers to distances on a plane, not on the surface of a sphere, but it's probably close enough for your needs.
You should be able to do this math right in your SQL statement.
I am able to successfully show the user their current location on a MapView. However when I go to another view controller and come back to my mapview, I see a blue screen. Why?
This is my code:
- (void)viewWillAppear:(BOOL)animated {
MyManager * myManager = [MyManager sharedInstance];
//if coming back from another screen, lets load the coordinates
if (myManager.centerOfMap) {
NSLog(#"myManager.centerOfMap has a value:");
self.centerOfMap = myManager.centerOfMap;
}
CLLocationCoordinate2D zoomLocation;
zoomLocation = *(self.centerOfMap);
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation, 0.5*METERS_PER_MILE, 0.5*METERS_PER_MILE);
MKCoordinateRegion adjustedRegion = [_mapView regionThatFits:viewRegion];
[_mapView setRegion:adjustedRegion animated:YES];
}
A blue screen is often a sign that you're point to (0,0) off the coast of Africa. Try printing out the coordinates of centerOfMap
At the point you come back, is the MKMapView allocated or does it show nil in the debugger?
Not sure? When you come back to your view controller, in the code go ahead and set a breakpoint and, in the console, type "po _mapView". Look at the result.
If it is nil, you probably have to Alloc/Init it. What's probably going on is that ARC is automatically flushing out the MKMapView in order to save memory.
Just a question, are you presenting the new View Controller in a modal way using [yourMainViewController presentViewController:newViewController animated:YES]?
This bit sets off alarm bells:
CLLocationCoordinate2D zoomLocation;
zoomLocation = *(self.centerOfMap);
This presumably corresponds to
#property (nonatomic, assign) CLLocationCoordinate2D * centerOfMap;
Which means it's highly likely that it now points to a random bit of stack, which has since been overwritten. It is highly likely that the high-order word is between 0 and 0x4000000 (0 and a billion - most integers and memory addresses will be in this range), which means you end up with a double between (approximately) 0 and 2.
Get rid of the *.