Advertisement
ReFiRnE

testview

Jul 30th, 2015
1,038
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.  *  TestViewController.m
  3.  *  WhirlyGlobeComponentTester
  4.  *
  5.  *  Created by Steve Gifford on 7/23/12.
  6.  *  Copyright 2011-2013 mousebird consulting
  7.  *
  8.  *  Licensed under the Apache License, Version 2.0 (the "License");
  9.  *  you may not use this file except in compliance with the License.
  10.  *  You may obtain a copy of the License at
  11.  *  http://www.apache.org/licenses/LICENSE-2.0
  12.  *
  13.  *  Unless required by applicable law or agreed to in writing, software
  14.  *  distributed under the License is distributed on an "AS IS" BASIS,
  15.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16.  *  See the License for the specific language governing permissions and
  17.  *  limitations under the License.
  18.  *
  19.  */
  20.  
  21. #import <QuartzCore/QuartzCore.h>
  22. #import "TestViewController.h"
  23. #import "AFHTTPRequestOperation.h"
  24. #import "AnimationTest.h"
  25. #import "WeatherShader.h"
  26.  
  27. // Simple representation of locations and name for testing
  28. typedef struct
  29. {
  30.     char name[20];
  31.     float lat,lon;
  32. } LocationInfo;
  33.  
  34. // Some random locations for testing.
  35. // If we've missed your home, it's because we think you suck.
  36. static const int NumLocations = 30;
  37. LocationInfo locations[NumLocations] =
  38. {
  39.     {"Kansas City",39.1, -94.58},
  40.     {"Washington, DC",38.895111,-77.036667},
  41.     {"Manila",14.583333,120.966667},
  42.     {"Moscow",55.75, 37.616667},
  43.     {"London",51.507222, -0.1275},
  44.     {"Caracas",10.5, -66.916667},
  45.     {"Lagos",6.453056, 3.395833},
  46.     {"Sydney",-33.859972, 151.211111},
  47.     {"Seattle",47.609722, -122.333056},
  48.     {"Tokyo",35.689506, 139.6917},
  49.     {"McMurdo Station",-77.85, 166.666667},
  50.     {"Tehran",35.696111, 51.423056},
  51.     {"Santiago",-33.45, -70.666667},
  52.     {"Pretoria",-25.746111, 28.188056},
  53.     {"Perth",-31.952222, 115.858889},
  54.     {"Beijing",39.913889, 116.391667},
  55.     {"New Delhi",28.613889, 77.208889},
  56.     {"San Francisco",37.7793, -122.4192},
  57.     {"Pittsburgh",40.441667, -80},
  58.     {"Freetown",8.484444, -13.234444},
  59.     {"Windhoek",-22.57, 17.083611},
  60.     {"Buenos Aires",-34.6, -58.383333},
  61.     {"Zhengzhou",34.766667, 113.65},
  62.     {"Bergen",60.389444, 5.33},
  63.     {"Glasgow",55.858, -4.259},
  64.     {"Bogota",4.598056, -74.075833},
  65.     {"Haifa",32.816667, 34.983333},
  66.     {"Puerto Williams",-54.933333, -67.616667},
  67.     {"Panama City",8.983333, -79.516667},
  68.     {"Niihau",21.9, -160.166667}
  69. };
  70. typedef struct
  71. {
  72.     char name[20];
  73.     float lat,lon;
  74. } CustLoc;
  75. //CustLoc
  76. static const int CustNumLoc = 5;
  77. CustLoc custLocs[CustNumLoc] =
  78. {
  79.     {"Los Angeles",34.0500, -118.2500},
  80.     {"London",51.507222, -0.1275},
  81.     {"Los Angeles", 34.0500, 118.2500},
  82.     {"Tallinn", 59.4372, 24.7453},
  83.     {"Amsterdam", 59.4372, 24.7453}
  84.  
  85. };
  86.  
  87. // High performance vs. low performance devices
  88. typedef enum {HighPerformance,LowPerformance} PerformanceMode;
  89.  
  90. // Local interface for TestViewController
  91. // We'll hide a few things here
  92. @interface TestViewController ()
  93. {
  94.     // The configuration view comes up when the user taps outside the globe
  95.     ConfigViewController *configViewC;
  96.    
  97.     // Base layer
  98.     NSString *baseLayerName;
  99.     MaplyViewControllerLayer *baseLayer;
  100.    
  101.     // Overlay layers
  102.     NSMutableDictionary *ovlLayers;
  103.        
  104.     // These represent a group of objects we've added to the globe.
  105.     // This is how we track them for removal
  106.     MaplyComponentObject *screenMarkersObj;
  107.     MaplyComponentObject *markersObj;
  108.     MaplyComponentObject *shapeCylObj;
  109.     MaplyComponentObject *shapeSphereObj;
  110.     MaplyComponentObject *greatCircleObj;
  111.     MaplyComponentObject *screenLabelsObj;
  112.     MaplyComponentObject *labelsObj;
  113.     MaplyComponentObject *stickersObj;
  114.     MaplyComponentObject *latLonObj;
  115.     NSArray *sfRoadsObjArray;
  116.     NSArray *vecObjects;
  117.     MaplyComponentObject *megaMarkersObj;
  118.     MaplyComponentObject *autoLabels;
  119.     MaplyActiveObject *animSphere;
  120.     NSMutableDictionary *loftPolyDict;
  121.  
  122.     // A source of elevation data, if we're in that mode
  123.     NSObject<MaplyElevationSourceDelegate> *elevSource;
  124.    
  125.     // The view we're using to track a selected object
  126. //    MaplyViewTracker *selectedViewTrack;
  127.    
  128.     NSDictionary *screenLabelDesc,*labelDesc,*vectorDesc;
  129.    
  130.     // If we're in 3D mode, how far the elevation goes
  131.     int zoomLimit;
  132.     bool requireElev;
  133.     bool imageWaitLoad;
  134.     int maxLayerTiles;
  135.  
  136.     // Label test
  137.     NSTimer *_labelAnimationTimer;
  138.     NSMutableDictionary *_trafficLabels;
  139.    
  140.     // Dashed lines used in wide vector test
  141.     MaplyTexture *dashedLineTex,*filledLineTex;
  142.    
  143.     PerformanceMode perfMode;
  144. }
  145.  
  146. // Change what we're showing based on the Configuration
  147. - (void)changeMapContents;
  148. @end
  149.  
  150. @implementation TestViewController
  151. {
  152.     MapType startupMapType;
  153. }
  154.  
  155. - (id)initWithMapType:(MapType)mapType
  156. {
  157.     self = [super init];
  158.     if (self) {
  159.         startupMapType = mapType;
  160.         ovlLayers = [NSMutableDictionary dictionary];
  161.     }
  162.     return self;
  163. }
  164.  
  165. - (void)dealloc
  166. {
  167.     [NSObject cancelPreviousPerformRequestsWithTarget:self];
  168.    
  169.     // This should release the globe view
  170.     if (baseViewC)
  171.     {
  172.         [baseViewC.view removeFromSuperview];
  173.         [baseViewC removeFromParentViewController];
  174.         baseViewC = nil;
  175.         mapViewC = nil;
  176.         globeViewC = nil;
  177.     }    
  178. }
  179.  
  180. - (void)viewDidLoad
  181. {
  182.     [super viewDidLoad];
  183.    
  184.     // What sort of hardware are we on?
  185.     perfMode = LowPerformance;
  186.     if ([UIScreen mainScreen].scale > 1.0)
  187.     {
  188.         // Retina devices tend to be better, except for
  189.         perfMode = HighPerformance;
  190.     }
  191. #if TARGET_IPHONE_SIMULATOR
  192.     perfMode = HighPerformance;
  193. #endif
  194.    
  195.     loftPolyDict = [NSMutableDictionary dictionary];
  196.    
  197.     // Configuration controller for turning features on and off
  198.     configViewC = [[ConfigViewController alloc] initWithNibName:@"ConfigViewController" bundle:nil];
  199.     configViewC.configOptions = ConfigOptionsAll;
  200.  
  201.     // Create an empty globe or map controller
  202.     zoomLimit = 0;
  203.     requireElev = false;
  204.     maxLayerTiles = 256;
  205.     switch (startupMapType)
  206.     {
  207.         case MaplyGlobe:
  208.         case MaplyGlobeWithElevation:
  209.             globeViewC = [[WhirlyGlobeViewController alloc] init];
  210.             globeViewC.delegate = self;
  211.             baseViewC = globeViewC;
  212.             maxLayerTiles = 128;
  213.             break;
  214.         case Maply3DMap:
  215.             mapViewC = [[MaplyViewController alloc] init];
  216.             mapViewC.doubleTapZoomGesture = true;
  217.             mapViewC.twoFingerTapGesture = true;
  218.             mapViewC.viewWrap = true;
  219.             mapViewC.delegate = self;
  220.             baseViewC = mapViewC;
  221.             break;
  222.         case Maply2DMap:
  223.             mapViewC = [[MaplyViewController alloc] initAsFlatMap];
  224.             mapViewC.viewWrap = true;
  225.             mapViewC.doubleTapZoomGesture = true;
  226.             mapViewC.twoFingerTapGesture = true;
  227.             mapViewC.delegate = self;
  228.             baseViewC = mapViewC;
  229.             configViewC.configOptions = ConfigOptionsFlat;
  230.             break;
  231. //        case MaplyScrollViewMap:
  232. //            break;
  233.         default:
  234.             break;
  235.     }
  236.     [self.view addSubview:baseViewC.view];
  237.     baseViewC.view.frame = self.view.bounds;
  238.     [self addChildViewController:baseViewC];
  239.  
  240.     // Note: Debugging
  241. //    [self labelExercise];
  242.  
  243.     if (perfMode == LowPerformance)
  244.     {
  245.         baseViewC.frameInterval = 3; // 20fps
  246.         baseViewC.threadPerLayer = false;
  247.     } else {
  248.         baseViewC.frameInterval = 2; // 30fps
  249.         baseViewC.threadPerLayer = true;
  250.     }
  251.    
  252.     // Set the background color for the globe
  253.    
  254.     baseViewC.clearColor = [UIColor clearColor];
  255.     globeViewC.view.backgroundColor = [UIColor clearColor];
  256.     UIView* sv = [globeViewC.view.subviews objectAtIndex:0];
  257.     sv.backgroundColor = [UIColor clearColor];
  258.     UIGraphicsBeginImageContext(self.view.frame.size);
  259.     [[UIImage imageNamed:@"kkkkk.png"] drawInRect: self.view.bounds];
  260.     UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
  261.     UIGraphicsEndImageContext();
  262.     globeViewC.view.backgroundColor = [UIColor colorWithPatternImage:image];
  263.        
  264.     if (globeViewC)
  265.     {
  266.         // Start up over San Francisco
  267.         globeViewC.height = 0.8;
  268.         [globeViewC animateToPosition:MaplyCoordinateMakeWithDegrees(-122.4192, 37.7793) time:1.0];
  269.     } else {
  270.         mapViewC.height = 1.0;
  271.         [mapViewC animateToPosition:MaplyCoordinateMakeWithDegrees(-122.4192, 37.7793) time:1.0];
  272.     }
  273.    
  274.  
  275.  
  276.     // For elevation mode, we need to do some other stuff
  277.     if (startupMapType == MaplyGlobeWithElevation)
  278.     {
  279.         // Tilt, so we can see it
  280.         if (globeViewC)
  281.             [globeViewC setTiltMinHeight:0.001 maxHeight:0.04 minTilt:1.21771169 maxTilt:0.0];
  282.         globeViewC.frameInterval = 2;  // 30fps
  283.  
  284.         // An elevation source.  This one just makes up sine waves to get some data in there
  285.         elevSource = [[MaplyElevationDatabase alloc] initWithName:@"world_web_mercator"];
  286.         zoomLimit = elevSource.maxZoom;
  287.         requireElev = true;
  288.         baseViewC.elevDelegate = elevSource;
  289.        
  290.         // Don't forget to turn on the z buffer permanently
  291.         [baseViewC setHints:@{kMaplyRenderHintZBuffer: @(YES)}];
  292.        
  293.         // Turn off most of the options for globe mode
  294.         configViewC.configOptions = ConfigOptionsTerrain;
  295.     }
  296.    
  297.     // Force the view to load so we can get the default switch values
  298.     [configViewC view];
  299.    
  300.     // Maximum number of objects for the layout engine to display
  301. //    [baseViewC setMaxLayoutObjects:1000];
  302.    
  303.     // Bring up things based on what's turned on
  304.     [self performSelector:@selector(changeMapContents) withObject:nil afterDelay:0.0];
  305.    
  306.     // Settings panel]
  307.  
  308.     self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:@selector(showConfig)];
  309.     globeViewC.height = 2.5;
  310.   //  [globeViewC setZoomLimitsMin:(1.5) max:(2.5)];
  311.     globeViewC.autoMoveToTap = false;
  312.     globeViewC.doubleTapZoomGesture = true;
  313.     globeViewC.zoomTapFactor = 2.0;
  314.     globeViewC.zoomTapAnimationDuration = 1.0;
  315.     globeViewC.keepNorthUp = true;
  316.     //[globeViewC animateWithDelegate:globeAnimation time:7.0];
  317.     MaplyLight *light = [[MaplyLight alloc] init];
  318.     light.pos = MaplyCoordinate3dMake(0.75, 0.5, -1.0);
  319.     //light.ambient = [UIColor colorWithRed:252.0 green:0.0 blue:0.0 alpha:1.0];
  320.     light.ambient = [UIColor colorWithRed:0.6 green:0.6 blue:0.6 alpha:1.0];
  321.     light.diffuse = [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:1.0];
  322. //    light.ambient = [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:1.0];
  323. //    light.diffuse = [UIColor colorWithRed:254.0 green:243.0 blue:154.0 alpha:1.0];
  324.     //light.diffuse = [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:1.0];
  325.     light.viewDependent = true;
  326.     [globeViewC addLight:light];
  327.     [self addCustomLocs];
  328.     [self addCust];
  329.  
  330. }
  331.  
  332. // Create a bunch of labels periodically
  333. - (void)labelExercise
  334. {
  335. //     NSTimer *_labelAnimationTimer;
  336. //     NSMutableDictionary *_trafficLabels;
  337.  
  338.     if (mapViewC) {
  339.          _trafficLabels = [NSMutableDictionary dictionary];
  340.  
  341.          _labelAnimationTimer = [NSTimer scheduledTimerWithTimeInterval:1.25 target:self selector:@selector(labelAnimationCallback) userInfo:nil repeats:NO];
  342.      }
  343. }
  344.  
  345. - (void) labelAnimationCallback
  346. {
  347.     NSLog(@"anim callback");
  348.     MaplyComponentObject *trafficLabelCompObj;
  349.  
  350.     NSArray *keys = [_trafficLabels allKeys];
  351.     for (NSObject *key in keys) {
  352.         trafficLabelCompObj = _trafficLabels[key];
  353.         if (!trafficLabelCompObj)
  354.             continue;
  355.         [mapViewC removeObject:trafficLabelCompObj];
  356.         [_trafficLabels removeObjectForKey:key];
  357.     }
  358.  
  359.     NSDictionary *labelsDesc = @{kMaplyMinVis: @(0.0), kMaplyMaxVis: @(1.0), kMaplyFade: @(0.3), kMaplyJustify : @"left", kMaplyDrawPriority: @(50)};
  360.     MaplyScreenLabel *label;
  361.     for (int i=0; i<50; i++) {
  362.          label = [[MaplyScreenLabel alloc] init];
  363.  
  364.          label.loc = MaplyCoordinateMakeWithDegrees(
  365.              -100.0 + 0.25 * ((float)arc4random()/0x100000000),
  366.              40.0 + 0.25 * ((float)arc4random()/0x100000000));
  367.          label.rotation = 0.0;
  368.          label.layoutImportance = 1.0;
  369.          label.text = @"ABCDE";
  370.          label.layoutPlacement = kMaplyLayoutRight;
  371.          label.userObject = nil;
  372.          label.color = [UIColor whiteColor];
  373.  
  374.        
  375.          trafficLabelCompObj = [mapViewC addScreenLabels:[NSArray arrayWithObjects:label, nil] desc:labelsDesc];
  376.          _trafficLabels[@(i)] = trafficLabelCompObj;
  377.        
  378.      }
  379.    
  380.    
  381.      _labelAnimationTimer = [NSTimer scheduledTimerWithTimeInterval:1.25 target:self selector:@selector(labelAnimationCallback) userInfo:nil repeats:NO];
  382. }
  383.  
  384. // Try to fetch the given WMS layer
  385. - (void)fetchWMSLayer:(NSString *)baseURL layer:(NSString *)layerName style:(NSString *)styleName cacheDir:(NSString *)thisCacheDir ovlName:(NSString *)ovlName
  386. {
  387.     NSString *capabilitiesURL = [MaplyWMSCapabilities CapabilitiesURLFor:baseURL];
  388.    
  389.     AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:capabilitiesURL]]];
  390.     operation.responseSerializer = [AFXMLParserResponseSerializer serializer];
  391.     [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
  392.         [self startWMSLayerBaseURL:baseURL xml:responseObject layer:layerName style:styleName cacheDir:thisCacheDir ovlName:ovlName];
  393.     } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
  394.         // Sometimes this works anyway
  395. //        if (![self startWMSLayerBaseURL:baseURL xml:XMLDocument layer:layerName style:styleName cacheDir:thisCacheDir ovlName:ovlName])
  396. //            NSLog(@"Failed to get capabilities from WMS server: %@",capabilitiesURL);
  397.     }];
  398.    
  399.     [operation start];
  400. }
  401.  
  402. // Try to start the layer, given the capabilities
  403. - (bool)startWMSLayerBaseURL:(NSString *)baseURL xml:(DDXMLDocument *)XMLDocument layer:(NSString *)layerName style:(NSString *)styleName cacheDir:(NSString *)thisCacheDir ovlName:(NSString *)ovlName
  404. {
  405.     // See what the service can provide
  406.     MaplyWMSCapabilities *cap = [[MaplyWMSCapabilities alloc] initWithXML:XMLDocument];
  407.     MaplyWMSLayer *layer = [cap findLayer:layerName];
  408.     MaplyCoordinateSystem *coordSys = [layer buildCoordSystem];
  409.     MaplyWMSStyle *style = [layer findStyle:styleName];
  410.     if (!layer)
  411.     {
  412.         NSLog(@"Couldn't find layer %@ in WMS response.",layerName);
  413.         return false;
  414.     } else if (!coordSys)
  415.     {
  416.         NSLog(@"No coordinate system we recognize in WMS response.");
  417.         return false;
  418.     } else if (styleName && !style)
  419.     {
  420.         NSLog(@"No style named %@ in WMS response.",styleName);
  421.         return false;
  422.     }
  423.    
  424.     if (layer && coordSys)
  425.     {
  426.         MaplyWMSTileSource *tileSource = [[MaplyWMSTileSource alloc] initWithBaseURL:baseURL capabilities:cap layer:layer style:style coordSys:coordSys minZoom:0 maxZoom:16 tileSize:256];
  427.         tileSource.cacheDir = thisCacheDir;
  428.         tileSource.transparent = true;
  429.         MaplyQuadImageTilesLayer *imageLayer = [[MaplyQuadImageTilesLayer alloc] initWithCoordSystem:coordSys tileSource:tileSource];
  430.         imageLayer.coverPoles = false;
  431.         imageLayer.handleEdges = true;
  432.         imageLayer.requireElev = requireElev;
  433.         imageLayer.waitLoad = imageWaitLoad;
  434.         [baseViewC addLayer:imageLayer];
  435.        
  436.         if (ovlName)
  437.             ovlLayers[ovlName] = imageLayer;
  438.     }
  439.    
  440.     return true;
  441. }
  442.  
  443. - (void)viewDidUnload
  444. {
  445.     [super viewDidUnload];
  446.    
  447.     // This should release the globe view
  448.     if (baseViewC)
  449.     {
  450.         [baseViewC.view removeFromSuperview];
  451.         [baseViewC removeFromParentViewController];
  452.         baseViewC = nil;
  453.     }
  454. }
  455.  
  456. - (void)viewWillAppear:(BOOL)animated
  457. {
  458.     // This tests heading
  459. //    [self performSelector:@selector(changeHeading:) withObject:@(0.0) afterDelay:1.0];
  460. }
  461.  
  462. - (void)viewWillDisappear:(BOOL)animated
  463. {
  464.     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(changeHeading:) object:nil];
  465. }
  466.  
  467. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
  468. {
  469.     return YES;
  470. }
  471.  
  472. #pragma mark - Data Display
  473.  
  474. // Change the heading every so often
  475. - (void)changeHeading:(NSNumber *)heading
  476. {
  477.     if (globeViewC)
  478.         [globeViewC setHeading:[heading floatValue]];
  479.     else if (mapViewC)
  480.         [mapViewC setHeading:[heading floatValue]];
  481.    
  482.     [self performSelector:@selector(changeHeading:) withObject:@([heading floatValue]+1.0/180.0*M_PI) afterDelay:1.0];
  483. }
  484.  
  485. // Add screen (2D) markers at all our locations
  486. - (void)addScreenMarkers:(LocationInfo *)locations len:(int)len stride:(int)stride offset:(int)offset
  487. {
  488.     CGSize size = CGSizeMake(40, 40);
  489.     UIImage *pinImage = [UIImage imageNamed:@"map_pin"];
  490.    
  491.     NSMutableArray *markers = [NSMutableArray array];
  492.     for (unsigned int ii=offset;ii<len;ii+=stride)
  493.     {
  494.         LocationInfo *location = &locations[ii];
  495.         MaplyScreenMarker *marker = [[MaplyScreenMarker alloc] init];
  496.         marker.image = pinImage;
  497.         marker.loc = MaplyCoordinateMakeWithDegrees(location->lon,location->lat);
  498.         marker.size = size;
  499.         marker.userObject = [NSString stringWithFormat:@"%s",location->name];
  500.         marker.layoutImportance = MAXFLOAT;
  501.         [markers addObject:marker];
  502.     }
  503.    
  504.     screenMarkersObj = [baseViewC addScreenMarkers:markers desc:@{kMaplyMinVis: @(0.0), kMaplyMaxVis: @(1.0), kMaplyFade: @(1.0)}];
  505. }
  506.  
  507. // Add 3D markers
  508.  
  509. - (void)addMarkers:(LocationInfo *)locations len:(int)len stride:(int)stride offset:(int)offset
  510. {
  511.     CGSize size = CGSizeMake(1.05, 1.05);
  512.    // CGSize size = CGSizeMake(0.05, 0.05);
  513.     UIImage *startImage = [UIImage imageNamed:@"pink"];
  514.    
  515.     NSMutableArray *markers = [NSMutableArray array];
  516.     for (unsigned int ii=offset;ii<len;ii+=stride)
  517.     {
  518.         LocationInfo *location = &locations[ii];
  519.         MaplyMarker *marker = [[MaplyMarker alloc] init];
  520.         marker.image = startImage;
  521.         marker.loc = MaplyCoordinateMakeWithDegrees(location->lon,location->lat);
  522.         marker.size = size;
  523.         marker.userObject = [NSString stringWithFormat:@"%s",location->name];
  524.         [markers addObject:marker];
  525.     }
  526.    
  527.     markersObj = [baseViewC addMarkers:markers desc:nil];
  528. }
  529. //Custom Markers
  530. - (void)addCustomLocs
  531. {
  532. //    {"san francisco",37.7793, -122.4192 },
  533. //    {"London",51.507222, -0.1275},
  534.     //34.0500° N, 118.2500
  535.    
  536.     MaplyCoordinate capitals[2];
  537.     capitals[0] = MaplyCoordinateMakeWithDegrees(-118.2500,34.0500 );
  538.     capitals[1] = MaplyCoordinateMakeWithDegrees(-0.1275,51.507222 );
  539. //    capitals[0] = MaplyCoordinateMakeWithDegrees(37.6167, 55.7500);
  540. //    capitals[1] = MaplyCoordinateMakeWithDegrees(0.1275, 51.5072);
  541. //    capitals[2] = MaplyCoordinateMakeWithDegrees(-122.4192, 37.7793);
  542. //    capitals[3] = MaplyCoordinateMakeWithDegrees(24.7453, 59.4372);
  543. //    capitals[4] = MaplyCoordinateMakeWithDegrees(4.9000, 52.3667);
  544.     UIImage *icon = [UIImage imageNamed:@"pink.png"];
  545.     NSMutableArray *markers = [NSMutableArray array];
  546.     for (unsigned int ii=0;ii<2;ii++)
  547.     {
  548.         MaplyMarker *marker = [[MaplyMarker alloc] init];
  549.         marker.image = icon;
  550.         marker.loc = capitals[ii];
  551.         marker.size = CGSizeMake(0.02,0.02);
  552.         marker.userObject = [NSString stringWithFormat:@"Nigga cool place"];
  553.         [markers addObject:marker];
  554.     }
  555.     [baseViewC addMarkers:markers desc:nil];
  556. }
  557.  
  558. - (void)addCust
  559. {
  560.     NSMutableArray *circles = [[NSMutableArray alloc] init];
  561.     for (unsigned int ii=0;ii<1;ii++)
  562.     {
  563.         CustLoc *loc0 = &custLocs[ii];
  564.         CustLoc *loc1 = &custLocs[(ii+1)%2];
  565.         MaplyShapeGreatCircle *greatCircle = [[MaplyShapeGreatCircle alloc] init];
  566.         greatCircle.startPt = MaplyCoordinateMakeWithDegrees(loc0->lon, loc0->lat);
  567.         greatCircle.endPt = MaplyCoordinateMakeWithDegrees(loc1->lon, loc1->lat);
  568.         greatCircle.lineWidth = 6.0;
  569.         // This limits the height based on the length of the great circle
  570.         float angle = [greatCircle calcAngleBetween];
  571.         greatCircle.height = 0.3 * angle / M_PI;
  572.         [circles addObject:greatCircle];
  573.     }
  574.    
  575.     [baseViewC addShapes:circles desc:nil ];
  576. }
  577. // Add spheres
  578. - (void)addGreatCircles:(LocationInfo *)locations len:(int)len stride:(int)stride offset:(int)offset desc:(NSDictionary *)desc
  579. {
  580.     NSMutableArray *circles = [[NSMutableArray alloc] init];
  581.     for (unsigned int ii=offset;ii<len;ii+=stride)
  582.     {
  583.         LocationInfo *loc0 = &locations[ii];
  584.         LocationInfo *loc1 = &locations[(ii+1)%len];
  585.         MaplyShapeGreatCircle *greatCircle = [[MaplyShapeGreatCircle alloc] init];
  586.         greatCircle.startPt = MaplyCoordinateMakeWithDegrees(loc0->lon, loc0->lat);
  587.         greatCircle.endPt = MaplyCoordinateMakeWithDegrees(loc1->lon, loc1->lat);
  588.         greatCircle.lineWidth = 6.0;
  589.         // This limits the height based on the length of the great circle
  590.         float angle = [greatCircle calcAngleBetween];
  591.         greatCircle.height = 0.3 * angle / M_PI;
  592.         [circles addObject:greatCircle];
  593.     }
  594.    
  595.     greatCircleObj = [baseViewC addShapes:circles desc:desc ];
  596. }
  597. -(void)addCMark:(CustLoc *)custLocs len:(int)len stride:(int)stride offset:(int)offset
  598. {
  599.     CGSize size = CGSizeMake(0.10, 0.10);
  600.     UIImage *startImage = [UIImage imageNamed:@"pink"];
  601.     NSMutableArray *markers = [NSMutableArray array];
  602.    
  603.     for (unsigned int ii=offset;ii<len;ii+=stride)
  604.     {
  605.         CustLoc *loc = &custLocs[ii];
  606.         MaplyMarker *marker = [[MaplyMarker alloc] init];
  607.         marker.image = startImage;
  608.         marker.loc = MaplyCoordinateMakeWithDegrees(loc->lon, loc->lat);
  609.         marker.size = size;
  610.         marker.userObject = [NSString stringWithFormat:@"%s",loc->name];
  611.         [markers addObject:marker];
  612.     }
  613.     markersObj = [baseViewC addMarkers:markers desc:nil];
  614. }
  615. // Add screen (2D) labels
  616. - (void)addScreenLabels:(LocationInfo *)locations len:(int)len stride:(int)stride offset:(int)offset
  617. {
  618.     NSMutableArray *labels = [NSMutableArray array];
  619.     for (unsigned int ii=offset;ii<len;ii+=stride)
  620.     {
  621.         LocationInfo *location = &locations[ii];
  622.         MaplyScreenLabel *label = [[MaplyScreenLabel alloc] init];
  623.         label.loc = MaplyCoordinateMakeWithDegrees(location->lon,location->lat);
  624.         label.text = [NSString stringWithFormat:@"%s",location->name];
  625.         label.layoutImportance = 2.0;
  626.         label.userObject = [NSString stringWithFormat:@"%s",location->name];
  627.         [labels addObject:label];
  628.     }
  629.    
  630.     screenLabelsObj = [baseViewC addScreenLabels:labels desc:screenLabelDesc];
  631. }
  632.  
  633. // Add 3D labels
  634. - (void)addLabels:(LocationInfo *)locations len:(int)len stride:(int)stride offset:(int)offset
  635. {
  636.     CGSize size = CGSizeMake(0, 0.05);
  637.    
  638.     NSMutableArray *labels = [NSMutableArray array];
  639.     for (unsigned int ii=offset;ii<len;ii+=stride)
  640.     {
  641.         LocationInfo *location = &locations[ii];
  642.         MaplyLabel *label = [[MaplyLabel alloc] init];
  643.         label.loc = MaplyCoordinateMakeWithDegrees(location->lon,location->lat);
  644.         label.size = size;
  645.         label.text = [NSString stringWithFormat:@"%s",location->name];
  646.         label.userObject = [NSString stringWithFormat:@"%s",location->name];
  647.         [labels addObject:label];
  648.     }
  649.    
  650.     labelsObj = [baseViewC addLabels:labels desc:labelDesc];
  651. }
  652.  
  653. // Add cylinders
  654. - (void)addShapeCylinders:(LocationInfo *)locations len:(int)len stride:(int)stride offset:(int)offset desc:(NSDictionary *)desc
  655. {
  656.     NSMutableArray *cyls = [[NSMutableArray alloc] init];
  657.     for (unsigned int ii=offset;ii<len;ii+=stride)
  658.     {
  659.         LocationInfo *location = &locations[ii];
  660.         MaplyShapeCylinder *cyl = [[MaplyShapeCylinder alloc] init];
  661.         cyl.baseCenter = MaplyCoordinateMakeWithDegrees(location->lon, location->lat);
  662.         cyl.radius = 0.01;
  663.         cyl.height = 0.06;
  664.         cyl.selectable = true;
  665.         [cyls addObject:cyl];
  666.     }
  667.    
  668.     shapeCylObj = [baseViewC addShapes:cyls desc:desc];
  669. }
  670.  
  671. // Add spheres
  672. - (void)addShapeSpheres:(LocationInfo *)locations len:(int)len stride:(int)stride offset:(int)offset desc:(NSDictionary *)desc
  673. {
  674.     NSMutableArray *spheres = [[NSMutableArray alloc] init];
  675.     for (unsigned int ii=offset;ii<len;ii+=stride)
  676.     {
  677.         LocationInfo *location = &locations[ii];
  678.         MaplyShapeSphere *sphere = [[MaplyShapeSphere alloc] init];
  679.         sphere.center = MaplyCoordinateMakeWithDegrees(location->lon, location->lat);
  680.         sphere.radius = 0.04;
  681.         sphere.selectable = true;
  682.         [spheres addObject:sphere];
  683.     }
  684.  
  685.     shapeSphereObj = [baseViewC addShapes:spheres desc:desc];
  686. }
  687.  
  688.  
  689.  
  690. - (void)addLinesLon:(float)lonDelta lat:(float)latDelta color:(UIColor *)color
  691. {
  692.     NSMutableArray *vectors = [[NSMutableArray alloc] init];
  693.     NSDictionary *desc = @{kMaplyColor: color, kMaplySubdivType: kMaplySubdivSimple, kMaplySubdivEpsilon: @(0.001), kMaplyVecWidth: @(4.0)};
  694.     // Longitude lines
  695.     for (float lon = -180;lon < 180;lon += lonDelta)
  696.     {
  697.         MaplyCoordinate coords[3];
  698.         coords[0] = MaplyCoordinateMakeWithDegrees(lon, -90);
  699.         coords[1] = MaplyCoordinateMakeWithDegrees(lon, 0);
  700.         coords[2] = MaplyCoordinateMakeWithDegrees(lon, +90);
  701.         MaplyVectorObject *vec = [[MaplyVectorObject alloc] initWithLineString:coords numCoords:3 attributes:nil];
  702.         [vectors addObject:vec];
  703.     }
  704.     // Latitude lines
  705.     for (float lat = -90;lat < 90;lat += latDelta)
  706.     {
  707.         MaplyCoordinate coords[5];
  708.         coords[0] = MaplyCoordinateMakeWithDegrees(-180, lat);
  709.         coords[1] = MaplyCoordinateMakeWithDegrees(-90, lat);
  710.         coords[2] = MaplyCoordinateMakeWithDegrees(0, lat);
  711.         coords[3] = MaplyCoordinateMakeWithDegrees(90, lat);
  712.         coords[4] = MaplyCoordinateMakeWithDegrees(+180, lat);
  713.         MaplyVectorObject *vec = [[MaplyVectorObject alloc] initWithLineString:coords numCoords:5 attributes:nil];
  714.         [vectors addObject:vec];
  715.     }
  716.    
  717.     latLonObj = [baseViewC addVectors:vectors desc:desc];
  718. }
  719.  
  720. - (NSArray *)addWideVectors:(MaplyVectorObject *)vecObj
  721. {
  722.     UIColor *color = [UIColor blueColor];
  723.     float fade = 0.25;
  724.     MaplyComponentObject *lines = [baseViewC addVectors:@[vecObj] desc:@{kMaplyColor: color,
  725.                                                                          kMaplyVecWidth: @(4.0),
  726.                                                                          kMaplyFade: @(fade),
  727.                                                                          kMaplyVecCentered: @(true),
  728.                                                                          kMaplyMaxVis: @(10.0),
  729.                                                                          kMaplyMinVis: @(0.00032424763776361942)
  730.                                                                          }];
  731.    
  732.     MaplyComponentObject *screenLines = [baseViewC addWideVectors:@[vecObj] desc:@{kMaplyColor: [UIColor redColor],
  733.                                                                                    kMaplyFade: @(fade),
  734.                                                                                    kMaplyVecWidth: @(4.0),
  735.                                                                                    kMaplyVecTexture: dashedLineTex,
  736.                                                                                    kMaplyWideVecCoordType: kMaplyWideVecCoordTypeScreen,
  737.                                                                                    kMaplyWideVecJoinType: kMaplyWideVecMiterJoin,
  738.                                                                                    kMaplyWideVecMiterLimit: @(1.01),
  739.                                                                                    kMaplyWideVecTexRepeatLen: @(8),
  740.                                                                                    kMaplyMaxVis: @(0.00032424763776361942),
  741.                                                                                    kMaplyMinVis: @(0.00011049506429117173)
  742.                                                                                    }];
  743.     MaplyComponentObject *realLines = [baseViewC addWideVectors:@[vecObj] desc:@{kMaplyColor: color,
  744.                                                                                  kMaplyFade: @(fade),
  745.                                                                                  kMaplyVecTexture: dashedLineTex,
  746.                                                                                  // 8m in display coordinates
  747.                                                                                  kMaplyVecWidth: @(10.0/6371000),
  748.                                                                                  kMaplyWideVecCoordType: kMaplyWideVecCoordTypeReal,
  749.                                                                                  kMaplyWideVecJoinType: kMaplyWideVecMiterJoin,
  750.                                                                                  kMaplyWideVecMiterLimit: @(1.01),
  751.                                                                                  // Repeat every 10m
  752.                                                                                  kMaplyWideVecTexRepeatLen: @(10/6371000.f),
  753.                                                                                  kMaplyMaxVis: @(0.00011049506429117173),
  754.                                                                                  kMaplyMinVis: @(0.0)
  755.                                                                                  }];
  756.    
  757.     // Look for some labels
  758.     MaplyComponentObject *labelObj = nil;
  759.     NSMutableArray *labels = [NSMutableArray array];
  760.     for (MaplyVectorObject *road in [vecObj splitVectors])
  761.     {
  762.         MaplyCoordinate middle;
  763.         double rot;
  764.         // Note: We should get this from the view controller
  765.         MaplyCoordinateSystem *coordSys = [[MaplySphericalMercator alloc] initWebStandard];
  766.         [road linearMiddle:&middle rot:&rot displayCoordSys:coordSys];
  767.         NSDictionary *attrs = road.attributes;
  768.        
  769.         NSString *name = attrs[@"FULLNAME"];
  770.        
  771.         if (name)
  772.         {
  773.             MaplyScreenLabel *label = [[MaplyScreenLabel alloc] init];
  774.             label.loc = middle;
  775.             label.text = name;
  776.             label.layoutImportance = 1.0;
  777.             label.rotation = rot + M_PI/2.0;
  778.             label.keepUpright = true;
  779.             label.layoutImportance = kMaplyLayoutBelow;
  780.             [labels addObject:label];
  781.         }
  782.     }
  783.     labelObj = [baseViewC addScreenLabels:labels desc:
  784.                 @{kMaplyTextOutlineSize: @(1.0),
  785.                   kMaplyTextOutlineColor: [UIColor blackColor],
  786.                   kMaplyFont: [UIFont systemFontOfSize:18.0]
  787.                   }];
  788.    
  789.     return @[lines,screenLines,realLines,labelObj];
  790. }
  791.  
  792. - (void)addShapeFile:(NSString *)shapeFileName
  793. {
  794.     // Make the dashed line if it isn't already there
  795.     if (!dashedLineTex)
  796.     {
  797.         MaplyLinearTextureBuilder *lineTexBuilder = [[MaplyLinearTextureBuilder alloc] initWithSize:CGSizeMake(4,8)];
  798.         [lineTexBuilder setPattern:@[@(4),@(4)]];
  799.         lineTexBuilder.opacityFunc = MaplyOpacitySin2;
  800.         UIImage *dashedLineImage = [lineTexBuilder makeImage];
  801.         dashedLineTex = [baseViewC addTexture:dashedLineImage imageFormat:MaplyImageIntRGBA wrapFlags:MaplyImageWrapY mode:MaplyThreadAny];
  802.     }
  803.     if (!filledLineTex)
  804.     {
  805.         MaplyLinearTextureBuilder *lineTexBuilder = [[MaplyLinearTextureBuilder alloc] initWithSize:CGSizeMake(8,32)];
  806.         [lineTexBuilder setPattern:@[@(32)]];
  807.         lineTexBuilder.opacityFunc = MaplyOpacitySin2;
  808.         UIImage *lineImage = [lineTexBuilder makeImage];
  809.         filledLineTex = [baseViewC addTexture:lineImage imageFormat:MaplyImageIntRGBA wrapFlags:MaplyImageWrapY mode:MaplyThreadAny];
  810.     }
  811.  
  812.     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
  813.     ^{
  814.         // Add the vectors at three different levels
  815.         MaplyVectorDatabase *vecDb = [MaplyVectorDatabase vectorDatabaseWithShape:shapeFileName];
  816.         if (vecDb)
  817.         {
  818.             MaplyVectorObject *vecObj = [vecDb fetchAllVectors];
  819.             if (vecObj)
  820.             {
  821.                 sfRoadsObjArray = [self addWideVectors:vecObj];
  822.             }
  823.         }
  824.     });
  825. }
  826.  
  827. - (void)addStickers:(LocationInfo *)locations len:(int)len stride:(int)stride offset:(int)offset desc:(NSDictionary *)desc
  828. {
  829.     UIImage *startImage = [UIImage imageNamed:@"Smiley_Face_Avatar_by_PixelTwist"];
  830.    
  831.     NSMutableArray *stickers = [NSMutableArray array];
  832.     for (unsigned int ii=offset;ii<len;ii+=stride)
  833.     {
  834.         LocationInfo *location = &locations[ii];
  835.         MaplySticker *sticker = [[MaplySticker alloc] init];
  836.         // Stickers are sized in geographic (because they're for KML ground overlays).  Bleah.
  837.         sticker.ll = MaplyCoordinateMakeWithDegrees(location->lon, location->lat);
  838.         sticker.ur = MaplyCoordinateMakeWithDegrees(location->lon+10.0, location->lat+10.0);
  839.         sticker.image = startImage;
  840.         // And a random rotation
  841. //        sticker.rotation = 2*M_PI * drand48();
  842.         [stickers addObject:sticker];
  843.     }
  844.    
  845.     stickersObj = [baseViewC addStickers:stickers desc:desc];
  846. }
  847.  
  848. // Add country outlines.  Pass in the names of the geoJSON files
  849. - (void)addCountries:(NSArray *)names stride:(int)stride
  850. {
  851.     // Parsing the JSON can take a while, so let's hand that over to another queue
  852.     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
  853.          ^{
  854.              NSMutableArray *locVecObjects = [NSMutableArray array];
  855.              NSMutableArray *locAutoLabels = [NSMutableArray array];
  856.              
  857.              int ii = 0;
  858.              for (NSString *name in names)
  859.              {
  860.                  if (ii % stride == 0)
  861.                  {
  862.                      NSString *fileName = [[NSBundle mainBundle] pathForResource:name ofType:@"geojson"];
  863.                      if (fileName)
  864.                      {
  865.                          NSData *jsonData = [NSData dataWithContentsOfFile:fileName];
  866.                          if (jsonData)
  867.                          {
  868.                              MaplyVectorObject *wgVecObj = [MaplyVectorObject VectorObjectFromGeoJSON:jsonData];
  869.                              NSString *vecName = [[wgVecObj attributes] objectForKey:@"ADMIN"];
  870.                              wgVecObj.userObject = vecName;
  871.                              MaplyComponentObject *compObj = [baseViewC addVectors:[NSArray arrayWithObject:wgVecObj] desc:vectorDesc];
  872.                              MaplyScreenLabel *screenLabel = [[MaplyScreenLabel alloc] init];
  873.                              // Add a label right in the middle
  874.                              MaplyCoordinate center;
  875.                              if ([wgVecObj centroid:&center])
  876.                              {
  877.                                  screenLabel.loc = center;
  878.                                  screenLabel.layoutImportance = 1.0;
  879.                                  screenLabel.text = vecName;
  880.                                  screenLabel.userObject = screenLabel.text;
  881.                                  screenLabel.selectable = true;
  882.                                  if (screenLabel.text)
  883.                                      [locAutoLabels addObject:screenLabel];
  884.                              }
  885.                              if (compObj)
  886.                                  [locVecObjects addObject:compObj];
  887.                          }
  888.                      }
  889.                  }
  890.                  ii++;
  891.              }
  892.              
  893.              // Keep track of the created objects
  894.              // Note: You could lose track of the objects if you turn the countries on/off quickly
  895.              dispatch_async(dispatch_get_main_queue(),
  896.                             ^{
  897.                                 // Toss in all the labels at once, more efficient
  898.                                 MaplyComponentObject *autoLabelObj = [baseViewC addScreenLabels:locAutoLabels desc:
  899.                                                                       @{kMaplyTextColor: [UIColor colorWithRed:0.85 green:0.85 blue:0.85 alpha:1.0],
  900.                                                                             kMaplyFont: [UIFont systemFontOfSize:24.0],
  901.                                                                          kMaplyTextOutlineColor: [UIColor blackColor],
  902.                                                                           kMaplyTextOutlineSize: @(1.0)
  903. //                                                                               kMaplyShadowSize: @(1.0)
  904.                                                                       } mode:MaplyThreadAny];
  905.  
  906.                                 vecObjects = locVecObjects;
  907.                                 autoLabels = autoLabelObj;
  908.                             });
  909.  
  910.          }
  911.     );
  912. }
  913.  
  914. // Number of markers to whip up for the large test case
  915. static const int NumMegaMarkers = 40000;
  916.  
  917. // Make up a large number of markers and add them
  918. - (void)addMegaMarkers
  919. {
  920.     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
  921.        ^{
  922.            UIImage *image = [UIImage imageNamed:@"map_pin.png"];
  923.            NSMutableArray *markers = [NSMutableArray array];
  924.            for (unsigned int ii=0;ii<NumMegaMarkers;ii++)
  925.            {
  926.                MaplyScreenMarker *marker = [[MaplyScreenMarker alloc] init];
  927.                marker.image = image;
  928.                marker.size = CGSizeMake(40,40);
  929.                marker.loc = MaplyCoordinateMakeWithDegrees(drand48()*360-180, drand48()*140-70);
  930.                marker.layoutImportance = drand48();
  931.                [markers addObject:marker];
  932.            }
  933.            dispatch_async(dispatch_get_main_queue(),
  934.                           ^{
  935.                               megaMarkersObj = [baseViewC addScreenMarkers:markers desc:nil];
  936.                           }
  937.                           );
  938.        }
  939.     );
  940. }
  941.  
  942. // Create an animated sphere
  943. - (void)addAnimatedSphere
  944. {
  945.     animSphere = [[AnimatedSphere alloc] initWithPeriod:0.3 radius:0.01 color:[UIColor orangeColor] viewC:baseViewC];
  946.     [baseViewC addActiveObject:animSphere];
  947. }
  948.  
  949. // Set this to reload the base layer ever so often.  Purely for testing
  950. //#define RELOADTEST 1
  951.  
  952. // Set up the base layer depending on what they've picked.
  953. // Also tear down an old one
  954. - (void)setupBaseLayer:(NSDictionary *)baseSettings
  955. {
  956.     // Figure out which one we're supposed to display
  957.     NSString *newBaseLayerName = nil;
  958.     for (NSString *key in [baseSettings allKeys])
  959.     {
  960.         if ([baseSettings[key] boolValue])
  961.         {
  962.             newBaseLayerName = key;
  963.             break;
  964.         }
  965.     }
  966.    
  967.     // Didn't change
  968.     if (![newBaseLayerName compare:baseLayerName])
  969.         return;
  970.    
  971.     // Tear down the old layer
  972.     if (baseLayer)
  973.     {
  974.         baseLayerName = nil;
  975.         [baseViewC removeLayer:baseLayer];
  976.         baseLayer = nil;
  977.     }
  978.     baseLayerName = newBaseLayerName;
  979.    
  980.     // For network paging layers, where we'll store temp files
  981.     NSString *cacheDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)  objectAtIndex:0];
  982.    
  983.     // We'll pick default colors for the labels
  984.     UIColor *screenLabelColor = [UIColor whiteColor];
  985.     UIColor *screenLabelBackColor = [UIColor clearColor];
  986.     UIColor *labelColor = [UIColor whiteColor];
  987.     UIColor *labelBackColor = [UIColor clearColor];
  988.     // And for the vectors to stand out
  989.     UIColor *vecColor = [UIColor whiteColor];
  990.     float vecWidth = 4.0;
  991.    
  992.     NSString *jsonTileSpec = nil;
  993.     NSString *thisCacheDir = nil;
  994.    
  995. #ifdef RELOADTEST
  996.     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(reloadLayer:) object:nil];
  997. #endif
  998.    
  999.     if (![baseLayerName compare:kMaplyTestBlank])
  1000.     {
  1001.         // Nothing to see here
  1002.     }
  1003.     if (![baseLayerName compare:kMaplyTestGeographyClass])
  1004.     {
  1005.         self.title = @"Geography Class - MBTiles Local";
  1006.         // This is the Geography Class MBTiles data set from MapBox
  1007.         MaplyMBTileSource *tileSource = [[MaplyMBTileSource alloc] initWithMBTiles:@"boonband"];
  1008.         MaplyQuadImageTilesLayer *layer = [[MaplyQuadImageTilesLayer alloc] initWithCoordSystem:tileSource.coordSys tileSource:tileSource];
  1009.         baseLayer = layer;
  1010.         layer.handleEdges = (globeViewC != nil);
  1011.         layer.coverPoles = (globeViewC != nil);
  1012.         layer.requireElev = requireElev;
  1013.         layer.waitLoad = imageWaitLoad;
  1014.         layer.drawPriority = 0;
  1015.         layer.singleLevelLoading = (startupMapType == Maply2DMap);
  1016.         [baseViewC addLayer:layer];
  1017.        
  1018.         labelColor = [UIColor blackColor];
  1019.         labelBackColor = [UIColor whiteColor];
  1020.         vecColor = [UIColor colorWithRed:0.4 green:0.4 blue:0.4 alpha:1.0];
  1021.        
  1022. #ifdef RELOADTEST
  1023.         [self performSelector:@selector(reloadLayer:) withObject:nil afterDelay:10.0];
  1024. #endif
  1025.  
  1026.     } else if (![baseLayerName compare:kMaplyTestBlueMarble])
  1027.     {
  1028.         self.title = @"Blue Marble Single Res";
  1029.         if (globeViewC)
  1030.         {
  1031.             // This is the static image set, included with the app, built with ImageChopper
  1032.             WGViewControllerLayer *layer = [globeViewC addSphericalEarthLayerWithImageSet:@"lowres_wtb_info"];
  1033.             baseLayer = (MaplyViewControllerLayer *)layer;
  1034.             baseLayer.drawPriority = 0;
  1035.             screenLabelColor = [UIColor whiteColor];
  1036.             screenLabelBackColor = [UIColor whiteColor];
  1037.             labelColor = [UIColor blackColor];
  1038.             labelBackColor = [UIColor whiteColor];
  1039.             vecColor = [UIColor whiteColor];
  1040.             vecWidth = 4.0;
  1041.         }        
  1042.     } else if (![baseLayerName compare:kMaplyTestStamenWatercolor])
  1043.     {
  1044.         self.title = @"Stamen Water Color - Remote";
  1045.         // These are the Stamen Watercolor tiles.
  1046.         // They're beautiful, but the server isn't so great.
  1047.         thisCacheDir = [NSString stringWithFormat:@"%@/stamentiles/",cacheDir];
  1048.         int maxZoom = 10;
  1049.         if (zoomLimit != 0 && zoomLimit < maxZoom)
  1050.             maxZoom = zoomLimit;
  1051.         MaplyRemoteTileSource *tileSource = [[MaplyRemoteTileSource alloc] initWithBaseURL:@"http://tile.stamen.com/watercolor/" ext:@"png" minZoom:0 maxZoom:maxZoom];
  1052.         tileSource.cacheDir = thisCacheDir;
  1053.         MaplyQuadImageTilesLayer *layer = [[MaplyQuadImageTilesLayer alloc] initWithCoordSystem:tileSource.coordSys tileSource:tileSource];
  1054.         layer.handleEdges = true;
  1055.         layer.requireElev = requireElev;
  1056.         [baseViewC addLayer:layer];
  1057.         layer.drawPriority = 0;
  1058.         layer.waitLoad = imageWaitLoad;
  1059.         layer.singleLevelLoading = (startupMapType == Maply2DMap);
  1060.         baseLayer = layer;
  1061.         screenLabelColor = [UIColor whiteColor];
  1062.         screenLabelBackColor = [UIColor whiteColor];
  1063.         labelColor = [UIColor blackColor];
  1064.         labelBackColor = [UIColor blackColor];
  1065.         vecColor = [UIColor grayColor];
  1066.         vecWidth = 4.0;
  1067.     } else if (![baseLayerName compare:kMaplyTestOSM])
  1068.     {
  1069.         self.title = @"OpenStreetMap - Remote";
  1070.         // This points to the OpenStreetMap tile set hosted by MapQuest (I think)
  1071.         thisCacheDir = [NSString stringWithFormat:@"%@/osmtiles/",cacheDir];
  1072.         int maxZoom = 18;
  1073.         if (zoomLimit != 0 && zoomLimit < maxZoom)
  1074.             maxZoom = zoomLimit;
  1075.         MaplyRemoteTileSource *tileSource = [[MaplyRemoteTileSource alloc] initWithBaseURL:@"http://otile1.mqcdn.com/tiles/1.0.0/osm/" ext:@"png" minZoom:0 maxZoom:maxZoom];
  1076.         tileSource.cacheDir = thisCacheDir;
  1077.         MaplyQuadImageTilesLayer *layer = [[MaplyQuadImageTilesLayer alloc] initWithCoordSystem:tileSource.coordSys tileSource:tileSource];
  1078.         layer.drawPriority = 0;
  1079.         layer.handleEdges = true;
  1080.         layer.requireElev = requireElev;
  1081.         layer.waitLoad = imageWaitLoad;
  1082.         layer.maxTiles = maxLayerTiles;
  1083.         layer.singleLevelLoading = (startupMapType == Maply2DMap);
  1084.         [baseViewC addLayer:layer];
  1085.         layer.drawPriority = 0;
  1086.         baseLayer = layer;
  1087.         screenLabelColor = [UIColor whiteColor];
  1088.         screenLabelBackColor = [UIColor whiteColor];
  1089.         labelColor = [UIColor blackColor];
  1090.         labelBackColor = [UIColor whiteColor];
  1091.         vecColor = [UIColor blackColor];
  1092.         vecWidth = 4.0;
  1093.     } else if (![baseLayerName compare:kMaplyTestMapBoxSat])
  1094.     {
  1095.         self.title = @"MapBox test";
  1096.         jsonTileSpec = @"https://a.tiles.mapbox.com/v4/gkoinc.380af04b/features.json?access_token=pk.eyJ1IjoiZ2tvaW5jIiwiYSI6ImQ5MzM2NGI2NDVhODExODlkYzlhODRhZTgwNmUyYjA5In0.5EOm1WXvyyMfQRjwsi4IcA";
  1097.         thisCacheDir = [NSString stringWithFormat:@"%@/mbtilessat1/",cacheDir];
  1098.         screenLabelColor = [UIColor whiteColor];
  1099.         screenLabelBackColor = [UIColor whiteColor];
  1100.         labelColor = [UIColor blackColor];
  1101.         labelBackColor = [UIColor whiteColor];
  1102.         vecColor = [UIColor blackColor];
  1103.         vecWidth = 4.0;
  1104.     } else if (![baseLayerName compare:kMaplyTestMapBoxTerrain])
  1105.     {
  1106.         self.title = @"MapBox Tiles Terrain - Remote";
  1107.         jsonTileSpec = @"http://a.tiles.mapbox.com/v3/examples.map-zq0f1vuc.json";
  1108.         thisCacheDir = [NSString stringWithFormat:@"%@/mbtilesterrain1/",cacheDir];
  1109.         screenLabelColor = [UIColor whiteColor];
  1110.         screenLabelBackColor = [UIColor whiteColor];
  1111.         labelColor = [UIColor blackColor];
  1112.         labelBackColor = [UIColor whiteColor];
  1113.         vecColor = [UIColor blackColor];
  1114.         vecWidth = 4.0;
  1115.     } else if (![baseLayerName compare:kMaplyTestMapBoxRegular])
  1116.     {
  1117.         self.title = @"MapBox Tiles Regular - Remote";
  1118.         jsonTileSpec = @"http://a.tiles.mapbox.com/v3/examples.map-zswgei2n.json";
  1119.         thisCacheDir = [NSString stringWithFormat:@"%@/mbtilesregular1/",cacheDir];
  1120.         screenLabelColor = [UIColor whiteColor];
  1121.         screenLabelBackColor = [UIColor whiteColor];
  1122.         labelColor = [UIColor blackColor];
  1123.         labelBackColor = [UIColor whiteColor];
  1124.         vecColor = [UIColor blackColor];
  1125.         vecWidth = 4.0;
  1126.     } else if (![baseLayerName compare:kMaplyTestQuadTest])
  1127.     {
  1128.         self.title = @"Quad Paging Test Layer";
  1129.         screenLabelColor = [UIColor whiteColor];
  1130.         screenLabelBackColor = [UIColor whiteColor];
  1131.         labelColor = [UIColor blackColor];
  1132.         labelBackColor = [UIColor whiteColor];
  1133.         vecColor = [UIColor blackColor];
  1134.         vecWidth = 4.0;
  1135.         MaplyAnimationTestTileSource *tileSource = [[MaplyAnimationTestTileSource alloc] initWithCoordSys:[[MaplySphericalMercator alloc] initWebStandard] minZoom:0 maxZoom:21 depth:1];
  1136.         tileSource.pixelsPerSide = 128;
  1137.         MaplyQuadImageTilesLayer *layer = [[MaplyQuadImageTilesLayer alloc] initWithCoordSystem:tileSource.coordSys tileSource:tileSource];
  1138.         layer.waitLoad = imageWaitLoad;
  1139.         layer.requireElev = requireElev;
  1140.         layer.maxTiles = 512;
  1141.         layer.singleLevelLoading = (startupMapType == Maply2DMap);
  1142.         layer.color = [UIColor colorWithWhite:1.0 alpha:0.75];
  1143.         [baseViewC addLayer:layer];
  1144.         layer.drawPriority = 0;
  1145.         baseLayer = layer;
  1146.     } else if (![baseLayerName compare:kMaplyTestQuadVectorTest])
  1147.     {
  1148.         self.title = @"Quad Paging Test Layer";
  1149.         screenLabelColor = [UIColor whiteColor];
  1150.         screenLabelBackColor = [UIColor whiteColor];
  1151.         labelColor = [UIColor blackColor];
  1152.         labelBackColor = [UIColor whiteColor];
  1153.         vecColor = [UIColor blackColor];
  1154.         vecWidth = 4.0;
  1155.         MaplyPagingVectorTestTileSource *tileSource = [[MaplyPagingVectorTestTileSource alloc] initWithCoordSys:[[MaplySphericalMercator alloc] initWebStandard] minZoom:0 maxZoom:10];
  1156.         MaplyQuadPagingLayer *layer = [[MaplyQuadPagingLayer alloc] initWithCoordSystem:tileSource.coordSys delegate:tileSource];
  1157.         layer.importance = 128*128;
  1158.         layer.singleLevelLoading = (startupMapType == Maply2DMap);
  1159.         [baseViewC addLayer:layer];
  1160.         layer.drawPriority = 0;
  1161.         baseLayer = layer;
  1162.     } else if (![baseLayerName compare:kMaplyTestQuadTestAnimate])
  1163.     {
  1164.         self.title = @"Quad Paging Test Layer (animated)";
  1165.         screenLabelColor = [UIColor whiteColor];
  1166.         screenLabelBackColor = [UIColor whiteColor];
  1167.         labelColor = [UIColor blackColor];
  1168.         labelBackColor = [UIColor whiteColor];
  1169.         vecColor = [UIColor blackColor];
  1170.         vecWidth = 4.0;
  1171.         MaplyAnimationTestTileSource *tileSource = [[MaplyAnimationTestTileSource alloc] initWithCoordSys:[[MaplySphericalMercator alloc] initWebStandard] minZoom:0 maxZoom:17 depth:4];
  1172.         tileSource.pixelsPerSide = 128;
  1173.         MaplyQuadImageTilesLayer *layer = [[MaplyQuadImageTilesLayer alloc] initWithCoordSystem:tileSource.coordSys tileSource:tileSource];
  1174.         layer.waitLoad = imageWaitLoad;
  1175.         layer.requireElev = requireElev;
  1176.         layer.imageDepth = 4;
  1177.         // We'll cycle through at 1s per layer
  1178.         layer.animationPeriod = 4.0;
  1179.         layer.singleLevelLoading = (startupMapType == Maply2DMap);
  1180.         [baseViewC addLayer:layer];
  1181.         layer.drawPriority = 0;
  1182.         baseLayer = layer;        
  1183.     }
  1184.    
  1185.     // If we're fetching one of the JSON tile specs, kick that off
  1186.     if (jsonTileSpec)
  1187.     {
  1188.         NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:jsonTileSpec]];
  1189.        
  1190.         AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
  1191.         operation.responseSerializer = [AFJSONResponseSerializer serializer];
  1192.         [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
  1193.          {
  1194.              // Add a quad earth paging layer based on the tile spec we just fetched
  1195.              MaplyRemoteTileSource *tileSource = [[MaplyRemoteTileSource alloc] initWithTilespec:responseObject];
  1196.              tileSource.cacheDir = thisCacheDir;
  1197.              if (zoomLimit != 0 && zoomLimit < tileSource.maxZoom)
  1198.                  tileSource.tileInfo.maxZoom = zoomLimit;
  1199.              MaplyQuadImageTilesLayer *layer = [[MaplyQuadImageTilesLayer alloc] initWithCoordSystem:tileSource.coordSys tileSource:tileSource];
  1200.              layer.handleEdges = true;
  1201.              layer.waitLoad = imageWaitLoad;
  1202.              layer.requireElev = requireElev;
  1203.              layer.maxTiles = maxLayerTiles;
  1204.              if (startupMapType == Maply2DMap)
  1205.              {
  1206.                  layer.singleLevelLoading = true;
  1207.                  layer.multilLevelLoads = @[@(-4), @(-2)];
  1208.              }
  1209.              [baseViewC addLayer:layer];
  1210.              layer.drawPriority = 0;
  1211.              baseLayer = layer;
  1212.  
  1213. #ifdef RELOADTEST
  1214.              [self performSelector:@selector(reloadLayer:) withObject:nil afterDelay:10.0];
  1215. #endif
  1216.          }
  1217.         failure:^(AFHTTPRequestOperation *operation, NSError *error)
  1218.          {
  1219.              NSLog(@"Failed to reach JSON tile spec at: %@",jsonTileSpec);
  1220.          }
  1221.          ];
  1222.        
  1223.         [operation start];
  1224.     }
  1225.    
  1226.     // Set up some defaults for display
  1227.     screenLabelDesc = @{kMaplyTextColor: screenLabelColor,
  1228.                         //                        kMaplyBackgroundColor: screenLabelBackColor,
  1229.                         kMaplyFade: @(1.0),
  1230.                         kMaplyTextOutlineSize: @(1.5),
  1231.                         kMaplyTextOutlineColor: [UIColor blackColor],
  1232.                         };
  1233.     labelDesc = @{kMaplyTextColor: labelColor,
  1234.                   kMaplyBackgroundColor: labelBackColor,
  1235.                   kMaplyFade: @(1.0)};
  1236.     vectorDesc = @{kMaplyColor: vecColor,
  1237.                    kMaplyVecWidth: @(vecWidth),
  1238.                    kMaplyFade: @(1.0),
  1239.                    kMaplySelectable: @(true)};
  1240.    
  1241. }
  1242.  
  1243. // Reload testing
  1244. - (void)reloadLayer:(MaplyQuadImageTilesLayer *)layer
  1245. {
  1246.     if (baseLayer && [baseLayer isKindOfClass:[MaplyQuadImageTilesLayer class]])
  1247.     {
  1248.         MaplyQuadImageTilesLayer *layer = (MaplyQuadImageTilesLayer *)baseLayer;
  1249.         NSLog(@"Reloading layer");
  1250.         [layer reload];
  1251.  
  1252.         [self performSelector:@selector(reloadLayer:) withObject:nil afterDelay:10.0];
  1253.     }
  1254. }
  1255.  
  1256. // Run through the overlays the user wants turned on
  1257. - (void)setupOverlays:(NSDictionary *)baseSettings
  1258. {
  1259.     // For network paging layers, where we'll store temp files
  1260.     NSString *cacheDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)  objectAtIndex:0];
  1261.     NSString *thisCacheDir = nil;
  1262.  
  1263.     for (NSString *layerName in [baseSettings allKeys])
  1264.     {
  1265.         bool isOn = [baseSettings[layerName] boolValue];
  1266.         MaplyViewControllerLayer *layer = ovlLayers[layerName];
  1267.         // Need to create the layer
  1268.         if (isOn && !layer)
  1269.         {
  1270.             if (![layerName compare:kMaplyTestUSGSOrtho])
  1271.             {
  1272.                 thisCacheDir = [NSString stringWithFormat:@"%@/usgs_naip/",cacheDir];
  1273.                 [self fetchWMSLayer:@"http://raster.nationalmap.gov/ArcGIS/services/Orthoimagery/USGS_EDC_Ortho_NAIP/ImageServer/WMSServer" layer:@"0" style:nil cacheDir:thisCacheDir ovlName:layerName];
  1274.             } else if (![layerName compare:kMaplyTestOWM])
  1275.             {
  1276.                 MaplyRemoteTileSource *tileSource = [[MaplyRemoteTileSource alloc] initWithBaseURL:@"http://tile.openweathermap.org/map/precipitation/" ext:@"png" minZoom:0 maxZoom:6];
  1277.                 tileSource.cacheDir = [NSString stringWithFormat:@"%@/openweathermap_precipitation/",cacheDir];
  1278.                 tileSource.tileInfo.cachedFileLifetime = 3 * 60 * 60; // invalidate OWM data after three hours
  1279.                 MaplyQuadImageTilesLayer *weatherLayer = [[MaplyQuadImageTilesLayer alloc] initWithCoordSystem:tileSource.coordSys tileSource:tileSource];
  1280.                 weatherLayer.coverPoles = false;
  1281.                 layer = weatherLayer;
  1282.                 weatherLayer.handleEdges = false;
  1283.                 [baseViewC addLayer:weatherLayer];
  1284.                 ovlLayers[layerName] = layer;
  1285.             } else if (![layerName compare:kMaplyTestForecastIO])
  1286.             {
  1287.                 // Collect up the various precipitation sources
  1288.                 NSMutableArray *tileSources = [NSMutableArray array];
  1289.                 for (unsigned int ii=0;ii<5;ii++)
  1290.                 {
  1291.                     MaplyRemoteTileInfo *precipTileSource =
  1292.                     [[MaplyRemoteTileInfo alloc]
  1293.                      initWithBaseURL:[NSString stringWithFormat:@"http://a.tiles.mapbox.com/v3/mousebird.precip-example-layer%d/",ii] ext:@"png" minZoom:0 maxZoom:6];
  1294.                     precipTileSource.cacheDir = [NSString stringWithFormat:@"%@/forecast_io_weather_layer%d/",cacheDir,ii];
  1295.                     [tileSources addObject:precipTileSource];
  1296.                 }
  1297.                 MaplyMultiplexTileSource *precipTileSource = [[MaplyMultiplexTileSource alloc] initWithSources:tileSources];
  1298.                 // Create a precipitation layer that animates
  1299.                 MaplyQuadImageTilesLayer *precipLayer = [[MaplyQuadImageTilesLayer alloc] initWithCoordSystem:precipTileSource.coordSys tileSource:precipTileSource];
  1300.                 precipLayer.imageDepth = (int)[tileSources count];
  1301.                 precipLayer.animationPeriod = 6.0;
  1302.                 precipLayer.imageFormat = MaplyImageUByteRed;
  1303. //                precipLayer.texturAtlasSize = 512;
  1304.                 precipLayer.numSimultaneousFetches = 4;
  1305.                 precipLayer.handleEdges = false;
  1306.                 precipLayer.coverPoles = false;
  1307.                 precipLayer.shaderProgramName = [WeatherShader setupWeatherShader:baseViewC];
  1308.                 [baseViewC addLayer:precipLayer];
  1309.                 layer = precipLayer;
  1310.                 ovlLayers[layerName] = layer;
  1311.             } else if (![layerName compare:kMaplyTestMapboxStreets])
  1312.             {
  1313.                 self.title = @"Mapbox Vector Streets";
  1314.                 thisCacheDir = [NSString stringWithFormat:@"%@/mapbox-streets-vectiles",cacheDir];
  1315.                 [MaplyMapnikVectorTiles StartRemoteVectorTilesWithTileSpec:@"http://a.tiles.mapbox.com/v3/mapbox.mapbox-streets-v4.json"
  1316.                   style:[[NSBundle mainBundle] pathForResource:@"osm-bright" ofType:@"xml"]
  1317.                   cacheDir:thisCacheDir
  1318.                      viewC:baseViewC
  1319.                    success:
  1320.                          ^(MaplyMapnikVectorTiles *vecTiles)
  1321.                         {
  1322.                             // Don't load the lowest levels for the globe
  1323.                             if (globeViewC)
  1324.                                 vecTiles.minZoom = 5;
  1325.                            
  1326.                             // Note: These are set after the MapnikStyleSet has already been initialized
  1327.                             MapnikStyleSet *styleSet = (MapnikStyleSet *)vecTiles.styleDelegate;
  1328.                             styleSet.tileStyleSettings.markerImportance = 10.0;
  1329.                             styleSet.tileStyleSettings.fontName = @"Gill Sans";
  1330.                            
  1331.                             // Now for the paging layer itself
  1332.                             MaplyQuadPagingLayer *pageLayer = [[MaplyQuadPagingLayer alloc] initWithCoordSystem:[[MaplySphericalMercator alloc] initWebStandard] delegate:vecTiles];
  1333.                             pageLayer.numSimultaneousFetches = 6;
  1334.                             pageLayer.flipY = false;
  1335.                             pageLayer.importance = 1024*1024*2;
  1336.                             pageLayer.useTargetZoomLevel = true;
  1337.                             pageLayer.singleLevelLoading = true;
  1338.                             [baseViewC addLayer:pageLayer];
  1339.                             ovlLayers[layerName] = pageLayer;
  1340.                          }
  1341.                    failure:
  1342.                          ^(NSError *error){
  1343.                              NSLog(@"Failed to load Mapnik vector tiles because: %@",error);
  1344.                          }
  1345.                  ];
  1346.             } else if (![layerName compare:kMaplyMapzenVectors])
  1347.             {
  1348.                 thisCacheDir = [NSString stringWithFormat:@"%@/mapzen-vectiles",cacheDir];
  1349.                 [MaplyMapnikVectorTiles StartRemoteVectorTilesWithURL:@"http://vector.mapzen.com/osm/all/"
  1350.                                                                   ext:@"mapbox"
  1351.                                                               minZoom:8
  1352.                                                               maxZoom:14
  1353.                                                                 style:[[NSBundle mainBundle] pathForResource:@"MapzenStyles" ofType:@"json"]
  1354.                                                                   cacheDir:thisCacheDir
  1355.                                                                      viewC:baseViewC
  1356.                                                                    success:
  1357.                  ^(MaplyMapnikVectorTiles *vecTiles)
  1358.                  {
  1359.                      // Now for the paging layer itself
  1360.                      MaplyQuadPagingLayer *pageLayer = [[MaplyQuadPagingLayer alloc] initWithCoordSystem:[[MaplySphericalMercator alloc] initWebStandard] delegate:vecTiles];
  1361.                      pageLayer.numSimultaneousFetches = 4;
  1362.                      pageLayer.flipY = false;
  1363.                      pageLayer.importance = 1024*1024;
  1364.                      pageLayer.useTargetZoomLevel = true;
  1365.                      pageLayer.singleLevelLoading = true;
  1366.                      [baseViewC addLayer:pageLayer];
  1367.                      ovlLayers[layerName] = pageLayer;
  1368.                  }
  1369.                                                                    failure:
  1370.                  ^(NSError *error){
  1371.                      NSLog(@"Failed to load Mapnik vector tiles because: %@",error);
  1372.                  }
  1373.                  ];
  1374.             }
  1375.         } else if (!isOn && layer)
  1376.         {
  1377.             // Get rid of the layer
  1378.             [baseViewC removeLayer:layer];
  1379.             [ovlLayers removeObjectForKey:layerName];
  1380.         }
  1381.     }
  1382.  
  1383.     // Fill out the cache dir if there is one
  1384.     if (thisCacheDir)
  1385.     {
  1386.         NSError *error = nil;
  1387.         [[NSFileManager defaultManager] createDirectoryAtPath:thisCacheDir withIntermediateDirectories:YES attributes:nil error:&error];
  1388.     }
  1389. }
  1390.  
  1391. // Look at the configuration controller and decide what to turn off or on
  1392. - (void)changeMapContents
  1393. {
  1394.     imageWaitLoad = [configViewC valueForSection:kMaplyTestCategoryInternal row:kMaplyTestWaitLoad];
  1395.    
  1396.     [self setupBaseLayer:((ConfigSection *)configViewC.values[0]).rows];
  1397.     if ([configViewC.values count] > 1)
  1398.         [self setupOverlays:((ConfigSection *)configViewC.values[1]).rows];
  1399.    
  1400.     if ([configViewC valueForSection:kMaplyTestCategoryObjects row:kMaplyTestLabel2D])
  1401.     {
  1402.         if (!screenLabelsObj)
  1403.             [self addScreenLabels:locations len:NumLocations stride:4 offset:0];
  1404.     } else {
  1405.         if (screenLabelsObj)
  1406.         {
  1407.             [baseViewC removeObject:screenLabelsObj];
  1408.             screenLabelsObj = nil;
  1409.         }
  1410.     }    
  1411.  
  1412.     if ([configViewC valueForSection:kMaplyTestCategoryObjects row:kMaplyTestLabel3D])
  1413.     {
  1414.         if (!labelsObj)
  1415.             [self addLabels:locations len:NumLocations stride:4 offset:1];
  1416.     } else {
  1417.         if (labelsObj)
  1418.         {
  1419.             [baseViewC removeObject:labelsObj];
  1420.             labelsObj = nil;
  1421.         }
  1422.     }
  1423.  
  1424.     if ([configViewC valueForSection:kMaplyTestCategoryObjects row:kMaplyTestMarker2D])
  1425.     {
  1426.         if (!screenMarkersObj)
  1427.             [self addScreenMarkers:locations len:NumLocations stride:4 offset:2];
  1428.     } else {
  1429.         if (screenMarkersObj)
  1430.         {
  1431.             [baseViewC removeObject:screenMarkersObj];
  1432.             screenMarkersObj = nil;
  1433.         }
  1434.     }
  1435.    
  1436.     if ([configViewC valueForSection:kMaplyTestCategoryObjects row:kMaplyTestMarker3D])
  1437.     {
  1438.         if (!markersObj)
  1439.             [self addMarkers:locations len:NumLocations stride:4 offset:3];
  1440.     } else {
  1441.         if (markersObj)
  1442.         {
  1443.             [baseViewC removeObject:markersObj];
  1444.             markersObj = nil;
  1445.         }
  1446.     }
  1447.  
  1448.     if ([configViewC valueForSection:kMaplyTestCategoryObjects row:kMaplyTestSticker])
  1449.     {
  1450.         if (!stickersObj)
  1451.             [self addStickers:locations len:NumLocations stride:4 offset:2 desc:@{kMaplyFade: @(1.0)}];
  1452.     } else {
  1453.         if (stickersObj)
  1454.         {
  1455.             [baseViewC removeObject:stickersObj];
  1456.             stickersObj = nil;
  1457.         }
  1458.     }
  1459.  
  1460.     if ([configViewC valueForSection:kMaplyTestCategoryObjects row:kMaplyTestShapeCylinder])
  1461.     {
  1462.         if (!shapeCylObj)
  1463.         {
  1464.             [self addShapeCylinders:locations len:NumLocations stride:4 offset:0 desc:@{kMaplyColor : [UIColor colorWithRed:0.0 green:0.0 blue:1.0 alpha:0.8], kMaplyFade: @(1.0)}];
  1465.         }
  1466.     } else {
  1467.         if (shapeCylObj)
  1468.         {
  1469.             [baseViewC removeObject:shapeCylObj];
  1470.             shapeCylObj = nil;
  1471.         }
  1472.     }
  1473.  
  1474.     if ([configViewC valueForSection:kMaplyTestCategoryObjects row:kMaplyTestShapeSphere])
  1475.     {
  1476.         if (!shapeSphereObj)
  1477.         {
  1478.             [self addShapeSpheres:locations len:NumLocations stride:4 offset:1 desc:@{kMaplyColor : [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.8], kMaplyFade: @(1.0)}];
  1479.         }
  1480.     } else {
  1481.         if (shapeSphereObj)
  1482.         {
  1483.             [baseViewC removeObject:shapeSphereObj];
  1484.             shapeSphereObj = nil;
  1485.         }
  1486.     }
  1487.  
  1488.     if ([configViewC valueForSection:kMaplyTestCategoryObjects row:kMaplyTestShapeGreatCircle])
  1489.     {
  1490.         if (!greatCircleObj)
  1491.         {
  1492.             [self addGreatCircles:locations len:NumLocations stride:4 offset:2 desc:@{kMaplyColor : [UIColor colorWithRed:1.0 green:0.1 blue:0.0 alpha:1.0], kMaplyFade: @(1.0)}];
  1493.         }
  1494.     } else {
  1495.         if (greatCircleObj)
  1496.         {
  1497.             [baseViewC removeObject:greatCircleObj];
  1498.             greatCircleObj = nil;
  1499.         }
  1500.     }
  1501.    
  1502.     if ([configViewC valueForSection:kMaplyTestCategoryObjects row:kMaplyTestLatLon])
  1503.     {
  1504.         if (!latLonObj)
  1505.         {
  1506.             [self addLinesLon:20 lat:10 color:[UIColor blueColor]];
  1507.         }
  1508.     } else {
  1509.         if (latLonObj)
  1510.         {
  1511.             [baseViewC removeObject:latLonObj];
  1512.             latLonObj = nil;
  1513.         }
  1514.     }
  1515.    
  1516.     if ([configViewC valueForSection:kMaplyTestCategoryObjects row:kMaplyTestRoads])
  1517.     {
  1518.         if (!sfRoadsObjArray)
  1519.         {
  1520.             [self addShapeFile:@"tl_2013_06075_roads"];
  1521. //            MaplyCoordinate coords[5];
  1522. //            coords[0] = MaplyCoordinateMakeWithDegrees(-122.3, 37.7);
  1523. //            coords[1] = MaplyCoordinateMakeWithDegrees(-122.3, 37.783333);
  1524. //            coords[2] = MaplyCoordinateMakeWithDegrees(-122.3, 37.783333);
  1525. //            coords[3] = MaplyCoordinateMakeWithDegrees(-122.416667, 37.8333);
  1526. //            MaplyVectorObject *vecObj = [[MaplyVectorObject alloc] initWithLineString:coords numCoords:4 attributes:nil];
  1527. //            sfRoadsObjArray = [self addWideVectors:vecObj];
  1528.         }
  1529.     } else {
  1530.         if (sfRoadsObjArray)
  1531.         {
  1532.             [baseViewC removeObjects:sfRoadsObjArray];
  1533.             sfRoadsObjArray = nil;
  1534.         }
  1535.     }
  1536.  
  1537.     if ([configViewC valueForSection:kMaplyTestCategoryObjects row:kMaplyTestCountry])
  1538.     {
  1539.         // Countries we have geoJSON for
  1540.         NSArray *countryArray = [NSArray arrayWithObjects:
  1541.          @"ABW", @"AFG", @"AGO", @"AIA", @"ALA", @"ALB", @"AND", @"ARE", @"ARG", @"ARM", @"ASM", @"ATA", @"ATF", @"ATG", @"AUS", @"AUT",
  1542.          @"AZE", @"BDI", @"BEL", @"BEN", @"BES", @"BFA", @"BGD", @"BGR", @"BHR", @"BHS", @"BIH", @"BLM", @"BLR", @"BLZ", @"BMU", @"BOL",
  1543.          @"BRA", @"BRB", @"BRN", @"BTN", @"BVT", @"BWA", @"CAF", @"CAN", @"CCK", @"CHE", @"CHL", @"CHN", @"CIV", @"CMR", @"COD", @"COG",
  1544.          @"COK", @"COL", @"COM", @"CPV", @"CRI", @"CUB", @"CUW", @"CXR", @"CYM", @"CYP", @"CZE", @"DEU", @"DJI", @"DMA", @"DNK", @"DOM",
  1545.          @"DZA", @"ECU", @"EGY", @"ERI", @"ESH", @"ESP", @"EST", @"ETH", @"FIN", @"FJI", @"FLK", @"FRA", @"FRO", @"FSM", @"GAB", @"GBR",
  1546.          @"GEO", @"GGY", @"GHA", @"GIB", @"GIN", @"GLP", @"GMB", @"GNB", @"GNQ", @"GRC", @"GRD", @"GRL", @"GTM", @"GUF", @"GUM", @"GUY",
  1547.          @"HKG", @"HMD", @"HND", @"HRV", @"HTI", @"HUN", @"IDN", @"IMN", @"IND", @"IOT", @"IRL", @"IRN", @"IRQ", @"ISL", @"ISR", @"ITA",
  1548.          @"JAM", @"JEY", @"JOR", @"JPN", @"KAZ", @"KEN", @"KGZ", @"KHM", @"KIR", @"KNA", @"KOR", @"KWT", @"LAO", @"LBN", @"LBR", @"LBY",
  1549.          @"LCA", @"LIE", @"LKA", @"LSO", @"LTU", @"LUX", @"LVA", @"MAC", @"MAF", @"MAR", @"MCO", @"MDA", @"MDG", @"MDV", @"MEX", @"MHL",
  1550.          @"MKD", @"MLI", @"MLT", @"MMR", @"MNE", @"MNG", @"MNP", @"MOZ", @"MRT", @"MSR", @"MTQ", @"MUS", @"MWI", @"MYS", @"MYT", @"NAM",
  1551.          @"NCL", @"NER", @"NFK", @"NGA", @"NIC", @"NIU", @"NLD", @"NOR", @"NPL", @"NRU", @"NZL", @"OMN", @"PAK", @"PAN", @"PCN", @"PER",
  1552.          @"PHL", @"PLW", @"PNG", @"POL", @"PRI", @"PRK", @"PRT", @"PRY", @"PSE", @"PYF", @"QAT", @"REU", @"ROU", @"RUS", @"RWA", @"SAU",
  1553.          @"SDN", @"SEN", @"SGP", @"SGS", @"SHN", @"SJM", @"SLB", @"SLE", @"SLV", @"SMR", @"SOM", @"SPM", @"SRB", @"SSD", @"STP", @"SUR",
  1554.          @"SVK", @"SVN", @"SWE", @"SWZ", @"SXM", @"SYC", @"SYR", @"TCA", @"TCD", @"TGO", @"THA", @"TJK", @"TKL", @"TKM", @"TLS", @"TON",
  1555.          @"TTO", @"TUN", @"TUR", @"TUV", @"TWN", @"TZA", @"UGA", @"UKR", @"UMI", @"URY", @"USA", @"UZB", @"VAT", @"VCT", @"VEN", @"VGB",
  1556.          @"VIR", @"VNM", @"VUT", @"WLF", @"WSM", @"YEM", @"ZAF", @"ZMB", @"ZWE", nil];
  1557.        
  1558.         if (!vecObjects)
  1559.             [self addCountries:countryArray stride:1];
  1560.     } else {
  1561.         if (vecObjects)
  1562.         {
  1563.             [baseViewC removeObjects:vecObjects];
  1564.             vecObjects = nil;
  1565.         }
  1566.         if (autoLabels)
  1567.         {
  1568.             [baseViewC removeObject:autoLabels];
  1569.             autoLabels = nil;
  1570.         }
  1571.     }
  1572.    
  1573.     if ([configViewC valueForSection:kMaplyTestCategoryObjects row:kMaplyTestLoftedPoly])
  1574.     {
  1575.     } else {
  1576.         if ([loftPolyDict count] > 0)
  1577.         {
  1578.             [baseViewC removeObjects:loftPolyDict.allValues];
  1579.             loftPolyDict = [NSMutableDictionary dictionary];
  1580.         }
  1581.     }
  1582.    
  1583.     if ([configViewC valueForSection:kMaplyTestCategoryObjects row:kMaplyTestMegaMarkers])
  1584.     {
  1585.         if (!megaMarkersObj)
  1586.             [self addMegaMarkers];
  1587.     } else {
  1588.         if (megaMarkersObj)
  1589.         {
  1590.             [baseViewC removeObject:megaMarkersObj];
  1591.             megaMarkersObj = nil;
  1592.         }
  1593.     }
  1594.    
  1595.     if ([configViewC valueForSection:kMaplyTestCategoryAnimation row:kMaplyTestAnimateSphere])
  1596.     {
  1597.         if (!animSphere)
  1598.             [self addAnimatedSphere];
  1599.     } else {
  1600.         if (animSphere)
  1601.         {
  1602.             [baseViewC removeActiveObject:animSphere];
  1603.             animSphere = nil;
  1604.         }
  1605.     }
  1606.    
  1607.     baseViewC.performanceOutput = [configViewC valueForSection:kMaplyTestCategoryInternal row:kMaplyTestPerf];
  1608.    
  1609.     if (globeViewC)
  1610.     {
  1611.         globeViewC.keepNorthUp = [configViewC valueForSection:kMaplyTestCategoryGestures row:kMaplyTestNorthUp];
  1612.         globeViewC.pinchGesture = [configViewC valueForSection:kMaplyTestCategoryGestures row:kMaplyTestPinch];
  1613.         globeViewC.rotateGesture = [configViewC valueForSection:kMaplyTestCategoryGestures row:kMaplyTestRotate];
  1614.     } else {
  1615.         if([configViewC valueForSection:kMaplyTestCategoryGestures row:kMaplyTestNorthUp]) {
  1616.             mapViewC.heading = 0;
  1617.         }
  1618.         mapViewC.pinchGesture = [configViewC valueForSection:kMaplyTestCategoryGestures row:kMaplyTestPinch];
  1619.         mapViewC.rotateGesture = [configViewC valueForSection:kMaplyTestCategoryGestures row:kMaplyTestRotate];
  1620.     }
  1621.    
  1622.     // Update rendering hints
  1623.     NSMutableDictionary *hintDict = [NSMutableDictionary dictionary];
  1624.     [hintDict setObject:[NSNumber numberWithBool:[configViewC valueForSection:kMaplyTestCategoryInternal row:kMaplyTestCulling]] forKey:kMaplyRenderHintCulling];
  1625.     [baseViewC setHints:hintDict];
  1626. }
  1627.  
  1628. - (void)showConfig
  1629. {
  1630.     if (UI_USER_INTERFACE_IDIOM() ==  UIUserInterfaceIdiomPad)
  1631.     {
  1632.         popControl = [[UIPopoverController alloc] initWithContentViewController:configViewC];
  1633.         popControl.delegate = self;
  1634.         [popControl setPopoverContentSize:CGSizeMake(400.0,4.0/5.0*self.view.bounds.size.height)];
  1635.         [popControl presentPopoverFromRect:CGRectMake(0, 0, 10, 10) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
  1636.     } else {
  1637.         configViewC.navigationItem.hidesBackButton = YES;
  1638.         configViewC.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(editDone)];
  1639.         [self.navigationController pushViewController:configViewC animated:YES];
  1640.     }
  1641. }
  1642.  
  1643. - (void)editDone
  1644. {
  1645.     [self.navigationController popToViewController:self animated:YES];
  1646.     [self changeMapContents];
  1647. }
  1648.  
  1649. #pragma mark - Whirly Globe Delegate
  1650.  
  1651. // Build a simple selection view to draw over top of the globe
  1652. - (UIView *)makeSelectionView:(NSString *)msg
  1653. {
  1654.     float fontSize = 32.0;
  1655.     float marginX = 32.0;
  1656.    
  1657.     // Make a label and stick it in as a view to track
  1658.     // We put it in a top level view so we can center it
  1659.     UIView *topView = [[UIView alloc] initWithFrame:CGRectZero];
  1660.     // Start out hidden before the first placement.  The tracker will turn it on.
  1661.     topView.hidden = YES;
  1662.     topView.alpha = 0.8;
  1663.     UIView *backView = [[UIView alloc] initWithFrame:CGRectZero];
  1664.     [topView addSubview:backView];
  1665.     topView.clipsToBounds = NO;
  1666.     UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectZero];
  1667.     [backView addSubview:testLabel];
  1668.     testLabel.font = [UIFont systemFontOfSize:fontSize];
  1669.     testLabel.textColor = [UIColor whiteColor];
  1670.     testLabel.backgroundColor = [UIColor clearColor];
  1671.     testLabel.text = msg;
  1672.     CGSize textSize = [testLabel.text sizeWithFont:testLabel.font];
  1673.     testLabel.frame = CGRectMake(marginX/2.0,0,textSize.width,textSize.height);
  1674.     testLabel.opaque = NO;
  1675.     backView.layer.cornerRadius = 5.0;
  1676.     backView.backgroundColor = [UIColor colorWithRed:0.0 green:102/255.0 blue:204/255.0 alpha:1.0];
  1677.     backView.frame = CGRectMake(-(textSize.width)/2.0,-(textSize.height)/2.0,textSize.width+marginX,textSize.height);
  1678.    
  1679.     return topView;
  1680. }
  1681.  
  1682. - (void)handleSelection:(NSObject *)selectedObj
  1683. {
  1684.     // If we've currently got a selected view, get rid of it
  1685. //    if (selectedViewTrack)
  1686. //    {
  1687. //        [baseViewC removeViewTrackForView:selectedViewTrack.view];
  1688. //        selectedViewTrack = nil;
  1689. //    }
  1690.     [baseViewC clearAnnotations];
  1691.    
  1692.     MaplyCoordinate loc;
  1693.     NSString *title = nil,*subTitle = nil;
  1694.     CGPoint offset = CGPointZero;
  1695.    
  1696.     if ([selectedObj isKindOfClass:[MaplyMarker class]])
  1697.     {
  1698.         MaplyMarker *marker = (MaplyMarker *)selectedObj;
  1699.         loc = marker.loc;
  1700.         title = (NSString *)marker.userObject;
  1701.         subTitle = @"Marker";
  1702.     } else if ([selectedObj isKindOfClass:[MaplyScreenMarker class]])
  1703.     {
  1704.         MaplyScreenMarker *screenMarker = (MaplyScreenMarker *)selectedObj;
  1705.         loc = screenMarker.loc;
  1706.         title = (NSString *)screenMarker.userObject;
  1707.         subTitle = @"Screen Marker";
  1708.         offset = CGPointMake(0.0, -8.0);
  1709.     } else if ([selectedObj isKindOfClass:[MaplyLabel class]])
  1710.     {
  1711.         MaplyLabel *label = (MaplyLabel *)selectedObj;
  1712.         loc = label.loc;
  1713.         title = (NSString *)label.userObject;
  1714.         subTitle = @"Label";
  1715.     } else if ([selectedObj isKindOfClass:[MaplyScreenLabel class]])
  1716.     {
  1717.         MaplyScreenLabel *screenLabel = (MaplyScreenLabel *)selectedObj;
  1718.         loc = screenLabel.loc;
  1719.         title = (NSString *)screenLabel.userObject;
  1720.         subTitle = @"Screen Label";
  1721.         offset = CGPointMake(0.0, -6.0);
  1722.     } else if ([selectedObj isKindOfClass:[MaplyVectorObject class]])
  1723.     {
  1724.         MaplyVectorObject *vecObj = (MaplyVectorObject *)selectedObj;
  1725.         if ([vecObj centroid:&loc])
  1726.         {
  1727.             NSString *name = (NSString *)vecObj.userObject;
  1728.             title = (NSString *)vecObj.userObject;
  1729.             subTitle = @"Vector";
  1730.             if ([configViewC valueForSection:kMaplyTestCategoryObjects row:kMaplyTestLoftedPoly])
  1731.             {
  1732.                 // See if there already is one
  1733.                 if (!loftPolyDict[name])
  1734.                 {
  1735.                     MaplyComponentObject *compObj = [baseViewC addLoftedPolys:@[vecObj] key:nil cache:nil desc:@{kMaplyColor: [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.25], kMaplyLoftedPolyHeight: @(0.05), kMaplyFade: @(0.5)}];
  1736.                     if (compObj)
  1737.                     {
  1738.                         loftPolyDict[name] = compObj;
  1739.                     }
  1740.                 }
  1741.             }
  1742.         }
  1743.     } else if ([selectedObj isKindOfClass:[MaplyShapeSphere class]])
  1744.     {
  1745.         MaplyShapeSphere *sphere = (MaplyShapeSphere *)selectedObj;
  1746.         loc = sphere.center;
  1747.         title = @"Shape";
  1748.         subTitle = @"Sphere";
  1749.     } else if ([selectedObj isKindOfClass:[MaplyShapeCylinder class]])
  1750.     {
  1751.         MaplyShapeCylinder *cyl = (MaplyShapeCylinder *)selectedObj;
  1752.         loc = cyl.baseCenter;
  1753.         title = @"Shape";
  1754.         subTitle = @"Cylinder";
  1755.     } else
  1756.         // Don't know what it is
  1757.         return;
  1758.    
  1759.     // Build the selection view and hand it over to the globe to track
  1760. //    selectedViewTrack = [[MaplyViewTracker alloc] init];
  1761. //    selectedViewTrack.loc = loc;
  1762. //    selectedViewTrack.view = [self makeSelectionView:msg];
  1763. //    [baseViewC addViewTracker:selectedViewTrack];
  1764.     if (title)
  1765.     {
  1766.         MaplyAnnotation *annotate = [[MaplyAnnotation alloc] init];
  1767.         annotate.title = title;
  1768.         annotate.subTitle = subTitle;
  1769.         [baseViewC clearAnnotations];
  1770.         [baseViewC addAnnotation:annotate forPoint:loc offset:offset];
  1771.     }
  1772. }
  1773.  
  1774. // User selected something
  1775. - (void)globeViewController:(WhirlyGlobeViewController *)viewC didSelect:(NSObject *)selectedObj
  1776. {
  1777.     [self handleSelection:selectedObj];
  1778. }
  1779.  
  1780. // User didn't select anything, but did tap
  1781. - (void)globeViewController:(WhirlyGlobeViewController *)viewC didTapAt:(MaplyCoordinate)coord
  1782. {
  1783.     // Just clear the selection
  1784.     [baseViewC clearAnnotations];
  1785.  
  1786.  
  1787.  
  1788.     if (globeViewC)
  1789.     {
  1790.          // [baseViewC stopAnimation];
  1791. //        MaplyCoordinate geoCoord;
  1792. //        if ([globeViewC geoPointFromScreen:CGPointMake(0, 0) geoCoord:&geoCoord])
  1793. //            NSLog(@"GeoCoord (upper left): %f, %f",geoCoord.x,geoCoord.y);
  1794. //        else
  1795. //            NSLog(@"GeoCoord not on globe");
  1796. //        MaplyCoordinate geoCoord = MaplyCoordinateMakeWithDegrees(0, 0);
  1797. //        CGPoint screenPt;
  1798. //        if ([globeViewC screenPointFromGeo:geoCoord screenPt:&screenPt])
  1799. //            NSLog(@"Origin at: %f,%f",screenPt.x,screenPt.y);
  1800. //        else
  1801. //            NSLog(@"Origin not on screen");
  1802.     }
  1803.    
  1804.     // Screen shot
  1805. //    UIImage *image = [baseViewC snapshot];
  1806. //    
  1807. //    if (selectedViewTrack)
  1808. //    {
  1809. //        [baseViewC removeViewTrackForView:selectedViewTrack.view];
  1810. //        selectedViewTrack = nil;
  1811. //    }
  1812. }
  1813.  
  1814. // Bring up the config view when the user taps outside
  1815. - (void)globeViewControllerDidTapOutside:(WhirlyGlobeViewController *)viewC
  1816. {
  1817. //    [self showPopControl];
  1818. }
  1819.  
  1820. - (void)globeViewController:(WhirlyGlobeViewController *)viewC layerDidLoad:(MaplyViewControllerLayer *)layer
  1821. {
  1822.     NSLog(@"Spherical Earth Layer loaded.");
  1823. }
  1824.  
  1825. - (void)globeViewControllerDidStartMoving:(WhirlyGlobeViewController *)viewC userMotion:(bool)userMotion
  1826. {
  1827. //    NSLog(@"Started moving");
  1828. }
  1829.  
  1830. - (void)globeViewController:(WhirlyGlobeViewController *)viewC didStopMoving:(MaplyCoordinate *)corners userMotion:(bool)userMotion
  1831. {
  1832. //    NSLog(@"Stopped moving");
  1833. }
  1834.  
  1835. #pragma mark - Maply delegate
  1836.  
  1837. - (void)maplyViewController:(MaplyViewController *)viewC didSelect:(NSObject *)selectedObj
  1838. {
  1839.     [self handleSelection:selectedObj];
  1840. }
  1841.  
  1842. //- (void)maplyViewController:(MaplyViewController *)viewC didTapAt:(MaplyCoordinate)coord
  1843. //{
  1844. //    // Just clear the selection
  1845. //    [baseViewC clearAnnotations];
  1846. ////    if (selectedViewTrack)
  1847. ////    {
  1848. ////        [baseViewC removeViewTrackForView:selectedViewTrack.view];
  1849. ////        selectedViewTrack = nil;
  1850. ////    }    
  1851. //}
  1852.  
  1853. - (void)maplyViewControllerDidStartMoving:(MaplyViewController *)viewC userMotion:(bool)userMotion
  1854. {
  1855. //    NSLog(@"Started moving");
  1856. }
  1857.  
  1858. - (void)maplyViewController:(MaplyViewController *)viewC didStopMoving:(MaplyCoordinate *)corners userMotion:(bool)userMotion
  1859. {
  1860. //    NSLog(@"Stopped moving");
  1861. }
  1862.  
  1863. #pragma mark - Popover Delegate
  1864.  
  1865. - (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
  1866. {
  1867.     [self changeMapContents];
  1868. }
  1869.  
  1870. @end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement