Select to view content in your preferred language

AGSGeometryEngine, map not fully loaded

2720
7
Jump to solution
04-26-2012 11:34 PM
VasupreeRyser
Emerging Contributor
Hello,

I have a problem with AGSGeometryEngine, I have make the possibility to identify some room with an area selection. But it seems the map isn't fully loaded, when I click to the map, it's just the identify symbol it's appear but not my blue square. And after a while it's OK.

Here is a part of my code :

AGSGeometryEngine *ge = [AGSGeometryEngine defaultGeometryEngine]; AGSEnvelope *actualEnv = (AGSEnvelope *)[ge projectGeometry:self.mapView.visibleArea.envelope toSpatialReference:self.spaRef] ;  double xLength = actualEnv.xmax - actualEnv.xmin; 


With this, the actualEnv.xmax has a 0.0 value. And after a while it's the good value.

I have try to make this with the help of the forum :

//Previously in my method AGSEnvelope *visibleEnv = [[self.mapView.visibleArea.envelope copy] autorelease]; AGSSpatialReference *spaRef = [[self.spaRef copy] autorelease]; ... AGSGeometryEngine *ge = [AGSGeometryEngine defaultGeometryEngine]; AGSEnvelope *actualEnv = (AGSEnvelope *)[ge projectGeometry:visibleEnv toSpatialReference:self.spaRef] ;  double xLength = actualEnv.xmax - actualEnv.xmin;


But it's not better.

Thank you in advance for any help.
0 Kudos
1 Solution

Accepted Solutions
NimeshJarecha
Esri Regular Contributor
Okay..let???s look at one issue at a time. You can create new thread for other issue.

By looking at the code???there are few issues.

1. You are setting up your map view ([self setupMapView:YES]) in videDidLoad and immediately creating an envelope with self.mapView.spatialReference for zoom function. It may happen that spatialReference of the mapView will be nil as map view may  or may not be loaded. If you want to do this then you should not rely on self.mapView.spatialReference and provide known spatial reference or you should move this code in the mapViewDid load where you know that self.mapView.spatialReference has valid spatial reference as map view successfully loaded.

2. You are observing MapDidEndZooming  notification and in respondToZoomlevelChange you are keeping a copy of self.mapView.visibleArea.envelope without checking whether it???s not-nil/valid envelope or not.

3. Immediately you are checking some condition and if it???s true then you are resetting the map view. Again, you are using the self.mapView.spatialReference  in the AGSGeometryEngine???s  projectGeometry method without verifying whether spatial reference is valid or not. You should use mapView???s properties only when you are confirm whether map is loaded successfully.

Hope this helps!

Regards,
Nimesh

View solution in original post

0 Kudos
7 Replies
NimeshJarecha
Esri Regular Contributor
Okay, let me ask you few questions before suggesting something...

1. Where are you executing this code?
2. Are you waiting for map to load before using the self.mapView.visibleArea.envelope and map's spatial reference in geometry engine?

Regards,
Nimesh
0 Kudos
VasupreeRyser
Emerging Contributor
Thanks for your answer.

1. I execute the code in the didClickAtPoint method. Then in the method I use a segmented control to switch between point search and area seach.
2. No I don't wait, but I don't know how much time I must wait.

Best regards.
0 Kudos
NimeshJarecha
Esri Regular Contributor
Could you please post a sample application so I can have a look?

Regards,
Nimesh
0 Kudos
VasupreeRyser
Emerging Contributor
Sorry for the delay, I was away from my office this week.

Here is the first part of the class for the display of the map.

#import "MapViewController.h"
@implementation MapViewController
...

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];
 self.title = @"MapView";
 
 self.mapView.layerDelegate = self;
 self.mapView.touchDelegate = self;
    self.mapView.calloutDelegate = self;
    
    self.visibleLayers = [NSMutableArray arrayWithObjects:[NSNumber numberWithInt:3],
                                          nil];
    isOSMDisplayed = YES;
    [self setupMapView:YES];
    isAreaSearch = NO;
    
    // zoom to UniNe (WKID 102100) -> OpenStreetMap
 AGSEnvelope *env = [AGSEnvelope envelopeWithXmin:773466.697310 ymin:5941903.815693 xmax:773768.071705 ymax:5942295.602407 spatialReference:self.mapView.spatialReference];
 
    [self.mapView zoomToEnvelope:env animated:YES];
     
 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(respondToZoomlevelChange:) name:@"MapDidEndZooming" object:nil];

    // setup the variables for the ResultsViewController
    entryOrder = [NSArray arrayWithObjects: @"BAT_ADRESSE", @"ETG_DESIGNATION", @"LOC_CODE", @"LOC_SURFACE", @"LOC_TYPE_DESIGNATION", @"LOC_OCCUPANTS", nil];
     
 self.queryTaskContainer = [self initializeQueryTaskContainer];
 
 self.query = [AGSQuery query];
 self.query.returnGeometry = NO;
 self.query.spatialRelationship = AGSSpatialRelationshipIntersects;
 self.query.outFields = entryOrder;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return YES;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; 
}

- (void)viewDidUnload {
}

- (void)dealloc {
 self.mapView = nil;
 self.dynamicLayer = nil;
 self.dynamicLayerView = nil;
 self.graphicsLayer = nil;
 self.queryTaskContainer = nil;
 self.query = nil;
 self.srUniNe = nil;
 self.infoView = nil;
 self.infoLabel = nil;
 self.scaleBarView = nil;
    entryOrder = nil;
    titleText = nil;
 
    [super dealloc];
}

#pragma mark -
- (void) setupMapView:(BOOL)withOSMLayer {
    
    if(withOSMLayer) {
        // if the dynamic layer base is open during the changing of layers, delete during zoom back
        if ([self.visibleLayers containsObject:[NSNumber numberWithInt:5]]){
            [self.visibleLayers removeObject:[NSNumber numberWithInt:5]];
        }
        
        AGSOpenStreetMapLayer *osmLayer = [[[AGSOpenStreetMapLayer alloc]init]autorelease];
        // add the openStreetMap as basemap 
        UIView<AGSLayerView>* lyr = [self.mapView addMapLayer:osmLayer withName:@"tiledLayer"];
 
        lyr.drawDuringPanning = YES;
        lyr.drawDuringZooming = YES;
    }
 // save a reference of the spatial reference from UniNe provided maps
 self.srUniNe = [AGSSpatialReference spatialReferenceWithWKID:kSpatialRefWkidUniNe];
 
    if (self.dynamicLayerInfo != nil) {
        self.dynamicLayer = [[[AGSDynamicMapServiceLayer alloc] initWithMapServiceInfo: self.dynamicLayerInfo] autorelease]; 
    } else {
        AGSDynamicMapServiceLayer *dmLayer = [[[AGSDynamicMapServiceLayer alloc] initWithURL:[NSURL URLWithString:kDynamicMapServiceURL]] autorelease];
        self.dynamicLayer = dmLayer;
        // copy the mapServiceInfo, otherwise the pointer gets lost during the reset of the map
        self.dynamicLayerInfo = [[dmLayer.mapServiceInfo copy] autorelease];
    }
 
    if (withOSMLayer) {
        if ([self.visibleLayers containsObject:[NSNumber numberWithInt:6]]) {
            [self.visibleLayers removeObject:[NSNumber numberWithInt:6]];
        }
        self.dynamicLayer.visibleLayers = [NSArray arrayWithArray:self.visibleLayers];
    } else {
        if (! [self.visibleLayers containsObject:[NSNumber numberWithInt:6]]) {
            [self.visibleLayers addObject:[NSNumber numberWithInt:6]];
        }
        self.dynamicLayer.visibleLayers = [NSArray arrayWithArray:self.visibleLayers];
    }
 
 UIView<AGSLayerView> *dynamicLayerView = [self.mapView addMapLayer:self.dynamicLayer withName:@"dynamicLayer"];
 dynamicLayerView.drawDuringPanning = YES;
 dynamicLayerView.drawDuringZooming = YES;
 self.dynamicLayerView.alpha = 0.7;
 
 // create and add the graphics layer to the map
 self.graphicsLayer = [AGSGraphicsLayer graphicsLayer];
 [self.mapView addMapLayer:self.graphicsLayer withName:@"graphicsLayer"];
}

- (NSDictionary *) initializeQueryTaskContainer {
    NSMutableDictionary *tmpDic = [[NSMutableDictionary new] autorelease];
    
    //the basemap where we zoom, just use for setting the layers in the menu
    AGSQueryTask *qtl = [[[AGSQueryTask alloc] initWithURL:[NSURL URLWithString:kDynamicMapServiceURL]] autorelease];
    qtl.delegate = self;
    [tmpDic setObject:qtl forKey:[NSNumber numberWithInt:5]];
    
    //the difference floors
    AGSQueryTask *qtl0 = [[[AGSQueryTask alloc] initWithURL:[NSURL URLWithString:kDynamicMapLayer0ServiceURL]] autorelease];
    qtl0.delegate = self;
    [tmpDic setObject:qtl0 forKey:[NSNumber numberWithInt:0]];
    
    ...
    return [NSDictionary dictionaryWithDictionary:tmpDic];
}

- (void)respondToZoomlevelChange: (NSNotification*) notification {
 [self.scaleBarView  updateBar:(1 / AGSUnitsToUnits(self.mapView.resolution, self.mapView.units, AGSUnitsMeters))];
    
    AGSEnvelope *actEnv = [[[self.mapView.visibleArea envelope] copy] autorelease]; 
    if (self.mapView.resolution <= 0.6 && isOSMDisplayed) {
        
        [self.mapView reset];
        [self setupMapView:NO];
        isOSMDisplayed = NO;
        
        if (isAreaSearch){
            self.query.returnGeometry = NO;
        } else {
            self.query.returnGeometry = YES;
        }      
        AGSGeometryEngine *ge = [AGSGeometryEngine defaultGeometryEngine];
        [self.mapView zoomToEnvelope:(AGSEnvelope *)[ge projectGeometry:actEnv toSpatialReference:self.mapView.spatialReference] animated:YES];   
    } else if (self.mapView.resolution > 0.6 && ! isOSMDisplayed) {
        
        [self.mapView reset];
        [self setupMapView:YES];
        isOSMDisplayed = YES;    
        self.query.returnGeometry = NO;
        
        AGSGeometryEngine *ge = [AGSGeometryEngine defaultGeometryEngine];
        [self.mapView zoomToEnvelope:(AGSEnvelope *)[ge projectGeometry:actEnv toSpatialReference:self.mapView.spatialReference] animated:YES];
    }
}

#pragma mark -
#pragma mark IBAction methods
-(IBAction) gpsButtonClicked {
 if (self.mapView.gps.enabled) {
        // according to apple, this should work on iOS 5..but somehow it doesn't...
        self.gpsButton.tintColor = [UIColor blackColor];
        [self.mapView.gps stop];
    } else {
        // according to apple, this should work on iOS 5..but somehow it doesn't...
        self.gpsButton.tintColor = [UIColor whiteColor];
        [self.mapView.gps start];
    }
}

-(IBAction) infoButtonClicked {
    
 SettingsMenuViewController *settingsMenuController = [[SettingsMenuViewController alloc] initWithNibName:kXibNameSettingsMenuView bundle:nil];
 
    settingsMenuController.visibleLayers = self.dynamicLayer.visibleLayers;
    settingsMenuController.isOSMDisplayed = isOSMDisplayed;
    settingsMenuController.parentDelegate = self;
    
    [self presentModalViewController:settingsMenuController animated:YES]; 
 
    [settingsMenuController release];    
}

-(IBAction) queryModeValueChanged {
    foundLocation = NO;
    [self.graphicsLayer removeAllGraphics];
    [self.graphicsLayer dataChanged];
    self.mapView.callout.hidden = YES;
    
    if (self.queryModeSwitch.selectedSegmentIndex == 1) {
        self.infoLabel.text = @"area search";
    } else {
        self.infoLabel.text = @"single location search";
    }
}

#pragma mark -
#pragma mark AGSMapViewLayerDelegate
-(void) mapViewDidLoad:(AGSMapView*)mapView {
 
 // startup GPS but not autoPan
 [self.mapView.gps start];
 [self.scaleBarView  updateBar:(1 / AGSUnitsToUnits(self.mapView.resolution, self.mapView.units, AGSUnitsMeters))];
}
0 Kudos
VasupreeRyser
Emerging Contributor
Here is the last part :

#pragma mark AGSMapViewTouchDelegate
- (void) mapView:(AGSMapView *)mapView didClickAtPoint:(CGPoint)screen mapPoint:(AGSPoint *)mappoint graphics:(NSDictionary *)graphics {
    
    AGSEnvelope *visibleEnv = [[[self.mapView.visibleArea envelope] copy] autorelease];
    AGSSpatialReference *spaRef = [[self.srUniNe copy] autorelease];
    
    foundLocation = NO;
    [self.graphicsLayer removeAllGraphics];
 self.infoLabel.text = @"";
 self.clickedPoint = mappoint;
    
    AGSGeometryEngine *ge = [AGSGeometryEngine defaultGeometryEngine];
    AGSPoint *point_srUniNe = (AGSPoint *)[ge projectGeometry:mappoint toSpatialReference:self.srUniNe];
 
    if (self.queryModeSwitch.selectedSegmentIndex == 1) {
        // arcGIS iOS v2.1 Pay attention!
        // visibleArea can be null, when the baseMap isn't fully loaded yet. (http://forums.arcgis.com/threads/44385-iOS-API-2.1-envelope-to-visibleArea-deprication)        
        AGSEnvelope *actualEnv = (AGSEnvelope *)[ge projectGeometry:visibleEnv toSpatialReference:spaRef];
        
        isAreaSearch = YES;
        self.query.returnGeometry = NO;
        
        double xLength = actualEnv.xmax - actualEnv.xmin;
        // size the square according to the height of the device
        if (self.interfaceOrientation == UIDeviceOrientationLandscapeLeft || self.interfaceOrientation == UIDeviceOrientationLandscapeRight) {
            xLength = actualEnv.ymax - actualEnv.ymin;
        }
        
        double xmin = point_srUniNe.x - (xLength / 13);
        double xmax = point_srUniNe.x + (xLength / 13);
        double ymin = point_srUniNe.y - (xLength / 13);
        double ymax = point_srUniNe.y + (xLength / 13);
        
        AGSEnvelope *queryEnv = [AGSEnvelope envelopeWithXmin:xmin ymin:ymin xmax:xmax ymax:ymax spatialReference:self.srUniNe];
        
        self.query.geometry = queryEnv;
        
        AGSSymbol* symbol = [AGSSimpleFillSymbol simpleFillSymbol];
        symbol.color = [UIColor colorWithRed:0 green:0 blue:1 alpha:0.5];
        AGSEnvelope *queryEnv_srOSM = (AGSEnvelope *)[ge projectGeometry:queryEnv toSpatialReference:self.mapView.spatialReference];
        AGSGraphic *envGraphic = [AGSGraphic graphicWithGeometry:queryEnv_srOSM symbol:symbol attributes:[NSMutableDictionary dictionary]  infoTemplateDelegate:nil];
        [self.graphicsLayer addGraphic:envGraphic];
        [self.graphicsLayer dataChanged];

    } else {
        isAreaSearch = NO;
        if (isOSMDisplayed){
            self.query.returnGeometry = NO;
        } else {
            self.query.returnGeometry = YES;
    }
    self.query.geometry = point_srUniNe;
    }
 for (NSNumber *nr in self.dynamicLayer.visibleLayers) {
  if (foundLocation) {
   break;
  }
  [[self.queryTaskContainer objectForKey:nr] executeWithQuery:self.query];
 }
}

#pragma mark - AGSMapViewCalloutDelegate
- (void)mapView:(AGSMapView *)mapView didClickCalloutAccessoryButtonForGraphic: (AGSGraphic *)  graphic {
    
    //The user clicked the callout button, so display the complete set of results
    ResultsViewController *resultsVC = [[ResultsViewController alloc] initWithNibName:kXibNameResultsView bundle:nil];
    resultsVC.entryOrder = entryOrder;
    
    NSMutableDictionary *tmp = [NSMutableDictionary new];
    [tmp setObject:@"Adress" forKey:@"BAT_ADRESSE"];
    ...
    [tmp release];
 
    //set our attributes/results into the results VC
    if ([self.resultsArray count] > 20) {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Too many results" message:[NSString stringWithFormat:@"%d results found.\nDisplay maximum is 20.\nZoom in for less results", [self.resultsArray count]] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alert show];
        [alert release];
        
        NSRange range;
        range.location = 0;
        range.length = 20;
        
        resultsVC.resultsArray = [[NSArray arrayWithArray:self.resultsArray] subarrayWithRange:range];
    } else {
        resultsVC.resultsArray = [NSArray arrayWithArray:self.resultsArray];
    }
    
    [self presentModalViewController:resultsVC animated:YES]; 
 
    [resultsVC release];
}

#pragma mark - AGSQueryTaskDelegate

- (void)queryTask:(AGSQueryTask *)queryTask operation:(NSOperation*)op didExecuteWithFeatureSetResult:(AGSFeatureSet *)featureSet {
    
    if ([featureSet.features count] > 0) {
        if (foundLocation) {
            for (AGSGraphic *graphic in featureSet.features) {
                [self.resultsArray addObject:graphic.attributes];
            }
        } else {
            foundLocation = YES;
         
            AGSSymbol* symbol = [AGSSimpleFillSymbol simpleFillSymbol];
            symbol.color = [UIColor colorWithRed:0 green:0 blue:1 alpha:0.5];
            
            // set the symbol and add it to the graphics layer
            AGSGraphic *resultGraphic = [featureSet.features objectAtIndex:0];
            if (self.resultsArray == nil) {
                self.resultsArray = [[NSMutableArray new] autorelease];
            } else {
                [self.resultsArray removeAllObjects];
            }
            for (AGSGraphic *graphic in featureSet.features) {
                [self.resultsArray addObject:graphic.attributes];
            }
            
            resultGraphic.symbol = symbol;
            [self.graphicsLayer addGraphic:resultGraphic];
            
            if (self.queryModeSwitch.selectedSegmentIndex == 1) {
                
                self.infoLabel.text = @"area search";
                self.mapView.callout.title = @"Details";
                self.mapView.callout.detail = @"Click for more details..";
            } else {
                
               NSString *numero = [[NSDictionary dictionaryWithDictionary:resultGraphic.attributes] valueForKey:@"LOC_CODE"];
               self.infoLabel.text = numero;
                
               self.mapView.callout.title = numero;
               self.mapView.callout.detail = @"Click for more detail..";
            }
          
            [self.mapView showCalloutAtPoint:self.clickedPoint forGraphic:resultGraphic animated:YES];
            [self.graphicsLayer dataChanged];
        }
 }
}

- (void)queryTask:(AGSQueryTask *)queryTask operation:(NSOperation*)op didFailWithError:(NSError *)error {
 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Query Task Failed"
             message:[NSString stringWithFormat:@"Error: %@", [error localizedDescription]] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
 [alert show];
 [alert release];
}

#pragma mark - ContextMenuReturnDelegate
- (void) returnVisibleLayers:(NSArray*)visibleLayers {
        
    self.dynamicLayer.visibleLayers = visibleLayers;
    self.visibleLayers = [NSMutableArray arrayWithArray:visibleLayers];
    
    foundLocation = NO;
    [self.dynamicLayer dataChanged];
    [self.graphicsLayer removeAllGraphics];
    [self.graphicsLayer dataChanged];
    self.infoLabel.text = @"";
 self.clickedPoint = nil;
}

@end


With this class, I have another problem. In the menu of Info button, we can change the visible layers = the different floor of the building, but when I change the layer, the symbol is always displaying even I make [self.graphicsLayer removeAllGraphics] , what is my error ?

Thank you for your help
0 Kudos
NimeshJarecha
Esri Regular Contributor
Okay..let???s look at one issue at a time. You can create new thread for other issue.

By looking at the code???there are few issues.

1. You are setting up your map view ([self setupMapView:YES]) in videDidLoad and immediately creating an envelope with self.mapView.spatialReference for zoom function. It may happen that spatialReference of the mapView will be nil as map view may  or may not be loaded. If you want to do this then you should not rely on self.mapView.spatialReference and provide known spatial reference or you should move this code in the mapViewDid load where you know that self.mapView.spatialReference has valid spatial reference as map view successfully loaded.

2. You are observing MapDidEndZooming  notification and in respondToZoomlevelChange you are keeping a copy of self.mapView.visibleArea.envelope without checking whether it???s not-nil/valid envelope or not.

3. Immediately you are checking some condition and if it???s true then you are resetting the map view. Again, you are using the self.mapView.spatialReference  in the AGSGeometryEngine???s  projectGeometry method without verifying whether spatial reference is valid or not. You should use mapView???s properties only when you are confirm whether map is loaded successfully.

Hope this helps!

Regards,
Nimesh
0 Kudos
VasupreeRyser
Emerging Contributor
Thank you for your reply.

I have make the thing little bit different, because my boss don't want the select area method. But with your information, it's working better in the few test that I made and it's now more comprehensive for me.

Best regards.
0 Kudos