aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--androidApp/src/main/java/mx/trackermap/TrackerMap/android/TrackerApp.kt12
-rw-r--r--androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/commands/UnitCommandsViewModel.kt25
-rw-r--r--androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/reports/UnitReportsFragment.kt8
-rw-r--r--androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/MapFragment.kt34
-rw-r--r--androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/MapWrapperFragment.kt6
-rw-r--r--androidApp/src/main/java/mx/trackermap/TrackerMap/android/shared/MarkerTransformations.kt125
-rw-r--r--androidApp/src/main/java/mx/trackermap/TrackerMap/android/shared/UnitRenderData.kt64
-rw-r--r--iosApp/.gitignore95
-rw-r--r--iosApp/Localizable.strings12
-rw-r--r--iosApp/WhirlyGlobe.xcframework/Info.plist40
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Config-ac.h.in91
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GeoJSONSource.h40
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GeographicLib_ObjC.h100
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeDoubleTapDelegate.h34
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeDoubleTapDragDelegate.h33
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobePanDelegate.h48
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobePinchDelegate.h61
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeRotateDelegate.h37
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeTapDelegate.h29
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeTiltDelegate.h28
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeTwoFingerTapDelegate.h34
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapboxVectorInterpreter.h65
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapboxVectorStyleSet.h139
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapboxVectorTiles.h65
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/Maply3DTouchPreviewDatasource.h38
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/Maply3dTouchPreviewDelegate.h26
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyActiveObject.h70
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyAnnotation.h71
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyAtmosphere.h81
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyBaseViewController.h1582
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyBillboard.h74
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyBridge.h23
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyCluster.h147
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyColorRampGenerator.h42
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyComponent.h102
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyComponentObject.h37
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyControllerLayer.h44
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyCoordinate.h336
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyCoordinateSystem.h176
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyDoubleTapDelegate.h25
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyDoubleTapDragDelegate.h22
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyGeomBuilder.h301
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyGeomModel.h122
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyGlobeRenderController.h115
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyIconManager.h140
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyImageTile.h113
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyLabel.h101
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyLight.h60
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyLocationTracker.h174
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyMBTileFetcher.h46
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyMarker.h85
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyMatrix.h65
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyMoon.h50
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyPanDelegate.h32
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyParticleSystem.h215
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyPinchDelegate.h23
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyPoints.h84
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyQuadImageFrameLoader.h191
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyQuadImageLoader.h229
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyQuadLoader.h236
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyQuadPagingLoader.h82
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyQuadSampler.h103
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyRemoteTileFetcher.h288
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyRenderController.h1007
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyRenderTarget.h119
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyRotateDelegate.h29
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyScreenLabel.h187
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyScreenMarker.h168
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyScreenObject.h106
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyShader.h174
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyShape.h318
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplySharedAttributes.h406
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplySimpleTileFetcher.h88
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyStarsModel.h59
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplySticker.h85
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplySun.h47
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTapDelegate.h30
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTapMessage.h35
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTexture.h31
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTextureBuilder.h47
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTileSourceNew.h161
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTouchCancelAnimationDelegate.h26
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTwoFingerTapDelegate.h25
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyUpdateLayer.h100
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVariableTarget.h88
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorObject.h562
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorStyle.h214
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorStyleSimple.h85
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorTileLineStyle.h29
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorTileMarkerStyle.h29
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorTilePolygonStyle.h29
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorTileStyle.h60
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorTileTextStyle.h29
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVertexAttribute.h49
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyViewController.h651
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyViewTracker.h68
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyWMSTileSource.h183
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyZoomGestureDelegate.h31
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapnikStyle.h33
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapnikStyleRule.h36
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapnikStyleSet.h47
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/NSData+Zlib.h37
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/NSDictionary+StyleRules.h33
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/SLDExpressions.h55
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/SLDOperators.h101
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/SLDStyleSet.h119
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/SLDSymbolizers.h82
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/SLDWellKnownMarkers.h23
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/WGCoordinate.h34
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/WhirlyGlobe.h121
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/WhirlyGlobeComponent.h23
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/WhirlyGlobeViewController.h809
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Info.plistbin0 -> 813 bytes
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Modules/module.modulemap6
-rwxr-xr-xiosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/WhirlyGlobebin0 -> 39596576 bytes
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/default.metallibbin0 -> 193696 bytes
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Config-ac.h.in91
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GeoJSONSource.h40
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GeographicLib_ObjC.h100
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeDoubleTapDelegate.h34
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeDoubleTapDragDelegate.h33
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobePanDelegate.h48
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobePinchDelegate.h61
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeRotateDelegate.h37
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeTapDelegate.h29
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeTiltDelegate.h28
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeTwoFingerTapDelegate.h34
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapboxVectorInterpreter.h65
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapboxVectorStyleSet.h139
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapboxVectorTiles.h65
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/Maply3DTouchPreviewDatasource.h38
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/Maply3dTouchPreviewDelegate.h26
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyActiveObject.h70
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyAnnotation.h71
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyAtmosphere.h81
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyBaseViewController.h1582
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyBillboard.h74
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyBridge.h23
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyCluster.h147
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyColorRampGenerator.h42
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyComponent.h102
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyComponentObject.h37
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyControllerLayer.h44
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyCoordinate.h336
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyCoordinateSystem.h176
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyDoubleTapDelegate.h25
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyDoubleTapDragDelegate.h22
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyGeomBuilder.h301
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyGeomModel.h122
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyGlobeRenderController.h115
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyIconManager.h140
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyImageTile.h113
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyLabel.h101
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyLight.h60
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyLocationTracker.h174
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyMBTileFetcher.h46
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyMarker.h85
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyMatrix.h65
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyMoon.h50
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyPanDelegate.h32
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyParticleSystem.h215
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyPinchDelegate.h23
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyPoints.h84
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyQuadImageFrameLoader.h191
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyQuadImageLoader.h229
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyQuadLoader.h236
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyQuadPagingLoader.h82
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyQuadSampler.h103
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyRemoteTileFetcher.h288
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyRenderController.h1007
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyRenderTarget.h119
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyRotateDelegate.h29
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyScreenLabel.h187
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyScreenMarker.h168
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyScreenObject.h106
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyShader.h174
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyShape.h318
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplySharedAttributes.h406
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplySimpleTileFetcher.h88
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyStarsModel.h59
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplySticker.h85
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplySun.h47
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTapDelegate.h30
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTapMessage.h35
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTexture.h31
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTextureBuilder.h47
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTileSourceNew.h161
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTouchCancelAnimationDelegate.h26
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTwoFingerTapDelegate.h25
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyUpdateLayer.h100
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVariableTarget.h88
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorObject.h562
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorStyle.h214
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorStyleSimple.h85
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorTileLineStyle.h29
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorTileMarkerStyle.h29
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorTilePolygonStyle.h29
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorTileStyle.h60
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorTileTextStyle.h29
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVertexAttribute.h49
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyViewController.h651
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyViewTracker.h68
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyWMSTileSource.h183
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyZoomGestureDelegate.h31
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapnikStyle.h33
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapnikStyleRule.h36
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapnikStyleSet.h47
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/NSData+Zlib.h37
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/NSDictionary+StyleRules.h33
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/SLDExpressions.h55
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/SLDOperators.h101
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/SLDStyleSet.h119
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/SLDSymbolizers.h82
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/SLDWellKnownMarkers.h23
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/WGCoordinate.h34
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/WhirlyGlobe.h121
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/WhirlyGlobeComponent.h23
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/WhirlyGlobeViewController.h809
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Info.plistbin0 -> 793 bytes
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Modules/module.modulemap6
-rwxr-xr-xiosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/WhirlyGlobebin0 -> 12133600 bytes
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/_CodeSignature/CodeResources1246
-rw-r--r--iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/default.metallibbin0 -> 194544 bytes
-rw-r--r--iosApp/iosApp.xcodeproj/project.pbxproj297
-rw-r--r--iosApp/iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata7
-rw-r--r--iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist8
-rw-r--r--iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved124
-rw-r--r--iosApp/iosApp.xcodeproj/xcshareddata/xcschemes/iosApp.xcscheme78
-rw-r--r--iosApp/iosApp.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist8
-rw-r--r--iosApp/iosApp/AppDelegate.swift62
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapAnimal.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapAnimal.imageset/animal.svg7
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapArrow.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapArrow.imageset/arrow.svg4
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapBicycle.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapBicycle.imageset/bicycle.svg7
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapBoat.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapBoat.imageset/boat.svg7
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapBus.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapBus.imageset/bus.svg7
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapCar.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapCar.imageset/car.svg7
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapCrane.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapCrane.imageset/crane.svg7
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapDefault.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapDefault.imageset/default.svg7
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapHelicopter.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapHelicopter.imageset/helicopter.svg7
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapMotorcycle.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapMotorcycle.imageset/motorcycle.svg7
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapOffroad.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapOffroad.imageset/offroad.svg7
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapPerson.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapPerson.imageset/person.svg7
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapPickup.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapPickup.imageset/pickup.svg7
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapPlane.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapPlane.imageset/plane.svg7
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapScooter.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapScooter.imageset/scooter.svg7
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapShip.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapShip.imageset/ship.svg7
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapTractor.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapTractor.imageset/tractor.svg7
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapTrain.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapTrain.imageset/train.svg7
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapTram.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapTram.imageset/tram.svg7
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapTrolleybus.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapTrolleybus.imageset/trolleybus.svg7
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapTruck.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapTruck.imageset/truck.svg7
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapVan.imageset/Contents.json21
-rw-r--r--iosApp/iosApp/Assets.xcassets/MapVan.imageset/van.svg7
-rw-r--r--iosApp/iosApp/Details/Commands/UnitCommandsView.swift58
-rw-r--r--iosApp/iosApp/Details/Commands/UnitCommandsViewModel.swift54
-rw-r--r--iosApp/iosApp/Details/DetailsView.swift81
-rw-r--r--iosApp/iosApp/Details/Information/UnitInformationView.swift120
-rw-r--r--iosApp/iosApp/Details/Reports/UnitReportsView.swift (renamed from shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/utils/MarkerType.kt)14
-rw-r--r--iosApp/iosApp/Devices/DeviceRow.swift197
-rw-r--r--iosApp/iosApp/Devices/DevicesView.swift38
-rw-r--r--iosApp/iosApp/Devices/DevicesViewModel.swift48
-rw-r--r--iosApp/iosApp/Info.plist4
-rw-r--r--iosApp/iosApp/Koin.swift14
-rw-r--r--iosApp/iosApp/Map/MapView.swift71
-rw-r--r--iosApp/iosApp/Map/MapViewController.swift338
-rw-r--r--iosApp/iosApp/Map/MapViewController.xib114
-rw-r--r--iosApp/iosApp/Map/UnitMapView.swift44
-rw-r--r--iosApp/iosApp/Session/AboutView.swift48
-rw-r--r--iosApp/iosApp/Session/AccountView.swift73
-rw-r--r--iosApp/iosApp/Session/AccountViewModel.swift29
-rw-r--r--iosApp/iosApp/Session/RootView.swift (renamed from iosApp/iosApp/Authentication/LoginView.swift)71
-rw-r--r--iosApp/iosApp/Session/RootViewModel.swift60
-rw-r--r--iosApp/iosApp/Session/UserInformationView.swift50
-rw-r--r--iosApp/iosApp/Shared/FlowCollector.swift35
-rw-r--r--iosApp/iosApp/Shared/HyperlinkText.swift103
-rw-r--r--iosApp/iosApp/Shared/Inject.swift34
-rw-r--r--iosApp/iosApp/Shared/LoadingView.swift28
-rw-r--r--iosApp/iosApp/Shared/MarkerTransformations.swift49
-rw-r--r--iosApp/iosApp/Shared/Resolver.swift45
-rw-r--r--iosApp/iosApp/Shared/SmallLabelStyle.swift32
-rw-r--r--iosApp/iosApp/Shared/Utils.swift48
-rw-r--r--iosApp/iosApp/Units/UnitsView.swift102
-rw-r--r--iosApp/iosApp/Units/UnitsViewModel.swift139
-rw-r--r--iosApp/iosApp/en.lproj/Localizable.strings68
-rw-r--r--iosApp/iosApp/es-419.lproj/Localizable.strings68
-rw-r--r--iosApp/iosApp/iOSApp.swift75
-rw-r--r--iosApp/iosApp/iosApp.entitlements8
-rw-r--r--shared/build.gradle.kts2
-rw-r--r--shared/src/androidMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/HttpClientProvider.kt10
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/Injectable.kt20
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/AttributesApi.kt3
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/CalendarsApi.kt3
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/CommandsApi.kt3
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/DevicesApi.kt3
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/DriversApi.kt3
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/EventsApi.kt3
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/GeofencesApi.kt3
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/GroupsApi.kt3
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/MaintenanceApi.kt3
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/NotificationsApi.kt3
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/PermissionsApi.kt3
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/PositionsApi.kt3
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/ReportsApi.kt3
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/ServerApi.kt3
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/SessionApi.kt15
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/StatisticsApi.kt3
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/UsersApi.kt3
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/ApiClient.kt35
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/HttpClientProvider.kt7
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/SessionManager.kt35
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/EventInformation.kt17
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/MapLayer.kt17
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/Marker.kt102
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/UnitInformation.kt54
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/CommandsController.kt17
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/GeofencesController.kt3
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/ReportController.kt15
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/SessionController.kt9
-rw-r--r--shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/UnitsController.kt3
-rw-r--r--shared/src/iosMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/HttpClientProvider.kt33
-rw-r--r--shared/src/iosMain/kotlin/mx/trackermap/TrackerMap/utils/MainScope.kt34
342 files changed, 32312 insertions, 326 deletions
diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/TrackerApp.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/TrackerApp.kt
index 1d181dd..aa92c91 100644
--- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/TrackerApp.kt
+++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/TrackerApp.kt
@@ -26,10 +26,8 @@ import mx.trackermap.TrackerMap.android.session.LoginViewModel
import mx.trackermap.TrackerMap.android.session.UserInformationViewModel
import mx.trackermap.TrackerMap.android.units.UnitsViewModel
import mx.trackermap.TrackerMap.client.apis.*
-import mx.trackermap.TrackerMap.controllers.GeofencesController
-import mx.trackermap.TrackerMap.controllers.ReportController
-import mx.trackermap.TrackerMap.controllers.SessionController
-import mx.trackermap.TrackerMap.controllers.UnitsController
+import mx.trackermap.TrackerMap.client.infrastructure.SessionManager
+import mx.trackermap.TrackerMap.controllers.*
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
import org.koin.androidx.viewmodel.dsl.viewModel
@@ -47,6 +45,9 @@ open class TrackerApp : Application() {
val appModule = module {
single { getString(R.string.default_server_url) }
+
+ factory { SessionManager(get()) }
+
factory { SessionApi(get()) }
factory { UsersApi(get()) }
factory { DevicesApi(get()) }
@@ -59,10 +60,11 @@ open class TrackerApp : Application() {
factory { UnitsController(get(), get()) }
factory { GeofencesController(get()) }
factory { ReportController(get(), get()) }
+ factory { CommandsController(get()) }
viewModel { LoginViewModel() }
viewModel { UnitInformationViewModel(get()) }
- viewModel { UnitCommandsViewModel(get()) }
+ viewModel { UnitCommandsViewModel() }
viewModel { UnitsViewModel(get()) }
viewModel { UnitReportsViewModel(get()) }
viewModel { UserInformationViewModel() }
diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/commands/UnitCommandsViewModel.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/commands/UnitCommandsViewModel.kt
index 3bb7f11..d1b1e69 100644
--- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/commands/UnitCommandsViewModel.kt
+++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/commands/UnitCommandsViewModel.kt
@@ -23,14 +23,15 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.launch
-import mx.trackermap.TrackerMap.client.apis.CommandsApi
import mx.trackermap.TrackerMap.client.models.Command
+import mx.trackermap.TrackerMap.controllers.CommandsController
import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
@DelicateCoroutinesApi
-class UnitCommandsViewModel(
- private val commandsApi: CommandsApi
-) : ViewModel(), KoinComponent {
+class UnitCommandsViewModel : ViewModel(), KoinComponent {
+
+ private val commandsController: CommandsController by inject()
var commands = MutableLiveData<List<Command>>()
private var selectedCommand: Command? = null
@@ -38,9 +39,11 @@ class UnitCommandsViewModel(
fun fetchCommands(deviceId: Int?) {
this.deviceId = deviceId
- viewModelScope.launch {
- val commands = commandsApi.commandsGet(deviceId = deviceId)
- this@UnitCommandsViewModel.commands.value = commands.toList()
+ deviceId?.let {
+ viewModelScope.launch {
+ val commands = commandsController.fetchCommands(it)
+ this@UnitCommandsViewModel.commands.value = commands.toList()
+ }
}
}
@@ -59,9 +62,11 @@ class UnitCommandsViewModel(
}
Log.d("UnitCommandsVM", "Sending command - $selectedCommand")
- viewModelScope.launch {
- val command = commandsApi.commandsSendPost(selectedCommand!!)
- Log.d("UnitCommandsVM", "Command sent - $command")
+ selectedCommand?.let {
+ viewModelScope.launch {
+ val command = commandsController.sendCommand(it)
+ Log.d("UnitCommandsVM", "Command sent - $command")
+ }
}
}
} \ No newline at end of file
diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/reports/UnitReportsFragment.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/reports/UnitReportsFragment.kt
index 22c75f4..60ad531 100644
--- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/reports/UnitReportsFragment.kt
+++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/reports/UnitReportsFragment.kt
@@ -149,16 +149,16 @@ class UnitReportsFragment : Fragment() {
when (report) {
is ReportController.Report.PositionsReport -> {
mapFragment.display(unitReportsViewModel.geofences.value!!)
- mapFragment.display(report.positions, isReport = true, center = true)
+ mapFragment.display(report.positions.toTypedArray(), isReport = true, center = true)
showMap(true)
}
is ReportController.Report.EventsReport -> {
- display(report.events)
+ display(report.events.toTypedArray())
showMap(false)
}
is ReportController.Report.StopsReport -> {
mapFragment.display(unitReportsViewModel.geofences.value!!)
- mapFragment.display(report.stops)
+ mapFragment.display(report.stops.toTypedArray())
showMap(true)
}
is ReportController.Report.XlsxReport -> {
@@ -232,7 +232,7 @@ class UnitReportsFragment : Fragment() {
binding.reportsMapContainer.visibility = View.GONE
binding.eventsTable.removeViews(1, max(0, binding.eventsTable.childCount - 1))
- val context = context!!
+ val context = requireContext()
events.forEach { event ->
val layoutParams = TableRow.LayoutParams()
layoutParams.setMargins(
diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/MapFragment.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/MapFragment.kt
index a76ebde..b04bfbc 100644
--- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/MapFragment.kt
+++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/MapFragment.kt
@@ -38,8 +38,8 @@ import mx.trackermap.TrackerMap.android.R
import mx.trackermap.TrackerMap.android.shared.MarkerTransformations
import mx.trackermap.TrackerMap.client.models.Geofence
import mx.trackermap.TrackerMap.client.models.MapLayer
+import mx.trackermap.TrackerMap.client.models.Marker
import mx.trackermap.TrackerMap.utils.MapCalculus
-import mx.trackermap.TrackerMap.utils.MarkerType
typealias SetupCallback = () -> Unit
typealias MarkerCallback = (Int?) -> Unit
@@ -48,14 +48,6 @@ open class MapFragment : GlobeMapFragment() {
private var loader: QuadImageLoader? = null
- data class Marker(
- val id: Int,
- val name: String,
- val latitude: Double,
- val longitude: Double,
- val type: MarkerType = MarkerType.DEFAULT
- )
-
var hasStarted: Boolean = false
val setupCallbacks = mutableListOf<SetupCallback>()
var markerCallback: MarkerCallback? = null
@@ -185,9 +177,9 @@ open class MapFragment : GlobeMapFragment() {
}.toTypedArray()
val fontSize = context?.resources?.getDimensionPixelSize(R.dimen.marker_label_text_size)
- val colorReport = ContextCompat.getColor(context!!, R.color.colorReport)
- val colorLabel = ContextCompat.getColor(context!!, R.color.colorMarkerLabel)
- val colorLabelOutline = ContextCompat.getColor(context!!, R.color.colorMarkerLabelOutline)
+ val colorReport = ContextCompat.getColor(requireContext(), R.color.colorReport)
+ val colorLabel = ContextCompat.getColor(requireContext(), R.color.colorMarkerLabel)
+ val colorLabelOutline = ContextCompat.getColor(requireContext(), R.color.colorMarkerLabelOutline)
val vectorWidth = context?.resources?.getDimensionPixelSize(R.dimen.report_label_width)?.toFloat()
val vectorInfo = VectorInfo()
@@ -210,9 +202,9 @@ open class MapFragment : GlobeMapFragment() {
screenMarker.image = if (isReport) {
// For reports, position, start and end, icons must be different
when (i) {
- 0 -> getIcon(MarkerType.REPORT_START)
- markers.size - 1 -> getIcon(MarkerType.REPORT_END)
- else -> getIcon(MarkerType.REPORT_POSITION)
+ 0 -> getIcon(Marker.Type.REPORT_START)
+ markers.size - 1 -> getIcon(Marker.Type.REPORT_END)
+ else -> getIcon(Marker.Type.REPORT_POSITION)
}
} else getIcon(marker.type)
screenMarker.size = if (isReport) {
@@ -291,9 +283,9 @@ open class MapFragment : GlobeMapFragment() {
clear(true)
val fontSize = context?.resources?.getDimensionPixelSize(R.dimen.marker_label_text_size)
- val colorFill = ContextCompat.getColor(context!!, R.color.colorGeofence)
- val colorLabel = ContextCompat.getColor(context!!, R.color.colorGeofenceLabel)
- val colorLabelOutline = ContextCompat.getColor(context!!, R.color.colorMarkerLabelOutline)
+ val colorFill = ContextCompat.getColor(requireContext(), R.color.colorGeofence)
+ val colorLabel = ContextCompat.getColor(requireContext(), R.color.colorGeofenceLabel)
+ val colorLabelOutline = ContextCompat.getColor(requireContext(), R.color.colorMarkerLabelOutline)
val vectorWidth = context?.resources?.getDimensionPixelSize(R.dimen.geofence_label_width)?.toFloat()
val vectorInfo = VectorInfo()
@@ -428,10 +420,10 @@ open class MapFragment : GlobeMapFragment() {
}
}
- private fun getIcon(markerType: MarkerType): Bitmap {
+ private fun getIcon(markerType: Marker.Type): Bitmap {
return ResourcesCompat.getDrawable(
- activity!!.resources,
+ requireActivity().resources,
MarkerTransformations.markerTypeToResourceId(markerType),
- activity!!.theme)!!.toBitmap(144, 144)
+ requireActivity().theme)!!.toBitmap(144, 144)
}
} \ No newline at end of file
diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/MapWrapperFragment.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/MapWrapperFragment.kt
index c9eab70..aa2faf9 100644
--- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/MapWrapperFragment.kt
+++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/MapWrapperFragment.kt
@@ -165,7 +165,7 @@ class MapWrapperFragment: Fragment() {
Log.d("MapWrapperFragment", "Displaying positions: $positions")
mapFragment.display(
- positions.mapNotNull(MarkerTransformations::positionToMarker).toTypedArray(),
+ positions.mapNotNull(Marker::fromPosition).toTypedArray(),
isReport = isReport,
center = center
)
@@ -181,7 +181,7 @@ class MapWrapperFragment: Fragment() {
Log.d("MapWrapperFragment", "Displaying units: $units")
mapFragment.display(
- units.mapNotNull(MarkerTransformations::unitToMarker).toTypedArray(),
+ units.mapNotNull(Marker::fromUnit).toTypedArray(),
isReport = isReport,
center = center
)
@@ -197,7 +197,7 @@ class MapWrapperFragment: Fragment() {
Log.d("MapWrapperFragment", "Displaying stops: $stops")
mapFragment.display(
- stops.mapNotNull(MarkerTransformations::stopToMarker).toTypedArray(),
+ stops.mapNotNull(Marker::fromStop).toTypedArray(),
isReport = true
)
} else {
diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/shared/MarkerTransformations.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/shared/MarkerTransformations.kt
index 242cccf..1c4ad3b 100644
--- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/shared/MarkerTransformations.kt
+++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/shared/MarkerTransformations.kt
@@ -17,107 +17,34 @@
*/
package mx.trackermap.TrackerMap.android.shared
-import android.util.Log
import mx.trackermap.TrackerMap.android.R
-import mx.trackermap.TrackerMap.android.map.MapFragment
-import mx.trackermap.TrackerMap.client.models.Position
-import mx.trackermap.TrackerMap.client.models.Stop
-import mx.trackermap.TrackerMap.client.models.UnitInformation
-import mx.trackermap.TrackerMap.utils.MarkerType
+import mx.trackermap.TrackerMap.client.models.Marker
object MarkerTransformations {
- fun unitToMarker(unit: UnitInformation): MapFragment.Marker? {
- if (unit.position == null || unit.position!!.latitude == null || unit.position!!.longitude == null) {
- return null
- }
-
- return MapFragment.Marker(
- unit.position!!.id!!,
- unit.device.name,
- unit.position!!.latitude!!,
- unit.position!!.longitude!!,
- categoryToMarkerType(unit.device.category ?: "")
- )
- }
-
- fun positionToMarker(position: Position): MapFragment.Marker? {
- if (position.latitude == null || position.longitude == null) {
- return null
- }
-
- return MapFragment.Marker(
- position.id!!,
- "",
- position.latitude!!,
- position.longitude!!
- )
- }
-
- fun stopToMarker(stop: Stop): MapFragment.Marker? {
- Log.d("MarkerTransformations", "stopToMarker($stop)")
- if (stop.latitude == null || stop.longitude == null) {
- return null
- }
-
- return MapFragment.Marker(
- stop.deviceId!!,
- stop.deviceName!!,
- stop.latitude!!,
- stop.longitude!!
- )
- }
-
- private fun categoryToMarkerType(category: String?): MarkerType {
- return when (category?.lowercase()) {
- "animal" -> MarkerType.ANIMAL
- "backhoe" -> MarkerType.BACKHOE
- "bicycle" -> MarkerType.BICYCLE
- "boat" -> MarkerType.BOAT
- "bus" -> MarkerType.BUS
- "car" -> MarkerType.CAR
- "crane" -> MarkerType.CRANE
- "helicopter" -> MarkerType.HELICOPTER
- "motorcycle" -> MarkerType.MOTORCYCLE
- "offroad" -> MarkerType.OFFROAD
- "person" -> MarkerType.PERSON
- "pickup" -> MarkerType.PICKUP
- "plane" -> MarkerType.PLANE
- "scooter" -> MarkerType.SCOOTER
- "ship" -> MarkerType.SHIP
- "tractor" -> MarkerType.TRACTOR
- "train" -> MarkerType.TRAIN
- "tram" -> MarkerType.TRAM
- "trolleybus" -> MarkerType.TROLLEYBUS
- "truck" -> MarkerType.TRUCK
- "van" -> MarkerType.VAN
- else -> MarkerType.DEFAULT
- }
- }
-
- fun markerTypeToResourceId(markerType: MarkerType): Int {
+ fun markerTypeToResourceId(markerType: Marker.Type): Int {
return when (markerType) {
- MarkerType.ANIMAL -> R.drawable.map_animal
- MarkerType.BACKHOE -> R.drawable.map_backhoe
- MarkerType.BICYCLE -> R.drawable.map_bicycle
- MarkerType.BOAT -> R.drawable.map_boat
- MarkerType.BUS -> R.drawable.map_bus
- MarkerType.CAR -> R.drawable.map_car
- MarkerType.CRANE -> R.drawable.map_crane
- MarkerType.DEFAULT -> R.drawable.map_default
- MarkerType.HELICOPTER -> R.drawable.map_helicopter
- MarkerType.MOTORCYCLE -> R.drawable.map_motorcycle
- MarkerType.OFFROAD -> R.drawable.map_offroad
- MarkerType.PERSON -> R.drawable.map_person
- MarkerType.PICKUP -> R.drawable.map_pickup
- MarkerType.PLANE -> R.drawable.map_plane
- MarkerType.SCOOTER -> R.drawable.map_scooter
- MarkerType.SHIP -> R.drawable.map_ship
- MarkerType.TRACTOR -> R.drawable.map_tractor
- MarkerType.TRAIN -> R.drawable.map_train
- MarkerType.TRAM -> R.drawable.map_tram
- MarkerType.TROLLEYBUS -> R.drawable.map_trolleybus
- MarkerType.TRUCK -> R.drawable.map_truck
- MarkerType.VAN -> R.drawable.map_van
+ Marker.Type.ANIMAL -> R.drawable.map_animal
+ Marker.Type.BACKHOE -> R.drawable.map_backhoe
+ Marker.Type.BICYCLE -> R.drawable.map_bicycle
+ Marker.Type.BOAT -> R.drawable.map_boat
+ Marker.Type.BUS -> R.drawable.map_bus
+ Marker.Type.CAR -> R.drawable.map_car
+ Marker.Type.CRANE -> R.drawable.map_crane
+ Marker.Type.DEFAULT -> R.drawable.map_default
+ Marker.Type.HELICOPTER -> R.drawable.map_helicopter
+ Marker.Type.MOTORCYCLE -> R.drawable.map_motorcycle
+ Marker.Type.OFFROAD -> R.drawable.map_offroad
+ Marker.Type.PERSON -> R.drawable.map_person
+ Marker.Type.PICKUP -> R.drawable.map_pickup
+ Marker.Type.PLANE -> R.drawable.map_plane
+ Marker.Type.SCOOTER -> R.drawable.map_scooter
+ Marker.Type.SHIP -> R.drawable.map_ship
+ Marker.Type.TRACTOR -> R.drawable.map_tractor
+ Marker.Type.TRAIN -> R.drawable.map_train
+ Marker.Type.TRAM -> R.drawable.map_tram
+ Marker.Type.TROLLEYBUS -> R.drawable.map_trolleybus
+ Marker.Type.TRUCK -> R.drawable.map_truck
+ Marker.Type.VAN -> R.drawable.map_van
MarkerType.REPORT_POSITION -> R.drawable.map_report_position
MarkerType.REPORT_START -> R.drawable.map_report_start
@@ -154,10 +81,10 @@ object MarkerTransformations {
}
fun categoryToResourceId(category: String?): Int {
- return markerTypeToResourceId(categoryToMarkerType(category))
+ return markerTypeToResourceId(Marker.categoryToMarkerType(category))
}
fun categoryToStringId(category: String?): Int {
- return markerTypeToResourceId(categoryToMarkerType(category))
+ return markerTypeToStringId(Marker.categoryToMarkerType(category))
}
} \ No newline at end of file
diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/shared/UnitRenderData.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/shared/UnitRenderData.kt
index 123e1ab..9a9f85c 100644
--- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/shared/UnitRenderData.kt
+++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/shared/UnitRenderData.kt
@@ -89,43 +89,41 @@ class UnitRenderData {
}
}
- statusIcon.visibility = View.GONE
- engineStopIcon.visibility = View.GONE
-
- unit.position?.let { position ->
- /* Status icon */
- statusIcon.visibility = View.VISIBLE
- position.speed?.let { speed ->
- if (speed >= 2) {
- statusIcon.setColorFilter(
- ContextCompat.getColor(context, R.color.colorOnline)
- )
- } else {
- statusIcon.setColorFilter(
- ContextCompat.getColor(context, R.color.colorOffline)
- )
- }
- } ?: run {
+ /* Status icon */
+ when (unit.getStatus()) {
+ UnitInformation.Status.ONLINE -> {
+ statusIcon.setColorFilter(
+ ContextCompat.getColor(context, R.color.colorOnline)
+ )
+ }
+ UnitInformation.Status.OFFLINE -> {
+ statusIcon.setColorFilter(
+ ContextCompat.getColor(context, R.color.colorOffline)
+ )
+ }
+ else -> {
statusIcon.setColorFilter(Color.GRAY)
}
+ }
- /* Engine stop */
- val attributes = position.attributes
- if (attributes["out1"].toString() != "null") {
+ /* Engine stop */
+ when(unit.getEngineStop()) {
+ UnitInformation.EngineStop.ON -> {
engineStopIcon.visibility = View.VISIBLE
- engineStopIcon.setImageResource(
- when (attributes["out1"].toString()) {
- "true" -> R.drawable.device_unlocked
- "false" -> R.drawable.device_locked
- else -> R.drawable.device_locked
- }
- )
- engineStopIcon.contentDescription = when (attributes["out1"].toString()) {
- "true" -> context.getString(R.string.unit_lock_on)
- "false" -> context.getString(R.string.unit_lock_off)
- else -> context.getString(R.string.unit_lock_on)
- }
+ engineStopIcon.setImageResource(R.drawable.device_unlocked)
+ engineStopIcon.contentDescription = context.getString(R.string.unit_lock_on)
+ }
+ UnitInformation.EngineStop.OFF -> {
+ engineStopIcon.visibility = View.VISIBLE
+ engineStopIcon.setImageResource(R.drawable.device_locked)
+ engineStopIcon.contentDescription = context.getString(R.string.unit_lock_off)
}
+ UnitInformation.EngineStop.UNKNOWN -> {
+ engineStopIcon.visibility = View.GONE
+ }
+ }
+
+ unit.position?.let { position ->
/* Speed */
position.speed?.let { speed ->
@@ -150,7 +148,7 @@ class UnitRenderData {
}
/* Hourmeter */
- position.attributes["hours"]?.longOrNull?.let {
+ unit.getHourmeter()?.let {
if (it > 0) {
details.add(
Triple(
diff --git a/iosApp/.gitignore b/iosApp/.gitignore
new file mode 100644
index 0000000..cfbc7b3
--- /dev/null
+++ b/iosApp/.gitignore
@@ -0,0 +1,95 @@
+# Xcode
+#
+# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
+
+## User settings
+xcuserdata/
+**/xcuserdata/
+
+## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
+*.xcscmblueprint
+*.xccheckout
+
+## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
+build/
+DerivedData/
+*.moved-aside
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+
+## Obj-C/Swift specific
+*.hmap
+
+## App packaging
+*.ipa
+*.dSYM.zip
+*.dSYM
+
+## Playgrounds
+timeline.xctimeline
+playground.xcworkspace
+
+# Swift Package Manager
+#
+# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
+# Packages/
+# Package.pins
+# Package.resolved
+# *.xcodeproj
+#
+# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
+# hence it is not needed unless you have added a package configuration file to your project
+# .swiftpm
+
+.build/
+
+# CocoaPods
+#
+# We recommend against adding the Pods directory to your .gitignore. However
+# you should judge for yourself, the pros and cons are mentioned at:
+# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
+#
+# Pods/
+#
+# Add this line if you want to avoid checking in source code from the Xcode workspace
+# *.xcworkspace
+
+# Carthage
+#
+# Add this line if you want to avoid checking in source code from Carthage dependencies.
+# Carthage/Checkouts
+
+Carthage/Build/
+
+# Accio dependency management
+Dependencies/
+.accio/
+
+# fastlane
+#
+# It is recommended to not store the screenshots in the git repo.
+# Instead, use fastlane to re-generate the screenshots whenever they are needed.
+# For more information about the recommended setup visit:
+# https://docs.fastlane.tools/best-practices/source-control/#source-control
+
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots/**/*.png
+fastlane/test_output
+
+# Code Injection
+#
+# After new code Injection tools there's a generated folder /iOSInjectionProject
+# https://github.com/johnno1962/injectionforxcode
+
+iOSInjectionProject/
+
+# Firebase
+
+GoogleService-Info.plist
diff --git a/iosApp/Localizable.strings b/iosApp/Localizable.strings
deleted file mode 100644
index 754e4ea..0000000
--- a/iosApp/Localizable.strings
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- Localizable.strings
- iosApp
-
- Created by Iván on 23/01/22.
- Copyright © 2022 orgName. All rights reserved.
-*/
-"app-name" = "TrackerMap";
-"username" = "Username";
-"password" = "Password";
-"server-url" = "Server URL";
-"login" = "Login";
diff --git a/iosApp/WhirlyGlobe.xcframework/Info.plist b/iosApp/WhirlyGlobe.xcframework/Info.plist
new file mode 100644
index 0000000..4528555
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/Info.plist
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>AvailableLibraries</key>
+ <array>
+ <dict>
+ <key>LibraryIdentifier</key>
+ <string>ios-arm64_x86_64-simulator</string>
+ <key>LibraryPath</key>
+ <string>WhirlyGlobe.framework</string>
+ <key>SupportedArchitectures</key>
+ <array>
+ <string>arm64</string>
+ <string>x86_64</string>
+ </array>
+ <key>SupportedPlatform</key>
+ <string>ios</string>
+ <key>SupportedPlatformVariant</key>
+ <string>simulator</string>
+ </dict>
+ <dict>
+ <key>LibraryIdentifier</key>
+ <string>ios-arm64</string>
+ <key>LibraryPath</key>
+ <string>WhirlyGlobe.framework</string>
+ <key>SupportedArchitectures</key>
+ <array>
+ <string>arm64</string>
+ </array>
+ <key>SupportedPlatform</key>
+ <string>ios</string>
+ </dict>
+ </array>
+ <key>CFBundlePackageType</key>
+ <string>XFWK</string>
+ <key>XCFrameworkFormatVersion</key>
+ <string>1.0</string>
+</dict>
+</plist>
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Config-ac.h.in b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Config-ac.h.in
new file mode 100644
index 0000000..ac3ba0b
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Config-ac.h.in
@@ -0,0 +1,91 @@
+/* include/GeographicLib/Config-ac.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* major version number */
+#undef GEOGRAPHICLIB_VERSION_MAJOR
+
+/* minor version number */
+#undef GEOGRAPHICLIB_VERSION_MINOR
+
+/* patch number */
+#undef GEOGRAPHICLIB_VERSION_PATCH
+
+/* define if the compiler supports basic C++11 syntax */
+#undef HAVE_CXX11
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if the system has the type `long double'. */
+#undef HAVE_LONG_DOUBLE
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#undef LT_OBJDIR
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+# undef WORDS_BIGENDIAN
+# endif
+#endif
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GeoJSONSource.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GeoJSONSource.h
new file mode 100644
index 0000000..ff80172
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GeoJSONSource.h
@@ -0,0 +1,40 @@
+/* GeoJSONSource.mm
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Ranen Ghosh on 2016-11-18.
+ * Copyright 2016-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyBaseViewController.h>
+
+#define GEOJSON_MAX_POINTS 4096
+
+/**
+ This class will read GeoJSON via URL with an associated Styled Layer Descriptor via URL. It will then
+ parse both of them and apply the SLD style to the GeoJSON data. This results in visual data in
+ much the same way as loading vector tiles would.
+ */
+@interface GeoJSONSource : NSObject
+
+- (id _Nullable)initWithViewC:(NSObject<MaplyRenderControllerProtocol> * _Nonnull)baseVC GeoJSONURL:(NSURL * _Nonnull)geoJSONURL sldURL:(NSURL * _Nonnull)sldURL relativeDrawPriority:(int)relativeDrawPriority ;
+
+- (void)startParseWithCompletion:(nonnull void (^)(void)) completionBlock;
+
+- (void)startParse;
+
+@property (nonatomic, readonly) bool loaded;
+@property (nonatomic, assign) bool enabled;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GeographicLib_ObjC.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GeographicLib_ObjC.h
new file mode 100644
index 0000000..22bd915
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GeographicLib_ObjC.h
@@ -0,0 +1,100 @@
+//
+// geowrap.h
+// WhirlyGlobeLib
+//
+// Created by Tim Sylvester on 12/14/20.
+// Copyright 2020 mousebird consulting. All rights reserved.
+//
+
+#ifndef GeographicLib_Wrapper_h
+#define GeographicLib_Wrapper_h
+
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+typedef struct GeoLibInv_t {
+ double distance; // meters
+ double azimuth1; // radians
+ double azimuth2; // radians
+} GeoLibInv;
+
+typedef struct GeoLibInt_t {
+ MaplyCoordinateD intersection;
+ bool intersects;
+} GeoLibInt;
+
+typedef struct GeoLibIntPair_t {
+ MaplyCoordinateD intersections[2];
+ double distances[2];
+ unsigned int count;
+} GeoLibIntPair;
+
+typedef struct GeoLibOrthoDist_t {
+ double downtrackDistance;
+ double crosstrackDistance;
+ double segmentLength;
+} GeoLibOrthoDist;
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+/// Solve the direct geodesic problem where the length of the geodesic is specified in terms of distance.
+/// azimuth in radians, distance in meters
+MaplyCoordinate GeoLibCalcDirectF(MaplyCoordinate origin, double azimuth, double distance);
+MaplyCoordinateD GeoLibCalcDirectD(MaplyCoordinateD origin, double azimuth, double distance);
+
+// Solve the inverse geodesic problem
+GeoLibInv GeoLibCalcInverseF(MaplyCoordinate p1, MaplyCoordinate p2);
+GeoLibInv GeoLibCalcInverseD(MaplyCoordinateD p1, MaplyCoordinateD p2);
+
+// Test for a point lying inside the specified polygon
+bool MaplyCoordinateInPolygon(MaplyCoordinate p, const MaplyCoordinate polygon[], unsigned count);
+bool MaplyCoordinateDInPolygon(MaplyCoordinateD p, const MaplyCoordinate polygon[], unsigned count);
+bool MaplyCoordinateInPolygonD(MaplyCoordinate p, const MaplyCoordinateD polygon[], unsigned count);
+bool MaplyCoordinateDInPolygonD(MaplyCoordinateD p, const MaplyCoordinateD polygon[], unsigned count);
+
+double GeoLibDistanceD(MaplyCoordinateD startPt, MaplyCoordinateD endPt);
+
+// Test for a segment intersecting a polygon.
+// Note that if the line is completely within the polygon the result is false.
+bool GeoLibLineDIntersectsPolygonD(MaplyCoordinateD startPt, MaplyCoordinateD endPt, const MaplyCoordinateD[], unsigned count);
+
+// Compute the intersection point of two geodesic segments
+GeoLibInt GeoLibIntersectD(MaplyCoordinateD a, MaplyCoordinateD b, MaplyCoordinateD c, MaplyCoordinateD d);
+
+// Determine where a great circle intersects a small circle
+GeoLibIntPair GeoLibLineDIntersectCircleD(MaplyCoordinateD startPt, MaplyCoordinateD endPt, MaplyCoordinateD center, double radiusMeters);
+
+// Determine whether there's an intersection without bothering to compute its location
+bool GeoLibLineDIntersectsCircleD(MaplyCoordinateD startPt, MaplyCoordinateD endPt, MaplyCoordinateD center, double radiusMeters);
+
+// Compute the orthogonal distances for a point.
+//
+// Given a segment and a point, find the perpendicular intersection point (the closest point along the
+// segment) and compute the distance from that point to the segment starting point (down-track) and
+// to the specified point (cross-track).
+//
+// negative down-track distance C
+// v | <- negative cross-track distance
+// - - - - - A--------B
+// | | <- positive cross-track distance
+// C C
+// ----
+// ^ positive down-track-distance
+//
+// If the point lies "before" the segment start point, the down-track distance will be negative.
+// If the point lies "after" the segment end point, the down-track distance will be greater than the segment length.
+// If the point lies to the right of the segment, the cross-track distance will be positive.
+// If the point lies to the left of the segment, the cross-track distance will be negative.
+GeoLibOrthoDist GeoLibOrthoDistD(MaplyCoordinateD a, MaplyCoordinateD b, MaplyCoordinateD c);
+
+// Generate points along an arc
+double GeoLibSampleArcD(MaplyCoordinateD center, double radiusMeters,
+ double beginAzimuthRad, double endAziumthRad, bool clockwise,
+ MaplyCoordinateD points[], unsigned count);
+
+#if defined __cplusplus
+} // extern "C"
+#endif
+
+#endif /* GeographicLib_Wrapper_h */
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeDoubleTapDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeDoubleTapDelegate.h
new file mode 100644
index 0000000..ea1b934
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeDoubleTapDelegate.h
@@ -0,0 +1,34 @@
+/* GlobeDoubleTapDelegate.h
+ *
+ * Created by Steve Gifford on 2/7/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@interface WhirlyGlobeDoubleTapDelegate : NSObject<UIGestureRecognizerDelegate>
+
+@property (nonatomic,weak) UIGestureRecognizer *gestureRecognizer;
+
+// How much we zoom in by
+@property (nonatomic) float zoomTapFactor;
+
+// How long the zoom animation takes
+@property (nonatomic) float zoomAnimationDuration;
+
+/// Zoom limits
+@property (nonatomic) float minZoom,maxZoom;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeDoubleTapDragDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeDoubleTapDragDelegate.h
new file mode 100644
index 0000000..295fff8
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeDoubleTapDragDelegate.h
@@ -0,0 +1,33 @@
+/* GlobeDoubleTapDragDelegate.h
+ *
+ * Created by Steve Gifford on 2/7/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <WhirlyGlobe/GlobePinchDelegate.h>
+
+// Sent out when the double tap delegate takes control
+#define kGlobeDoubleTapDragDidStart @"WKGlobeDoubleTapDragStarted"
+// Sent out when the double tap delegate finished (but hands off to momentum)
+#define kGlobeDoubleTapDragDidEnd @"WKGlobeDoubleTapDragEnded"
+
+@interface WhirlyGlobeDoubleTapDragDelegate : NSObject<UIGestureRecognizerDelegate>
+
+@property (nonatomic,weak) UIGestureRecognizer *gestureRecognizer;
+
+/// Zoom limits
+@property (nonatomic) float minZoom,maxZoom;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobePanDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobePanDelegate.h
new file mode 100644
index 0000000..02d2249
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobePanDelegate.h
@@ -0,0 +1,48 @@
+/*
+ * GlobePanDelegate.h
+ * WhirlyGlobeApp
+ *
+ * Created by Stephen Gifford on 4/28/11.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+
+// Sent out when the pan delegate takes control
+#define kPanDelegateDidStart @"WKPanDelegateStarted"
+// Sent out when the pan delegate finished (but hands off to momentum)
+#define kPanDelegateDidEnd @"WKPanDelegateEnded"
+
+#define kPanDelegateMinTime 0.1
+
+// Custom pan gesture recognizer that plays well with scroll views.
+@interface MinDelayPanGestureRecognizer : UIPanGestureRecognizer {
+ // time of start of gesture
+ CFTimeInterval startTime;
+}
+
+- (void)forceEnd;
+
+@end
+
+
+// The pan delegate handles panning and rotates the globe accordingly
+@interface WhirlyGlobePanDelegate : NSObject<UIGestureRecognizerDelegate>
+
+@property(nonatomic,assign) bool northUp;
+
+@property (nonatomic,weak) UIGestureRecognizer *gestureRecognizer;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobePinchDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobePinchDelegate.h
new file mode 100644
index 0000000..35d40d8
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobePinchDelegate.h
@@ -0,0 +1,61 @@
+/* GlobePinchDelegate.h
+ * WhirlyGlobeLib
+ *
+ * Created by Steve Gifford on 8/22/12.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+
+@class WhirlyGlobeRotateDelegate;
+
+// Sent out when the pinch delegate takes control
+#define kPinchDelegateDidStart @"WKPinchDelegateStarted"
+// Sent out when the pinch delegate finished (but hands off to momentum)
+#define kPinchDelegateDidEnd @"WKPinchDelegateEnded"
+
+/** WhirlyGlobe Pinch Gesture Delegate
+ Responds to pinches on a UIView and manipulates the globe view
+ accordingly.
+ */
+@interface WhirlyGlobePinchDelegate : NSObject <UIGestureRecognizerDelegate>
+
+/// Min and max height to allow the user to change
+@property (nonatomic,assign) float minHeight,maxHeight;
+
+/// If set we're cooperating with the rotation delegate (HACK!)
+@property (nonatomic,weak) WhirlyGlobeRotateDelegate *rotateDelegate;
+
+/// If set, we'll zoom around the pinch, rather than the center of the view
+@property (nonatomic,assign) bool zoomAroundPinch;
+
+/// If set, we'll rotate around the pinch
+@property (nonatomic,assign) bool doRotation;
+
+/// If set, we'll pan around the center point. If not, we just zoom.
+@property (nonatomic,assign) bool allowPan;
+
+/// If set, we'll maintain north as up
+@property (nonatomic,assign) bool northUp;
+
+@property (nonatomic,weak) UIGestureRecognizer *gestureRecognizer;
+
+// If set, we'll keep track up rather than north up
+- (void)setTrackUp:(double)trackUp;
+
+// Turn track up back off
+- (void)clearTrackUp;
+
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeRotateDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeRotateDelegate.h
new file mode 100644
index 0000000..9e57c3a
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeRotateDelegate.h
@@ -0,0 +1,37 @@
+/* GlobeRotateDelegate.h
+ * WhirlyGlobeLib
+ *
+ * Created by Steve Gifford on 6/10/11.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+
+@protocol WhirlyKitViewWrapper;
+
+/** Rotation delegate
+ is for two fingered rotation around the axis at the middle of the screen
+ */
+@interface WhirlyGlobeRotateDelegate : NSObject <UIGestureRecognizerDelegate>
+
+/// If set, the rotation will occur around the center between the two fingers rather than the current viewpoint
+@property (nonatomic) bool rotateAroundCenter;
+
+/// Gesture recognizer attached to this delegate (or vice versa, actually)
+@property (nonatomic,weak) UIGestureRecognizer *gestureRecognizer;
+
+/// Can be called by a cooperating delegate (which is also messing with rotation) (HACK!)
+- (void)updateWithCenter:(CGPoint)center touch:(CGPoint)touch wrapView:(UIView<WhirlyKitViewWrapper> *)glView;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeTapDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeTapDelegate.h
new file mode 100644
index 0000000..61e3492
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeTapDelegate.h
@@ -0,0 +1,29 @@
+/* GlobeTapDelegate.h
+ * WhirlyGlobeLib
+ *
+ * Created by Steve Gifford on 2/3/11.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+
+/** WhirlyGlobe tap gesture delegate
+ responds to taps by blasting out a notification.
+ */
+@interface WhirlyGlobeTapDelegate : NSObject <UIGestureRecognizerDelegate>
+
+@property (nonatomic,weak) UIGestureRecognizer *gestureRecognizer;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeTiltDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeTiltDelegate.h
new file mode 100644
index 0000000..09cf3eb
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeTiltDelegate.h
@@ -0,0 +1,28 @@
+/* GlobeTiltDelegate.h
+ *
+ * Created by Stephen Gifford on 1/5/15.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/GlobePinchDelegate.h>
+
+// The tilt delegate handle the 3D camera tilt
+@interface WhirlyGlobeTiltDelegate : NSObject<UIGestureRecognizerDelegate>
+
+@property (nonatomic,weak) UIGestureRecognizer *gestureRecognizer;
+
+// Set so we can turn off the pinch delegate when we're working
+@property (nonatomic,weak) WhirlyGlobePinchDelegate *pinchDelegate;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeTwoFingerTapDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeTwoFingerTapDelegate.h
new file mode 100644
index 0000000..93bea5e
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/GlobeTwoFingerTapDelegate.h
@@ -0,0 +1,34 @@
+/* GlobeTwoFingerTapDelegate.h
+ *
+ * Created by Steve Gifford on 2/7/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@interface WhirlyGlobeTwoFingerTapDelegate : NSObject<UIGestureRecognizerDelegate>
+
+@property (nonatomic,weak) UIGestureRecognizer *gestureRecognizer;
+
+// How much we zoom in by
+@property (nonatomic) float zoomTapFactor;
+
+// How long the zoom animation takes
+@property (nonatomic) float zoomAnimationDuration;
+
+/// Zoom limits
+@property (nonatomic) float minZoom,maxZoom;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapboxVectorInterpreter.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapboxVectorInterpreter.h
new file mode 100644
index 0000000..25a3417
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapboxVectorInterpreter.h
@@ -0,0 +1,65 @@
+/*
+ * MapboxVectorTilesImageDelegate.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on January 24 2018
+ * Copyright 2011-2022 Saildrone
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#import <Foundation/Foundation.h>
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyVectorStyle.h>
+#import <WhirlyGlobe/MapboxVectorTiles.h>
+#import <WhirlyGlobe/MaplyQuadImageFrameLoader.h>
+
+@class MapboxVectorStyleSet;
+
+/**
+ An interpreter for Mapbox Vector Tiles.
+
+ This will turn vector tiles into images, visual objects, or a combination of the two. Loader interpreters like
+ this one can be used by Loaders that talk to ondevice objects (such as MBTiles files) or remote tile
+ sources.
+ */
+@interface MapboxVectorInterpreter : NSObject<MaplyLoaderInterpreter>
+
+/** This version of the init takes an image style set, a vector style set,
+ and an offline renderer to build the image tiles.
+
+ Image tiles will be used as a background and vectors put on top of them.
+ This is very nice for the globe, but requires specialized style sheets.
+ */
+- (instancetype _Nullable ) initWithImageStyle:(NSObject<MaplyVectorStyleDelegate> *__nonnull)imageStyle
+ offlineRender:(MaplyRenderController *__nonnull)renderControl
+ vectorStyle:(NSObject<MaplyVectorStyleDelegate> *__nonnull)vectorStyle
+ viewC:(NSObject<MaplyRenderControllerProtocol> *__nonnull)viewC;
+
+/** This version of the init builds visual features for vector tiles.
+
+ This interpreter can be used as overlay data or a full map, depending
+ on how your style is configured.
+ */
+- (instancetype __nullable) initWithVectorStyle:(NSObject<MaplyVectorStyleDelegate> *__nonnull)vectorStyle
+ viewC:(NSObject<MaplyRenderControllerProtocol> *__nonnull)viewC;
+
+/**
+ Set an optional list of unique features we'll filter on.
+ Any feature we want to pass through must have the given attribute name and one of the values.
+ */
+- (void)setUUIDName:(NSString * __nonnull)uuidName uuidValues:(NSArray<NSString *> * __nonnull)uuids;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapboxVectorStyleSet.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapboxVectorStyleSet.h
new file mode 100644
index 0000000..1f5c9ae
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapboxVectorStyleSet.h
@@ -0,0 +1,139 @@
+/*
+ * MapboxVectorStyleSet.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 2/16/15.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+#import <WhirlyGlobe/MaplyVectorStyle.h>
+#import <WhirlyGlobe/MapboxVectorTiles.h>
+
+typedef NS_ENUM(NSUInteger,MapboxLayerType) {
+ MapboxLayerTypeBackground,
+ MapboxLayerTypeCircle,
+ MapboxLayerTypeFill,
+ MapboxLayerTypeLine,
+ MapboxLayerTypeRaster,
+ MapboxLayerTypeSymbol,
+ MapboxLayerTypeUnknown
+};
+
+/**
+ A single entry in the legend array returned by
+ */
+@interface MaplyLegendEntry : NSObject
+
+/// Name of this entry
+@property (nonatomic,nonnull) NSString *name;
+
+/// Image for this entry, if this is a single entry
+@property (nonatomic,nullable) UIImage *image;
+
+/// Array of entries if this is a group
+@property (nonatomic,nullable) NSMutableArray<MaplyLegendEntry *> *entries;
+
+@end
+
+/** @brief The Mapbox Vector Style Set parses Mapbox GL Style sheets and turns them into Maply compatible styles.
+ @details A style delegate is required by the Mapnik parser to build geometry out of Mapnik vector tiles. This style delegate can read a Mapbox GL Style sheet and produce compatible styles.
+ */
+@interface MapboxVectorStyleSet : NSObject<MaplyVectorStyleDelegate>
+
+/// @brief Initialize with the style dictionary alreayd parsed from JSON
+/// @details We'll parse the style JSON passed in and return nil on failure.
+/// @details The optional filter can be used to reject layers we won't use
+- (id __nullable)initWithDict:(NSDictionary * __nonnull)styleDict
+ settings:(MaplyVectorStyleSettings * __nonnull)settings
+ viewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+/// @brief Initialize with the style JSON and the view controller
+/// @details We'll parse the style JSON passed in and return nil on failure.
+/// @details The optional filter can be used to reject layers we won't use
+- (id __nullable)initWithJSON:(NSData * __nonnull)styleJSON
+ settings:(MaplyVectorStyleSettings * __nonnull)settings
+ viewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+/// @brief Where we can fetch the sprites
+@property (nonatomic, strong, nullable) NSString *spriteURL;
+
+/// Tile sources
+@property (nonatomic, strong, nonnull) NSArray *sources;
+
+/// All the layer names
+@property (nonatomic) NSArray<NSString *> * __nonnull layerNames;
+
+/// Type of the given layer
+- (MapboxLayerType) layerType:(NSString * __nonnull)layerName;
+
+/// Add the sprint sheet for use in symbols. Return false on failures.
+- (bool)addSprites:(NSDictionary * __nonnull)spriteDict image:(UIImage * __nonnull)image;
+
+/**
+ This method will poke around in the given layer to determine a distinc color for it.
+ For circle layers, you get the circle color. For fill and line layers, it's the paint color.
+ For symbols, you get the text color.
+ This is useful for visualizing layers, it has nothing to do with rendering them.
+ */
+- (UIColor * __nullable) colorForLayer:(NSString *__nonnull)layerName;
+
+/// If there is a background layer, calculate the color for a given zoom level.
+/// Otherwise return nil
+- (UIColor * __nullable)backgroundColorForZoom:(double)zoom;
+
+/// Make a layer visible/invisible
+- (void)setLayerVisible:(NSString *__nonnull)layerName visible:(bool)visible;
+
+/// Slot for continuous zoom levels. If not set, we won't use those.
+- (void)setZoomSlot:(int)zoomSlot;
+
+/**
+ Returns a dictionary containing a flexible legend for the layers contained in this style.
+ Each layer is rendered as a representative image at the given size.
+ Layer names that start with the same "<name>_" will be grouped together in the hiearchy if
+ the group parameter is set. Otherwise they'll be flat.
+ */
+- (NSArray<MaplyLegendEntry *> * __nonnull)layerLegend:(CGSize)imageSize group:(bool)useGroups;
+
+@property (nonatomic, weak, nullable) NSObject<MaplyRenderControllerProtocol> *viewC;
+
+@end
+
+typedef enum : NSUInteger {
+ MapboxSourceVector,
+ MapboxSourceRaster,
+ // TODO: Support the rest of these eventually
+} MapboxSourceType;
+
+// Sources are called out individually
+@interface MaplyMapboxVectorStyleSource : NSObject
+
+// Name of the source
+@property (nonatomic,nullable) NSString *name;
+
+// Vector and raster sources supported for now
+@property (nonatomic) MapboxSourceType type;
+
+// TileJSON URL, if present
+@property (nonatomic,nullable) NSString *url;
+
+// If the TileJSON spec is inline, this is it
+@property (nonatomic,nullable) NSDictionary *tileSpec;
+
+// Initialize with the entry in the style file
+- (id __nullable)initWithName:(NSString *__nonnull)name styleEntry:(NSDictionary * __nonnull)styleEntry styleSet:(MapboxVectorStyleSet * __nonnull)styleSet viewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapboxVectorTiles.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapboxVectorTiles.h
new file mode 100644
index 0000000..7b4cbef
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapboxVectorTiles.h
@@ -0,0 +1,65 @@
+/*
+ * MapboxVectorTiles.h
+ * WhirlyGlobeLib
+ *
+ * Created by Steve Gifford on 4/10/19.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyVectorTileStyle.h>
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyVectorStyle.h>
+
+typedef NS_ENUM(NSInteger,MapboxGeometryType)
+{
+ GeomTypeUnknown = 0,
+ GeomTypePoint = 1,
+ GeomTypeLineString = 2,
+ GeomTypePolygon = 3
+};
+
+
+/**
+ Container for data parsed out of a Mapbox Vector Tile stream.
+
+ This holds the parsed data as well as post-constructed data. You will likely be handed one of these
+ if you see it at all. There are few cases where you might construct one.
+ */
+@interface MaplyVectorTileData : NSObject
+
+/// Initialize with tile and bounds, both local coordinates and geographic
+- (id)initWithID:(MaplyTileID)tileID bbox:(MaplyBoundingBoxD)bbox geoBBox:(MaplyBoundingBoxD)geoBBox;
+
+/// Tile ID for the tile being built
+@property (readonly) MaplyTileID tileID;
+
+/// Bounding box in local coordinates
+@property (readonly) MaplyBoundingBoxD bounds;
+
+/// Bounding box in geographic
+@property (readonly) MaplyBoundingBoxD geoBounds;
+
+/// Add a single component object for tracking
+- (void)addComponentObject:(MaplyComponentObject *)compObj;
+
+/// When a style builds a component object, it needs to add it here
+/// for tracking. This lets us delete it later.
+- (void)addComponentObjects:(NSArray *)compObjs;
+
+/// Return all the component objects thus collected
+- (NSArray *)componentObjects;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/Maply3DTouchPreviewDatasource.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/Maply3DTouchPreviewDatasource.h
new file mode 100644
index 0000000..ef42bf5
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/Maply3DTouchPreviewDatasource.h
@@ -0,0 +1,38 @@
+//
+// Maply3DTouchPreviewDatasource.h
+// WhirlyGlobe-MaplyComponent
+//
+// Created by Jesse Crocker on 10/4/15.
+//
+//
+
+@class MaplyBaseViewController;
+
+@protocol Maply3dTouchPreviewDatasource <NSObject>
+
+@required
+/**
+ Asks the data source for a view controller to display as a preview for a selected object
+
+ @param viewC the map requesting the view controller;
+
+ @param selectedObj The object a preview is being requested for.
+
+ @return a UIViewController, or nil if no preview should be displayed.
+ */
+- (UIViewController * _Nullable)maplyViewController:(MaplyBaseViewController * _Nonnull)viewC
+ previewViewControllerForSelection:(NSObject * _Nonnull)selectedObj;
+
+/**
+ Asks the data source to present a preview view controller.
+
+ the most likely implementation of this is [self show:previewViewC sender:self];
+
+ @param viewC the map requesting the view controller;
+
+ @param previewViewC the view controller to present.
+ */
+- (void)maplyViewController:(MaplyBaseViewController * _Nonnull)viewC
+ showPreviewViewController:(UIViewController * _Nonnull)previewViewC;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/Maply3dTouchPreviewDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/Maply3dTouchPreviewDelegate.h
new file mode 100644
index 0000000..1957e10
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/Maply3dTouchPreviewDelegate.h
@@ -0,0 +1,26 @@
+//
+// Maply3dTouchDelegate.h
+// WhirlyGlobeLib
+//
+// Created by Jesse Crocker on 10/4/15.
+//
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/Maply3DTouchPreviewDatasource.h>
+
+@class MaplyBaseInteractionLayer;
+@class MaplyBaseViewController;
+
+@interface Maply3dTouchPreviewDelegate : NSObject <UIViewControllerPreviewingDelegate>
+
+@property (nonatomic, strong) NSObject<Maply3dTouchPreviewDatasource> * _Nonnull datasource;
+
+/// Create and configure new Maply3dTouchPreviewDelegate, but it is not activated.
++ (Maply3dTouchPreviewDelegate * _Nonnull)touchDelegate:(MaplyBaseViewController * _Nonnull)maplyViewC
+ interactLayer:( MaplyBaseInteractionLayer* _Nonnull)interactLayer
+ datasource:(NSObject<Maply3dTouchPreviewDatasource>* _Nonnull)datasource;
+
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyActiveObject.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyActiveObject.h
new file mode 100644
index 0000000..864e853
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyActiveObject.h
@@ -0,0 +1,70 @@
+/*
+ * MaplyActiveObject.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 4/3/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+@class MaplyBaseViewController;
+@protocol MaplyRenderControllerProtocol;
+
+/**
+ Active Objects are used implement animation.
+
+ Active Objects work in conjuction with the renderer to make updates on the main thread. The way they work is this. They're called right at the beginning of a frame draw. They can make updates to regular Maply objects via the MaplyBaseViewController add and remove calls with the MaplyThreadMode set to MaplyThreadCurrent. This forces the changes to happen immediately on the current (main) thread.
+
+ Fill in at least the hasUpdate and updateForFrameMethods.
+
+ Active Objects are run on the main thread and you're probably going to be asking the view controller to add and remove objects on the main thread. As such, this can be slow. Be sure to precalculate whatever you might need to make this run faster. Also consider implementing your changes another way. If it can be done on another thread, do it on another thread.
+
+ */
+@interface MaplyActiveObject : NSObject
+
+/**
+ Initialize with a view controller
+
+ The default initializer just takes a view controller. If you replace this with your own, be sure to pass in what you need.
+ */
+- (nonnull instancetype)initWithViewController:(NSObject<MaplyRenderControllerProtocol> *__nonnull)viewC;
+
+/// The view controller this active object is associated with
+@property (nonatomic,weak,readonly) NSObject<MaplyRenderControllerProtocol> *__nullable viewC;
+
+/** Has Update
+
+ This is called every frame to determine if the active model has an update.
+ If it doesn't, we may not need to render. So use this judiciously.
+ */
+- (bool)hasUpdate;
+
+/** Update for the current frame.
+
+ Run the update right now. This should not take too long, as it's holding up
+ the renderer.
+
+ The frameInfo object is undefined at this point.
+ */
+- (void)updateForFrame:(void * __nonnull)frameInfo;
+
+/** Teardown active model.
+
+ The active model will no longer be run. Get rid of your internal state.
+ */
+- (void)teardown;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyAnnotation.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyAnnotation.h
new file mode 100644
index 0000000..1337cc3
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyAnnotation.h
@@ -0,0 +1,71 @@
+/*
+ * MaplyAnnotation.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 12/13/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+/**
+ This object displays an annotation at a particular point and will track that point as the map or globe moves.
+
+ An annotation is used to point out some feature on the globe or map, typically that the user has tapped on. It's a multi-part beast that may contain titles, subtitles, images, background views and such.
+
+ To add one, create the MaplyAnnotation and then call addAnnotation:forPoint:offset: on the MaplyBaseViewController.
+
+ The MaplyAnnotation is a wrapper around the SMCalloutView by Nick Farina. It exposes much of the functionality, but sets things up correctly and deals with moving the annotation around.
+ */
+@interface MaplyAnnotation : NSObject
+
+/// The minimum viewer height this annotation is visible at.
+/// This is viewer height above the globe or map. The annotation will only be visible if the user is above this height.
+@property (nonatomic,assign) float minVis;
+
+/// The maximum viewer height this annotation is visible at.
+/// This is viewer height above the globe or map. The annotation will only be visible if the user is below this height.
+@property (nonatomic,assign) float maxVis;
+
+/// Set the popup's title
+@property (nonatomic,strong) NSString *title;
+
+/// Set the popup's subtitle
+@property (nonatomic,strong) NSString *subTitle;
+
+/// If set, the (optional) accessory view on the left
+@property (nonatomic,strong) UIView *leftAccessoryView;
+
+/// If set, the (optional) accessory view on the right
+@property (nonatomic,strong) UIView *rightAccessoryView;
+
+/// If set, the custom title view containing whatever you like.
+@property (nonatomic,strong) UIView *titleView;
+
+/// If set, the custom subtitle view containing whatever you put in there.
+@property (nonatomic,strong) UIView *subtitleView;
+
+/// If set, a custom content view. Title, subtitle and views are ignored.
+@property (nonatomic,strong) UIView *contentView;
+
+/// The location of the annotation
+@property (nonatomic,readonly) MaplyCoordinate loc;
+
+/// If set, we'll reposition the globe or map to make the annotation visible.
+/// If the annotation would be off screen we would normally reposition the globe or map to make it visible. If this is et to false, we won't.
+@property (nonatomic) bool repositionForVisibility;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyAtmosphere.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyAtmosphere.h
new file mode 100644
index 0000000..f5de72d
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyAtmosphere.h
@@ -0,0 +1,81 @@
+/*
+ * MaplyAtmosphere.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 6/30/15.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyComponentObject.h>
+#import <WhirlyGlobe/WhirlyGlobeViewController.h>
+#import <WhirlyGlobe/MaplyLight.h>
+
+/**
+ Sets up the objects and shaders to implement an atmosphere.
+
+ This object sets up a shader implementation of the simple atmosphere from GPU Gems 2 http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html
+ */
+@interface MaplyAtmosphere : NSObject
+
+/// Initialize the view controller. Will place objects in that view controller.
+- (nullable instancetype)initWithViewC:(WhirlyGlobeViewController *__nonnull)viewC;
+
+/// Rayleigh scattering constant (0.0025 by default)
+@property (nonatomic) float Kr;
+
+/// Mie scattering constant (0.0010 by default)
+@property (nonatomic) float Km;
+
+/// Brightness of the sun (20.0 by default)
+@property (nonatomic) float ESun;
+
+/// Number of samples for the ray through the atmosphere (3 by default)
+@property (nonatomic) int numSamples;
+
+/// Outer radius of the atmosphere (1.05 by default). Earth is radius 1.0.
+@property (nonatomic) float outerRadius;
+
+/// Constant used in the fragment shader. Default is -0.95.
+@property (nonatomic) float g;
+
+/// Exposure constant in fragment shader. Default is 2.0.
+@property (nonatomic) float exposure;
+
+/// The ground shader we set up. You need to apply it yourself.
+@property (nonatomic,nullable,strong) MaplyShader *groundShader;
+
+/// If set we'll lock the sun direction to the camera position. Permanent daylight.
+@property (nonatomic) bool lockToCamera;
+
+/// Wavelengths of the light (RGB). Three floats, defaults are: 0.650, 0.570, 0.475
+- (void)setWavelength:(float *__nonnull)wavelength;
+
+/// Wavelengths of the light (RGB). Defaults are: 0.650, 0.570, 0.475
+- (void)setWavelengthRed:(float) redWavelength green:(float)greenWavelength blue:(float)blueWavelength;
+
+/// Return the current wavelength settings (RGB)
+- (void)getWavelength:(float *__nonnull)wavelength;
+
+/// Return the current wavelength settings (RGB). The component is 0 for red, 1 for green and 2 for blue
+- (float)getWavelengthForComponent:(short)component;
+
+/// Set the sun's position relative to the earth. This is what comes out of MaplySun.
+- (void)setSunPosition:(MaplyCoordinate3d)sunDir;
+
+/// Remove objects from the view controller we set it up in.
+- (void)removeFromViewC;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyBaseViewController.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyBaseViewController.h
new file mode 100644
index 0000000..119b330
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyBaseViewController.h
@@ -0,0 +1,1582 @@
+/* MaplyBaseViewController.h
+ * MaplyComponent
+ *
+ * Created by Steve Gifford on 12/14/12.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <Metal/Metal.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyScreenMarker.h>
+#import <WhirlyGlobe/MaplyVectorObject.h>
+#import <WhirlyGlobe/MaplyViewTracker.h>
+#import <WhirlyGlobe/MaplyComponentObject.h>
+#import <WhirlyGlobe/MaplySharedAttributes.h>
+#import <WhirlyGlobe/MaplyControllerLayer.h>
+#import <WhirlyGlobe/MaplyLight.h>
+#import <WhirlyGlobe/MaplyShader.h>
+#import <WhirlyGlobe/MaplyActiveObject.h>
+#import <WhirlyGlobe/MaplyTexture.h>
+#import <WhirlyGlobe/MaplyAnnotation.h>
+#import <WhirlyGlobe/MaplyParticleSystem.h>
+#import <WhirlyGlobe/MaplyPoints.h>
+#import <WhirlyGlobe/MaplyCluster.h>
+#import <WhirlyGlobe/Maply3DTouchPreviewDatasource.h>
+#import <WhirlyGlobe/MaplyLocationTracker.h>
+#import <WhirlyGlobe/MaplyRenderTarget.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+#import <WhirlyGlobe/MaplyRemoteTileFetcher.h>
+#import <WhirlyGlobe/MaplyVertexAttribute.h>
+
+typedef double (^ZoomEasingBlock)(double z0,double z1,double t);
+typedef void (__strong ^InitCompletionBlock)(void);
+
+/**
+ When selecting multiple objects, one or more of these is returned.
+
+ When you implement one of the selection delegates that takes multiple objects, you'll get an NSArray of these things.
+ */
+@interface MaplySelectedObject : NSObject
+
+/// Object the user selected
+/// This is the original object the user passed in when adding it to the globe or map.
+@property (nonatomic) id __nullable selectedObj;
+
+/// Distance from where the user tapped to the closest part of the object on the screen
+@property double screenDist;
+
+/// Distance from the user's viewpoint to the center of the object in 3-space. Use this for sorting.
+@property double zDist;
+
+/// Set if this was part of a cluster
+@property bool cluster;
+
+@end
+
+/** Snapshot Delegate
+
+ Snapshots can be run as callbacks after the rendering. If you keep your area
+ small enough you can even do it every frame. This is the protocol for
+ snapshot delegates.
+ */
+@protocol MaplySnapshotDelegate
+
+/// Return true if you want a snapshot for this frame
+- (bool)needSnapshot:(NSTimeInterval)now viewC:(MaplyBaseViewController * __nonnull)viewC;
+
+/// If you want the whole thing return CGRectZero, otherwise return the rectangle you want based
+/// on the number of pixels. So multiply by the scale first.
+- (CGRect)snapshotRect;
+
+/// Here's your snapshot data. Do what you will, but do it quickly. You can hold onto the NSData.
+- (void)snapshot:(NSData * __nonnull)snapshotData;
+
+/// If you want a specific render target, return it. Otherwise nil for the screen.
+- (MaplyRenderTarget * __nullable)renderTarget;
+
+@optional
+/// If a render target calculates the min/max values after rendering, this snapshot callback will be called as well
+- (void)snapshotMinMax:(NSData * __nonnull)snapshotData;
+
+@end
+
+
+@protocol MaplyLocationTrackerDelegate;
+
+/**
+ Base class for the Maply and WhirlyGlobe view controllers.
+
+ The Maply Base View Controller is where most of the functionality lives. For the most part Maply and WhirlyGlobe share methods and data structures. This view controller sets up the rendering, the threading, basically everything that makes WhirlyGlobe-Maply work.
+
+ Don't create one of these directly, instead use the MaplyViewController or the WhirlyGlobeViewController.
+ */
+@interface MaplyBaseViewController : UIViewController <MaplyRenderControllerProtocol>
+
+/**
+ Turn selection on or off globally.
+
+ If on we'll forward selected features on to the delegate. When off, we don't do that. On by default.
+ */
+@property(nonatomic,assign) bool selection;
+
+/**
+ Set the globe (not the UIView's) background color.
+
+ This property sets the clear color used by OpenGL. By default it's black.
+ */
+@property (nonatomic,strong) UIColor * __nullable clearColor;
+
+/**
+ Set the frame interval passed to the CADisplayLink.
+
+ This sets the frame rate the renderer will attempt to achieve.
+
+ |value|frames per second|
+ |:----|:----------------|
+ |1|60fps|
+ |2|30fps|
+ |3|20fps|
+ |4|15fps|
+ |5|12fps|
+ |6|Really? No, you can do better.|
+ */
+@property (nonatomic,assign) int frameInterval;
+
+///**
+// The elevation delegate that will provide elevation data per tile.
+//
+// We break the image tiles out from the elevation tiles. The data is often coming from different sources, but in the end this is a probably a hack. It's a hack that's going to be in place for a while.
+//
+// To provide elevation for your compatible MaplyTileSource objects, you fill out the MaplyElevationSourceDelegate protocol and assign the resulting object here. When an image layer needs elevation, it will check for the delegate and then query for the respective file.
+//
+// At present there is no checking for coordinate system compatibility, so be aware.
+// */
+//@property (nonatomic,weak) NSObject<MaplyElevationSourceDelegate> *__nullable elevDelegate;
+
+/**
+ Set the offset for the screen space objects.
+
+ In general you want the screen space objects to appear on top of everything else. There used to be structural reasons for this, but now you can mix and match where everything appears. This controls the offset that's used to push screen space objects behind everything else in the list (and thus, on top).
+
+ If you set this to 0, you can control the ordering of everything more precisely.
+ */
+@property (nonatomic,assign) int screenObjectDrawPriorityOffset;
+
+/**
+ Controls whether objects with unique IDs fade in and out when added or removed from the layout manager
+ */
+@property (nonatomic,assign) bool layoutFade;
+
+/**
+ Controls the way height changes while animating the view
+ For simple, linear zoom use:
+
+ zoomEasing = ^(double z0,double z1,double t) { return z0 + (z1 - z0) * t; };
+ */
+@property (readwrite,copy) ZoomEasingBlock _Nullable animationZoomEasing;
+
+
+/**
+ If in Metal rendering mode, return the Metal device being used.
+ */
+- (id<MTLDevice> __nullable)getMetalDevice;
+
+/**
+ If in Metal rendering mode, return the shader library set up by the toolkit.
+ */
+- (id<MTLLibrary> __nullable)getMetalLibrary;
+
+/**
+ Clear all the currently active lights.
+
+ There are a default set of lights, so you'll want to do this before adding your own.
+ */
+- (void)clearLights;
+
+/**
+ Reset the lighting back to its default state at startup.
+
+ This clears out all the lights and adds in the default starting light source.
+ */
+- (void)resetLights;
+
+/**
+ Add the given light to the list of active lights.
+
+ This method will add the given light to our active lights. Most shaders will recognize these lights and do the calculations. If you have a custom shader in place, it may or may not use these.
+
+ Triangle shaders use the lights, but line shaders do not.
+ */
+- (void)addLight:(MaplyLight *__nonnull)light;
+
+/// Remove the given light (assuming it's active) from the list of lights.
+- (void)removeLight:(MaplyLight *__nonnull)light;
+
+/**
+ Set the rendering hints to control how the renderer is configured.
+
+ This is a bit vestigial, but still has a few important uses. The hints should be set right after the init call. Any later and they'll probably be ignored.
+
+ The rendering hints are as follows.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyRenderHintZBuffer|bool|If set, we'll explicitly turn on the Z buffer. Normally it's off until a drawable requests it, allowing us to play neat tricks with overlays. The only time you should be turning this on is if you're doing 3D elevation. The default is off.|
+ |kMaplyRenderHintCulling|bool|If set, we'll use the internal culling logic. Texture and drawable atlases have largely made this pointless. Leave it off unless you have a compelling reason to turn it on.|
+ |kMaplyRendererLightingMode|NSString|This can be set to @"none", in which case we use optimized shaders that do no lighting or "regular". The latter is the default.|
+ */
+- (void)setHints:(NSDictionary *__nonnull)hintsDict;
+
+/// This calls addScreenMarkers:desc:mode: with mode set to MaplyThreadAny
+- (MaplyComponentObject *__nullable)addScreenMarkers:(NSArray *__nonnull)markers desc:(NSDictionary *__nullable)desc;
+
+/**
+ Add one or more screen markers to the current scene.
+
+ This method will add the given MaplyScreenMaker objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param markers An NSArray of MaplyScreenMarker objects.
+
+ @param desc The desciption dictionary which controls how the markers will be constructed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|The color we'll use for the rectangle that makes up a marker. White by default.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The marker will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The marker will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyDrawPriority|NSNumber|If set, the markers are sorted by this number. Larger numbers will be sorted later.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a marker in when it appears and out when it disappears.|
+ |kMaplyFadeIn|NSNumber|The number of seconds to fade a marker in when it appears. This overrides kMaplyFade.|
+ |kMaplyFadeOut|NSNumber|The number of seconds to fade a marker out when it disappears. This override kMaplyFade.|
+ |kMaplyFadeOutTime|NSNumber|If you want to create an object, just to have it fade out at a specific time, this is what you set.|
+ |kMaplyShader|NSString|If set, this is the name of the MaplyShader to use when rendering the screen markers.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyEnableStart|NSNumber|If set, this controls when the resulting objects will be activated.|
+ |kMaplyEnableEnd|NSNumber|If set, this controls when the resulting objects will be deactivated.|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+ |kMaplyClusterGroup|NSNumber|If set, the screen markers will be clustered together according to the given group ID. Off by default, but 0 is the default cluster.|
+
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addScreenMarkers:(NSArray *__nonnull)markers desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add a cluster generator for making clustered marker images on demand.
+
+ When the layout system clusters a bunch of markers or labels together, it needs new images to represent the cluster.
+
+ You can provide a custom image for each group of markers by filling in one of these generates and passing it in.
+ */
+- (void)addClusterGenerator:(NSObject <MaplyClusterGenerator> *__nonnull)clusterGen;
+
+/// This calls addMarkers:desc:mode: with mode set to MaplyThreadAny
+- (MaplyComponentObject *__nullable)addMarkers:(NSArray *__nonnull)markers desc:(NSDictionary *__nullable)desc;
+
+/**
+ Add one or more 3D markers to the current scene.
+
+ This method will add the given MaplyMarker objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param markers An NSArray of MaplyMarker objects.
+
+ @param desc The desciption dictionary which controls how the markers will be constructed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|The color we'll use for the rectangle that makes up a marker. White by default.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The marker will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The marker will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a marker in when it appears and out when it disappears.|
+ |kMaplyFadeIn|NSNumber|The number of seconds to fade a marker in when it appears. This overrides kMaplyFade.|
+ |kMaplyFadeOut|NSNumber|The number of seconds to fade a marker out when it disappears. This override kMaplyFade.|
+ |kMaplyFadeOutTime|NSNumber|If you want to create an object, just to have it fade out at a specific time, this is what you set.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyMarkerDrawPriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's off by default, meaning that the geometry will draw on top of anything (respecting the kMaplyDrawPriority).|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addMarkers:(NSArray *__nonnull)markers desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/// This calls addScreenLabels:desc:mode: with mode set to MaplyThreadAny
+- (MaplyComponentObject *__nullable)addScreenLabels:(NSArray *__nonnull)labels desc:(NSDictionary *__nullable)desc;
+
+/**
+ Add one or more screen labels to the current scene.
+
+ This method will add the given MaplyScreenLabel objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param labels An NSArray of MaplyScreenLabel objects.
+
+ @param desc The desciption dictionary which controls how the labels will be constructed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyTextColor|UIColor|Color we'll use for the text. Black by default.|
+ |kMaplyBackgroundColor|UIColor|Color we'll use for the rectangle background. Use clearColor to make this invisible.|
+ |kMaplyFont|UIFont|The font we'll use for the text.|
+ |kMaplyLabelHeight|NSNumber|Height of the text in points.|
+ |kMaplyLabelWidth|NSNumber|Width of the text in points. It's best to set Height and leave this out. That way the width will be calculated by the toolkit.|
+ |kMaplyJustify|NSString|This can be set to @"middle", @"left", or @"right" to justify the text around the location.|
+ |kMaplyTextJustify|NSString|This can be kMaplyTextJustifyRight, kMaplyTextJustifyCenter, or kMaplyTextJustifyLeft|
+ |kMaplyShadowSize|NSNumber|If set, we'll draw a shadow with the kMaplyShadowColor offset by this amount. We recommend using an outline instead.|
+ |kMaplyShadowColor|UIColor|If we're drawing a shadow, this is its color.|
+ |kMaplyTextOutlineSize|NSNumber|If set, we'll draw an outline around the text (really draw it twice). The outline will be this large.|
+ |kMaplyTextOutlineColor|UIColor|If we're drawing an outline, it's in this color.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The label will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The label will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyDrawPriority|NSNumber|If set, the labels are sorted by this number. Larger numbers will be sorted later.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a screen label in when it appears and out when it disappears.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyEnableStart|NSNumber|If set, this controls when the resulting objects will be activated.|
+ |kMaplyEnableEnd|NSNumber|If set, this controls when the resulting objects will be deactivated.|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addScreenLabels:(NSArray *__nonnull)labels desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/// This calls addLabels:desc:mode: with mode set to MaplyThreadAny
+- (MaplyComponentObject *__nullable)addLabels:(NSArray *__nonnull)labels desc:(NSDictionary *__nullable)desc;
+
+/**
+ Add one or more 3D labels to the current scene.
+
+ This method will add the given MaplyLabel objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param labels An NSArray of MaplyLabel objects.
+
+ @param desc The desciption dictionary which controls how the labels will be constructed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyTextColor|UIColor|Color we'll use for the text. Black by default.|
+ |kMaplyBackgroundColor|UIColor|Color we'll use for the rectangle background. Use clearColor to make this invisible.|
+ |kMaplyFont|UIFont|The font we'll use for the text.|
+ |kMaplyLabelHeight|NSNumber|Height of the text in display coordinates. For the globe these are based on radius = 1.0.|
+ |kMaplyLabelWidth|NSNumber|Width of the text in display coordinates. It's best to set Height and leave this out. That way the width will be calculated by the toolkit.|
+ |kMaplyJustify|NSString|This can be set to @"middle", @"left", or @"right" to justify the text around the location.|
+ |kMaplyShadowSize|NSNumber|If set, we'll draw a shadow with the kMaplyShadowColor offset by this amount. We recommend using an outline instead.|
+ |kMaplyShadowColor|UIColor|If we're drawing a shadow, this is its color.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The label will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The label will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a label in when it appears and out when it disappears.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyLabelDrawPriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's off by default, meaning that the geometry will draw on top of anything (respecting the kMaplyDrawPriority).|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addLabels:(NSArray *__nonnull)labels desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/// This calls addVectors:desc:mode: with mode set to MaplyThreadAny
+- (MaplyComponentObject *__nullable)addVectors:(NSArray *__nonnull)vectors desc:(NSDictionary *__nullable)desc;
+
+/**
+ Add one or more vectors to the current scene.
+
+ This method will add the given MaplyVectorObject objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param vectors An NSArray of MaplyVectorObject objects.
+
+ @param desc The desciption dictionary which controls how the vectors will look. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the vector features.|
+ |kMaplyVecWidth|NSNumber|If the geometry is not filled, this is the width of the GL lines.|
+ |kMaplyFilled|NSNumber boolean|If set, the areal geometry will be tesselated, taking holes into account. The resulting triangles will be displayed instead of the vectors.|
+ |kMaplySubdivType|NSString|When present, this requests that the geometry be broken up to follow the globe (really only makes sense there). It can be set to kMaplySubdivGreatCircle or kMaplySubdivSimple which do a great circle subdivision and a simple 3-space subdivision respectively. If the key is missing, we do no subdivision at all.|
+ |kMaplySubdivEpsilon|NSNumber|If there's a kMaplySubdivType set this is the epsilon we'll pass into the subdivision routine. The value is in display coordinates. 0.01 is a reasonable value. Smaller results in more subdivision.|
+ |kMaplyVecTexture|UIImage|If set and the kMaplyFilled attribute is set, we will apply the given texture across any areal features. How the texture is applied can be controlled by kMaplyVecTexScaleX, kMaplyVecTexScaleY, kMaplyVecCenterX, kMaplyVecCenterY, and kMaplyVecTextureProjection|
+ |kMaplyVecTexScaleX,kMaplyVecTexScaleY|NSNumber|These control the scale of the texture application. We'll multiply by these numbers before generating texture coordinates from the vertices.|
+ |kMaplyVecCenterX,kMaplyVecCenterY|NSNumber|These control the center of a texture application. If not set we'll use the areal's centroid. If set, we'll use these instead. They should be in local coordinates (probably geographic radians).|
+ |kMaplyVecTextureProjection|NSString|This controls how a texture is projected onto an areal feature. By default we just use the geographic coordinates and stretch them out. This looks odd for very large features. If you set this to kMaplyProjectionTangentPlane then we'll take the center of the feature, make a tangent plane and then project the coordinates onto that tangent plane to get texture coordinates. This looks nice at the poles. If set to kMaplyProjectionScreen the texture is mapped on after screen space projection around the center of the feature.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a vector in when it appears and out when it disappears.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyVectorDrawPriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's off by default, meaning that the geometry will draw on top of anything (respecting the kMaplyDrawPriority).|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplySelectable|NSNumber boolean|Off by default. When enabled, the vector feature will be selectable by a user.|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addVectors:(NSArray *__nonnull)vectors desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Make a copy of the base object and apply the attributes given for the new version.
+
+ This call makes a cheap copy of the vectors in the given MaplyComponentObject and applies the given description to them. You can use this to make a wider or thinner version of a set of vectors, or change their color, while continuing to draw the originals. Or not, as the case may be.
+
+ This is useful for vector maps where we tend to reuse the same geometry at multiple levels and with different colors and line widths.
+
+ Instancing only works with a handful of visual changes. For instance, you can't make a filled and non-filled version.
+
+ @param baseObj The MaplyComponentObject returned by an addVectors: call. This only works for vectors.
+
+ @param desc The description dictionary with controls how vectors will be displayed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the vector features.|
+ |kMaplyVecWidth|NSNumber|If the geometry is not filled, this is the width of the GL lines.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyVectorDrawPriorityDefault.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)instanceVectors:(MaplyComponentObject *__nonnull)baseObj desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more widened vectors to the current scene.
+
+ Build widened vectors
+
+
+ @param desc The description dictionary which controls how vectors will be displayed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the features.|
+ |kMaplyVecWidth|NSNumber|If the geometry is not filled, this is the width of the lines.|
+ |kMaplyWideVecCoordType|NSNumber|Vectors can be widened in real coordinates (kMaplyWideVecCoordTypeReal) or screen coordinates (kMaplyWideVecCoordTypeScreen). In the latter case they stay the same size now matter how you zoom.|
+ |kMaplyWideVecJoinType|NSNumber|When lines meet in a join there are several options for representing them. These include kMaplyWideVecMiterJoin, which is a simple miter join and kMaplyWideVecBevelJoin which is a more complicated bevel. See http://www.w3.org/TR/SVG/painting.html#StrokeLinejoinProperty for how these look.|
+ |kMaplyWideVecMiterLimit|NSNumber|When using miter joins you can trigger them at a certain threshold.|
+ |kMaplyWideVecTexRepeatLen|NSNumber|This is the repeat size for a texture applied along the widened line. For kMaplyWideVecCoordTypeScreen this is pixels.|
+ |kMaplyVecTexture|UIImage or MaplyTexture|This the texture to be applied to the widened vector.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyVectorDrawPriorityDefault.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addWideVectors:(NSArray *__nonnull)vectors desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/// This calls addWideVectors:desc:mode: with mode set to MaplyThreadAny
+- (MaplyComponentObject *__nullable)addWideVectors:(NSArray *__nonnull)vectors desc:(NSDictionary *__nullable)desc;
+
+
+/// This calls addShapes:desc:mode: with mode set to MaplyThreadAny
+- (MaplyComponentObject *__nullable)addShapes:(NSArray *__nonnull)shapes desc:(NSDictionary *__nullable)desc;
+
+/**
+ Add one or more model instances.
+
+ Each MaplyGeomInstance points to a MaplyGeomModel. All those passed in here will be grouped and processed together.
+
+
+ @param desc The description dictionary which controls how the models are displayed, selected, and so forth.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplySelectable|NSNumber boolean|Off by default. When enabled, the vector feature will be selectable by a user.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addModelInstances:(NSArray *__nonnull)modelInstances desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or raw geometry models.
+
+ Each MaplyGeometryModel holds points and triangles in display space. These are relatively "raw" geometry and are passed to the geometry manager as is.
+
+
+ @param desc The description dictionary which controls how the geometry is displayed, selected, and so forth.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplySelectable|NSNumber boolean|Off by default. When enabled, the vector feature will be selectable by a user.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addGeometry:(NSArray *__nonnull)geom desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more MaplyShape children to the current scene.
+
+ This method will add the given MaplyShape derived objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param shapes An NSArray of MaplyShape derived objects.
+
+ @param desc The desciption dictionary which controls how the shapes will look. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the shape features.|
+ |kMaplyShapeSampleX|NSNumber|Number of samples to use in one direction when converting to polygons.|
+ |kMaplyShapeSampleY|NSNumber|Number of samples to use in the other direction when converting to polygons.|
+ |kMaplyShapeInsideOut|NSNumber boolean|If set to YES, we'll make the spheres inside out and such. Set to NO by default.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The shapes will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The shapes will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a shape in when it appears and out when it disappears.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyVectorShapePriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's on by default, meaning that the geometry can be occluded by things drawn first.|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addShapes:(NSArray *__nonnull)shapes desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/// This calls addStickers:desc:mode: with mode set to MaplyThreadAny
+- (MaplyComponentObject *__nullable)addStickers:(NSArray *__nonnull)stickers desc:(NSDictionary *__nullable)desc;
+
+/**
+ Add one or more MaplySticker objects to the current scene.
+
+ This method will add the given MaplySticker objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param stickers An NSArray of MaplySticker derived objects.
+
+ @param desc The desciption dictionary which controls how the stickers will look. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the stickers.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The stickers will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The stickers will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a sticker in when it appears and out when it disappears.|
+ |kMaplySampleX|NSNumber|Stickers are broken up along two dimensions to adhere to the globe. By default this is done adaptively. If you want to override it, this is the X dimension for the sticker.|
+ |kMaplySampleY|NSNumber|If you want to override it, this is the Y dimension for the sticker.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyVectorShapePriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's off by default, meaning that it will draw on top of things before it..|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyShader|NSString|If set, this is the name of the MaplyShader to use when rendering the sticker(s).|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addStickers:(NSArray *__nonnull)stickers desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Modify an existing sticker. This only supports changing the active textures.
+
+ This method will change attributes of a sticker that's currently in use. At present that's just the images it's displaying.
+
+ @param compObj The component object representing one or more existing stickers.
+
+ @param desc The description dictionary for changes we're making to the sticker.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyStickerImages|NSARray|The array of images to apply to the sticker. You can reuse old ones or introduce new ones.|
+ */
+- (void)changeSticker:(MaplyComponentObject *__nonnull)compObj desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more MaplyBillboard objects to the current scene.
+
+ This method will add the given MaplyBillboard objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param billboards An NSArray of MaplyBillboard objects.
+
+ @param desc The description dictionary that controls how the billboards will look. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the billboards.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The billboards will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The billboards will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyBillboardDrawPriorityDefault.|
+ |kMaplyBillboardOrient|NSNumber|Controls the billboard orientation. It's either directly toward the eye with kMaplyBillboardOrientEye or takes the ground into account with kMaplyBillboardOrientGround. Ground is the default.
+
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+ */
+- (MaplyComponentObject *__nullable)addBillboards:(NSArray *__nonnull)billboards desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add a particle system to the scene.
+
+ This adds a particle system to the scene, but does not kick off any particles.
+
+ @param partSys The particle system to start.
+
+ @param desc Any additional standard parameters (none at present).
+
+ @param threadMode MaplyThreadAny will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread. For particles, it's best to make a separate thread and use MaplyThreadCurrent.
+ */
+- (MaplyComponentObject *__nullable)addParticleSystem:(MaplyParticleSystem *__nonnull)partSys desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Change the render target for a particle system.
+
+ This changes the render target for an existing particle system that's already been created.
+ Can pass in nil, which means the particles are rendered to the screen directly.
+ This change takes place immediately, so call it on the main thread.
+ */
+- (void)changeParticleSystem:(MaplyComponentObject *__nonnull)compObj renderTarget:(MaplyRenderTarget *__nullable)target;
+
+/**
+ Add a batch of particles to the current scene.
+
+ Particles are short term objects, typically very small. We create them in large groups for efficience.
+
+ You'll need to fill out the MaplyParticleSystem initially and then the MaplyParticleBatch to create them.
+
+ @param batch The batch of particles to add to an active particle system.
+
+ @param threadMode MaplyThreadAny will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread. For particles, it's best to make a separate thread and use MaplyThreadCurrent.
+ */
+- (void)addParticleBatch:(MaplyParticleBatch *__nonnull)batch mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add vectors that can be used for selections.
+
+ These are MaplyVectorObject's that will show up in user selection, but won't be visible. So if a user taps on one, you get the vector in your delegate. Otherwise, no one will know it's there.
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addSelectionVectors:(NSArray *__nonnull)vectors;
+
+/**
+ Change the representation of the given vector features.
+
+ This will change how any vector features represented by the compObj look.
+
+ You can change kMaplyColor, kMaplyMinVis, kMaplyMaxVis, and kMaplyDrawPriority.
+ */
+- (void)changeVector:(MaplyComponentObject *__nonnull)compObj desc:(NSDictionary *__nullable)desc;
+
+/**
+ Change the representation of the given vector features.
+
+ This will change how any vector features represented by the compObj look.
+
+ You can change kMaplyColor, kMaplyMinVis, kMaplyMaxVis, and kMaplyDrawPriority.
+
+ This version takes a thread mode.
+ */
+- (void)changeVector:(MaplyComponentObject *__nonnull)compObj desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Adds the MaplyVectorObject's passed in as lofted polygons.
+
+ Lofted polygons are filled polygons draped on top of the globe with height. By using a transparent color, these can be used to represent selection or relative values on the globe (or map).
+
+
+ @param polys An NSArray of MaplyVectorObject.
+
+ @param desc The desciption dictionary which controls how the lofted polys will look. It takes the following entries.
+
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the lofted polygons. A bit of alpha looks good.|
+ |kMaplyLoftedPolyHeight|NSNumber|Height of the top of the lofted polygon in display units. For the globe display units are based on a radius of 1.0.|
+ |kMaplyLoftedPolyBase|NSNumber|If present, we'll start the lofted poly at this height. The height is in globe units, based on a radius of 1.0.|
+ |kMaplyLoftedPolyTop|NSNumber boolean|If on we'll create the geometry for the top. On by default.|
+ |kMaplyLoftedPolySide|NSNumber boolean|If on we'll create geometry for the sides. On by default.|
+ |kMaplyLoftedPolyGridSize|NSNumber|The size of the grid (in radians) we'll use to chop up the vector features to make them follow the sphere (for a globe).|
+ |kMaplyLoftedPolyOutline|NSNumber boolean|If set to @(YES) this will draw an outline around the top of the lofted poly in lines.|
+ |kMaplyLoftedPolyOutlineBottom|NSNumber boolean|If set to @(YES) this will draw an outline around the bottom of the lofted poly in lines.|
+ |kMaplyLoftedPolyOutlineColor|UIColor|If the outline is on this is the outline's color.|
+ |kMaplyLoftedPolyOutlineWidth|NSNumber|This is the outline's width if it's turned on.|
+ |kMaplyLoftedPolyOutlineDrawPriority|NSNumber|Draw priority of the lines created for the lofted poly outline.|
+ |kMaplyLoftedPolyOutlineSide|NSNumber boolean|If set and we're drawing an outline, this will create lines up the sides.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The lofted polys will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The lofted polys will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a lofted poly in when it appears and out when it disappears.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyLoftedPolysShapePriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's on by default, meaning that it can be occluded by geometry coming before it.|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addLoftedPolys:(NSArray *__nonnull)polys desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add a group of points to the display.
+
+ Adds a group of points all at once. We're assuming you want to draw a lot of points, so you have to group them together into a MaplyPoints.
+
+
+ @param points The points to add to the scene.
+
+ @param desc The desciption dictionary which controls how the points will look. It takes the following entries.
+
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the lofted polygons. A bit of alpha looks good.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The lofted polys will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The lofted polys will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a lofted poly in when it appears and out when it disappears.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyLoftedPolysShapePriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's on by default, meaning that it can be occluded by geometry coming before it.|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addPoints:(NSArray * __nonnull)points desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/// Add a view tracker to move a UIView around based on a geographic location.
+- (void)addViewTracker:(MaplyViewTracker *__nonnull)viewTrack;
+
+/// Move an existing view tracker to a new location
+- (void)moveViewTracker:(MaplyViewTracker *__nonnull)viewTrack moveTo:(MaplyCoordinate)newPos;
+
+/**
+ Add a single annotation which will track the given point.
+
+ This adds a MaplyAnnotation that will follow the given geo coordinate, applying the screen offset as given.
+
+ @param annotate The annotation we want to track a given point.
+
+ @param coord The location on the map (or globe) we'd like to track.
+
+ @param offset The screen offset for the annotation UIView. You use this to put the annotation above or below objects.
+ */
+- (void)addAnnotation:(MaplyAnnotation *__nonnull)annotate forPoint:(MaplyCoordinate)coord offset:(CGPoint)offset;
+
+/**
+ Remove the given annotation from the UIView.
+
+ This will dismiss the given annotation with its animation.
+ */
+- (void)removeAnnotation:(MaplyAnnotation *__nonnull)annotate;
+
+/**
+ Make the annotation stop moving.
+
+ If you have controls in your annotation you may need to make the annotation stop moving while the user manipulates them. Call this method to freeze the annotation while this happens.
+ */
+- (void)freezeAnnotation:(MaplyAnnotation *__nonnull)annotate;
+
+/**
+ Call this to start an annotation following its location again after being frozen.
+ */
+- (void)unfreezeAnnotation:(MaplyAnnotation *__nonnull)annotate;
+
+/**
+ Calls removeAnnotation: on all outstanding annotations.
+ */
+- (void)clearAnnotations;
+
+/**
+ Return an array of active annotations. Don't modify these.
+ */
+- (NSArray *__nullable)annotations;
+
+/// Remove an existing view tracker.
+- (void)removeViewTrackForView:(UIView *__nonnull)view;
+
+/**
+ Return the location on screen for a given geographic (lon/lat radians) coordinate.
+
+ @return Returns the screen point corresponding to a given geo coordinate.
+ */
+- (CGPoint)screenPointFromGeo:(MaplyCoordinate)geoCoord;
+
+/**
+ Animate the given position to the screen position over time.
+
+ This is similar to animateToPosition:time: except that it will attempt to match up the screen position and the geographic position. This is how you offset the location you're looking at.
+
+ If it's impossible to move newPos to loc, then nothing happens.
+
+ @param newPos The geographic position (lon/lat in radians) to move to.
+
+ @param loc The location on the screen where we'd like it to go.
+
+ @param howLong How long in seconds to take getting there.
+ */
+- (bool)animateToPosition:(MaplyCoordinate)newPos onScreen:(CGPoint)loc time:(NSTimeInterval)howLong;
+
+/**
+ Add an image as a texture and return a MaplyTexture to track it.
+
+ We reference count UIImages attached to Maply objects, but that has a couple of drawbacks. First, it retains the UIImage and if that's large, that's a waste of memory. Second, if you're adding and removing Maply objects you may repeatedly create and delete the same UIImage, which is a waste of CPU.
+
+ This method solves the problem by letting you create the texture associated with the UIImage and use it where you like. You can assign these in any place a UIImage is accepted on Maply objects.
+
+ You don't have call this before using a UIImage in a MaplyScreenMarker or other object. The system takes care of it for you. This is purely for optimization.
+
+ @param image The image we wish to retain the texture for.
+
+ @param imageFormat If we create this image, this is the texture format we want it to use.
+
+ | Image Format | Description |
+ |:-------------|:------------|
+ | MaplyImageIntRGBA | 32 bit RGBA with 8 bits per channel. The default. |
+ | MaplyImageUShort565 | 16 bits with 5/6/5 for RGB and none for A. |
+ | MaplyImageUShort4444 | 16 bits with 4 bits for each channel. |
+ | MaplyImageUShort5551 | 16 bits with 5/5/5 bits for RGB and 1 bit for A. |
+ | MaplyImageUByteRed | 8 bits, where we choose the R and ignore the rest. |
+ | MaplyImageUByteGreen | 8 bits, where we choose the G and ignore the rest. |
+ | MaplyImageUByteBlue | 8 bits, where we choose the B and ignore the rest. |
+ | MaplyImageUByteAlpha | 8 bits, where we choose the A and ignore the rest. |
+ | MaplyImageUByteRGB | 8 bits, where we average RGB for the value. |
+ | MaplyImage4Layer8Bit | 32 bits, four channels of 8 bits each. Just like MaplyImageIntRGBA, but a warning not to do anything too clever in sampling. |
+
+
+ @param wrapFlags These can be MaplyImageWrapX, MaplyImageWrapY, both or none.
+
+
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred.
+
+
+ @return A MaplyTexture you'll want to keep track of. It goes out of scope, the OpenGL ES texture will be deleted.
+ */
+- (MaplyTexture *__nullable)addTexture:(UIImage *__nonnull)image imageFormat:(MaplyQuadImageFormat)imageFormat wrapFlags:(int)wrapFlags mode:(MaplyThreadMode)threadMode;
+
+/**
+ Represent an image as a MaplyTexture.
+
+ This version of addTexture: allows more precise control over how the texture is represented. It replaces the other addTexture: and addTextureToAtlas calls.
+
+ @param image The UIImage to add as a texture.
+
+ @param desc A description dictionary controlling how the image is converted to a texture and represented in the system.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyTexFormat|NSNumber|The texture format to use for the image. Consult addTexture:imageFormat:wrapFlags:mode: for a list. Default is MaplyImageIntRGBA.|
+ |kMaplyTexMinFilter|NSNumber|Filter to use for minification. This can be kMaplyMinFilterNearest or kMaplyMinFilterLinear. Default is kMaplyMinFilterLinear.|
+ |kMaplyTexMagFilter|NSNumber|Filter to use for magnification. This can be kMaplyMinFilterNearest or kMaplyMinFilterLinear. Default is kMaplyMinFilterLinear.|
+ |kMaplyTexWrapX|NSNumber boolean|Texture wraps in x direction. Off by default.|
+ |kMaplyTexWrapY|NSNumber boolean|Texture wraps in y direction. Off by default.|
+ |kMaplyTexAtlas|NSNumber boolean|If set, the texture goes into an appropriate atlas. If not set, it's a standalone texture (default).|
+
+
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred.
+ */
+- (MaplyTexture *__nullable)addTexture:(UIImage *__nonnull)image desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Create an empty texture and return it.
+
+ Empty textures are used for offscreen rendering and other crazy stuff. You probably don't want to do this.
+
+ @param spec The description dictionary controlling the format and other textures goodies.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyTexFormat|NSNumber|The texture format to use for the image. Consult addTexture:imageFormat:wrapFlags:mode: for a list. Default is MaplyImageIntRGBA.|
+ |kMaplyTexMinFilter|NSNumber|Filter to use for minification. This can be kMaplyMinFilterNearest or kMaplyMinFilterLinear. Default is kMaplyMinFilterLinear.|
+ |kMaplyTexMagFilter|NSNumber|Filter to use for magnification. This can be kMaplyMinFilterNearest or kMaplyMinFilterLinear. Default is kMaplyMinFilterLinear.|
+ |kMaplyTexWrapX|NSNumber boolean|Texture wraps in x direction. Off by default.|
+ |kMaplyTexWrapY|NSNumber boolean|Texture wraps in y direction. Off by default.|
+ |kMaplyTexAtlas|NSNumber boolean|If set, the texture goes into an appropriate atlas. If not set, it's a standalone texture (default).|
+
+
+ @param sizeX The horizontal size of the textures (in pixels).
+
+ @param sizeY Vertical size of the texture (in pixels).
+ */
+- (MaplyTexture *__nullable)createTexture:(NSDictionary * _Nullable)spec sizeX:(int)sizeX sizeY:(int)sizeY mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add an image as a texture, but put it in a texture atlas. Return a
+
+ Texture atlases consolidate a number of compatible textures, speeding up rendering of any geometry they're used on. If you know you're going to be using a UIImage with a lot of other images in, say, a group of markers, it's wise to add it here first.
+
+ The entry in a texture atlas will be released when the MaplyTexture is released. So keep a copy of it around if you're going to use it.
+
+ @param image The image we're going to put in the texture.
+
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred if you're on the main thread.
+
+ @return A MaplyTexture you'll want to keep track of. It goes out of scope, the entry in the texture atlas will be cleared.
+ */
+- (MaplyTexture *__nullable)addTextureToAtlas:(UIImage *__nonnull)image mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add an image as a texture, but put it in a texture atlas and return a MaplyTexture to track it.
+
+ Texture atlases consolidate a number of compatible textures, speeding up rendering of any geometry they're used on. If you know you're going to be using a UIImage with a lot of other images in, say, a group of markers, it's wise to add it here first.
+
+ The entry in a texture atlas will be released when the MaplyTexture is released. So keep a copy of it around if you're going to use it.
+
+ @param image The image we're going to put in the texture.
+
+ @param imageFormat If we create this image, this is the texture format we want it to use.
+
+ | Image Format | Description |
+ |:-------------|:------------|
+ | MaplyImageIntRGBA | 32 bit RGBA with 8 bits per channel. The default. |
+ | MaplyImageUShort565 | 16 bits with 5/6/5 for RGB and none for A. |
+ | MaplyImageUShort4444 | 16 bits with 4 bits for each channel. |
+ | MaplyImageUShort5551 | 16 bits with 5/5/5 bits for RGB and 1 bit for A. |
+ | MaplyImageUByteRed | 8 bits, where we choose the R and ignore the rest. |
+ | MaplyImageUByteGreen | 8 bits, where we choose the G and ignore the rest. |
+ | MaplyImageUByteBlue | 8 bits, where we choose the B and ignore the rest. |
+ | MaplyImageUByteAlpha | 8 bits, where we choose the A and ignore the rest. |
+ | MaplyImageUByteRGB | 8 bits, where we average RGB for the value. |
+ | MaplyImage4Layer8Bit | 32 bits, four channels of 8 bits each. Just like MaplyImageIntRGBA, but a warning not to do anything too clever in sampling. |
+
+
+ @param wrapFlags These can be MaplyImageWrapX, MaplyImageWrapY, both or none.
+
+
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred if you're on the main thread.
+
+ @return A MaplyTexture you'll want to keep track of. It goes out of scope, the entry in the texture atlas will be cleared.
+ */
+- (MaplyTexture *__nullable)addTextureToAtlas:(UIImage *__nonnull)image imageFormat:(MaplyQuadImageFormat)imageFormat wrapFlags:(int)wrapFlags mode:(MaplyThreadMode)threadMode;
+
+/**
+ Creates a new texture that references part of an existing texture.
+
+ @param x Horizontal offset within the existing texture.
+ @param y Vertical offset within the existing texture.
+ @param width Width of the chunk to make a new texture.
+ @param height Height of the chunk to make a new texture.
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred if you're on the main thread.
+ */
+- (MaplyTexture *__nullable)addSubTexture:(MaplyTexture *__nonnull)tex xOffset:(int)x yOffset:(int)y width:(int)width height:(int)height mode:(MaplyThreadMode)threadMode;
+
+/**
+ Remove the OpenGL ES texture associated with the given MaplyTexture.
+
+ MaplyTexture's will remove their associated OpenGL textures when they go out of scope. This method does it expicitly and clears out the internals of the MaplyTexture.
+
+ Only call this if you're managing the texture explicitly and know you're finished with them.
+ */
+- (void)removeTexture:(MaplyTexture *__nonnull)image mode:(MaplyThreadMode)threadMode;
+
+/**
+ Remove the OpenGL ES textures associated with the given MaplyTextures.
+
+ MaplyTextures will remove their associated OpenGL textures when they go out of scope. This method does it expicitly and clears out the internals of the MaplyTexture.
+
+ Only call this if you're managing the texture explicitly and know you're finished with them.
+ */
+- (void)removeTextures:(NSArray *__nonnull)texture mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add a render target to the system
+
+ Sets up a render target and will start rendering to it on the next frame.
+
+ Keep the render target around so you can remove it later.
+ */
+- (void)addRenderTarget:(MaplyRenderTarget * _Nonnull)renderTarget;
+
+/**
+ Set the texture a given render target is writing to.
+
+ Render targets start out with one, but you may wish to change it.
+ */
+- (void)changeRenderTarget:(MaplyRenderTarget * __nonnull)renderTarget tex:(MaplyTexture * __nullable)tex;
+
+/**
+ Request a one time clear for the render target.
+
+ Rather than clearing every frame, you may want to specifically request a clear. This will
+ be executed at the next frame and then not again.
+ */
+- (void)clearRenderTarget:(MaplyRenderTarget * __nonnull)renderTarget mode:(MaplyThreadMode)threadMode;
+
+/**
+ Remove the given render target from the system.
+
+ Ask the system to stop drawing to the given render target. It will do this on the next frame.
+ */
+- (void)removeRenderTarget:(MaplyRenderTarget * _Nonnull)renderTarget;
+
+/**
+ Set the max number of objects for the layout engine to display.
+
+ The layout engine works with screen objects, such MaplyScreenLabel and MaplyScreenMaker. If those have layoutImportance set, this will control the maximum number we can display.
+ */
+- (void)setMaxLayoutObjects:(int)maxLayoutObjects;
+
+/**
+ Screen markers and labels can have uniqueIDs. We use these to ensure we're only displaying one version of an object with, say, vector tiles
+ that load multiple levels.
+
+ Now let's say you want to select some objects. This will let you pull them out of the usual layout logic so they'll always be displayed.
+ */
+- (void)setLayoutOverrideIDs:(NSArray *__nullable)uuids;
+
+
+
+/**
+ Normally the layout layer runs periodically if you change something or when you move around.
+ You can ask it to run ASAP right here. Layout runs on its own thread, so there may still be a delay.
+ */
+- (void)runLayout;
+
+/// Calls removeObjects:mode: with MaplyThreadAny.
+- (void)removeObject:(MaplyComponentObject *__nonnull)theObj;
+
+/// Calls removeObjects:mode: with MaplyThreadAny.
+- (void)removeObjects:(NSArray *__nonnull)theObjs;
+
+/**
+ Remove all information associated with the given MaplyComponentObject's.
+
+ Every add call returns a MaplyComponentObject. This will remove any visible features, textures, selection data, or anything else associated with it.
+
+ @param theObjs The MaplyComponentObject's we wish to remove.
+
+ @param threadMode For MaplyThreadAny we'll do the removal on another thread. For MaplyThreadCurrent we'll block the current thread to finish the removal. MaplyThreadAny is preferred.
+ */
+- (void)removeObjects:(NSArray *__nonnull)theObjs mode:(MaplyThreadMode)threadMode;
+
+/**
+ Disable a group of MaplyComponentObject's all at once.
+
+ By default all of the geometry created for a given object will appear. If you set kMaplyEnable to @(NO) then it will exist, but not appear. This has the effect of setting kMaplyEnable to @(NO).
+
+ @param theObjs The objects to disable.
+
+ @param threadMode For MaplyThreadAny we'll do the disable on another thread. For MaplyThreadCurrent we'll block the current thread to finish the disable. MaplyThreadAny is preferred.
+ */
+- (void)disableObjects:(NSArray *__nonnull)theObjs mode:(MaplyThreadMode)threadMode;
+
+/**
+ Enable a group of MaplyComponentObject's all at once.
+
+ By default all of the geometry created for a given object will appear. If you set kMaplyEnable to @(NO) then it will exist, but not appear. This has the effect of setting kMaplyEnable to @(YES).
+
+ @param theObjs The objects to enable.
+
+ @param threadMode For MaplyThreadAny we'll do the enable on another thread. For MaplyThreadCurrent we'll block the current thread to finish the enable. MaplyThreadAny is preferred.
+*/
+- (void)enableObjects:(NSArray *__nonnull)theObjs mode:(MaplyThreadMode)threadMode;
+
+/**
+ Set the representation to use for the matching UUIDs by specifying the UUIDs directly.
+
+ @param uuids Array of NSString, the UUIDs to update
+ @param repName The representation value to apply, nil to return to the default
+*/
+- (void)setRepresentation:(NSString *__nullable)repName
+ ofUUIDs:(NSArray<NSString *> *__nonnull)uuids;
+
+/**
+ Set the representation to use for the matching UUIDs by specifying the UUIDs directly.
+
+ @param repName The representation value to apply, nil to return to the default
+ @param fallbackRepName The representation to use if there are no matches
+ @param uuids Array of NSString, the UUIDs to update
+*/
+- (void)setRepresentation:(NSString *__nullable)repName
+ fallbackRepName:(NSString *__nullable)fallbackRepName
+ ofUUIDs:(NSArray<NSString *> *__nonnull)uuids;
+
+/**
+ Set the representation to use for the matching UUIDs by specifying the UUIDs directly.
+
+ @param uuids Array of NSString, the UUIDs to update
+ @param repName The representation value to apply, nil to return to the default
+ @param threadMode For MaplyThreadAny we'll do the enable on another thread. For MaplyThreadCurrent we'll block the current thread to finish the enable. MaplyThreadAny is preferred.
+*/
+- (void)setRepresentation:(NSString *__nullable)repName
+ ofUUIDs:(NSArray<NSString *> *__nonnull)uuids
+ mode:(MaplyThreadMode)threadMode;
+
+/**
+ Set the representation to use for the matching UUIDs by specifying the UUIDs directly.
+
+ @param uuids Array of NSString, the UUIDs to update
+ @param repName The representation value to apply, nil to return to the default
+ @param fallbackRepName The representation to use if there are no matches
+ @param threadMode For MaplyThreadAny we'll do the enable on another thread. For MaplyThreadCurrent we'll block the current thread to finish the enable. MaplyThreadAny is preferred.
+*/
+- (void)setRepresentation:(NSString *__nullable)repName
+ fallbackRepName:(NSString *__nullable)fallbackRepName
+ ofUUIDs:(NSArray<NSString *> *__nonnull)uuids
+ mode:(MaplyThreadMode)threadMode;
+
+/**
+ Set the representation to use for the UUIDs of the given objects.
+
+ @param objects Array of ComponentObject, the UUIDs to update
+ @param repName The representation value to apply, nil to return to the default
+*/
+- (void)setRepresentation:(NSString *__nullable)repName
+ ofObjects:(NSArray<MaplyComponentObject *> *__nonnull)objects;
+
+/**
+ Set the representation to use for the UUIDs of the given objects.
+
+ @param objects Array of ComponentObject, the UUIDs to update
+ @param repName The representation value to apply, nil to return to the default
+*/
+- (void)setRepresentation:(NSString *__nullable)repName
+ fallbackRepName:(NSString *__nullable)fallbackRepName
+ ofObjects:(NSArray<MaplyComponentObject *> *__nonnull)objects;
+
+/**
+ Set the representation to use for the UUIDs of the given objects.
+
+ @param objects Array of ComponentObject, the UUIDs to update
+ @param repName The representation value to apply, nil to return to the default
+ @param fallbackRepName The representation to use if there are no matches
+ @param threadMode For MaplyThreadAny we'll do the enable on another thread. For MaplyThreadCurrent we'll block the current thread to finish the enable. MaplyThreadAny is preferred.
+*/
+- (void)setRepresentation:(NSString *__nullable)repName
+ fallbackRepName:(NSString *__nullable)fallbackRepName
+ ofObjects:(NSArray<MaplyComponentObject *> *__nonnull)objects
+ mode:(MaplyThreadMode)threadMode;
+
+/**
+ Pass a uniform block through to a shader. Only for Metal.
+
+ Custom Metal shaders may have their own uniform blocks associated with a known bufferID.
+ This is how you pass those through for objects you've already created.
+ Useful for things like custom animation.
+ */
+- (void)setUniformBlock:(NSData *__nonnull)uniBlock buffer:(int)bufferID forObjects:(NSArray<MaplyComponentObject *> *__nonnull)compObjs mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add the given active object to the scene.
+
+ Active objects are used for immediate, frame based updates. They're fairly expensive, so be careful. After you create one, you add it to the scene here.
+ */
+- (void)addActiveObject:(MaplyActiveObject *__nonnull)theObj;
+
+/// Remove an active object from the scene.
+- (void)removeActiveObject:(MaplyActiveObject *__nonnull)theObj;
+
+/// Remove an array of active objects from the scene
+- (void)removeActiveObjects:(NSArray *__nonnull)theObjs;
+
+/**
+ Add a MaplyControllerLayer to the globe or map.
+
+ At present, layers are for paged geometry such as image tiles or vector tiles. You can create someting like a MaplyQuadImageTilesLayer, set it up and then hand it to addLayer: to add to the scene.
+ */
+- (bool)addLayer:(MaplyControllerLayer *__nonnull)layer;
+
+/// Remove a MaplyControllerLayer from the globe or map.
+- (void)removeLayer:(MaplyControllerLayer *__nonnull)layer;
+
+/// Remove zero or more MaplyControllerLayer objects from the globe or map.
+- (void)removeLayers:(NSArray *__nonnull)layers;
+
+/// Remove all the user created MaplyControllerLayer objects from the globe or map.
+- (void)removeAllLayers;
+
+/**
+ Utility routine to convert from a lat/lon (in radians) to display coordinates
+
+ This is a simple routine to get display coordinates from geocoordinates. Display coordinates for the globe are based on a radius of 1.0 and an origin of (0,0,0).
+
+ @return The input coordinate in display coordinates.
+ */
+- (MaplyCoordinate3d)displayPointFromGeo:(MaplyCoordinate)geoCoord;
+
+/**
+ Utility routine to convert from a lat/lon (in radians) to display coordinates
+
+ This is a simple routine to get display coordinates from geocoordinates. Display coordinates for the globe are based on a radius of 1.0 and an origin of (0,0,0).
+
+ @return The input coordinate in display coordinates.
+ */
+- (MaplyCoordinate3dD)displayPointFromGeoD:(MaplyCoordinate)geoCoord;
+
+/**
+ Utility routine to convert from a lat/lon (in radians) to display coordinates
+
+ This is a simple routine to get display coordinates from geocoordinates. Display coordinates for the globe are based on a radius of 1.0 and an origin of (0,0,0).
+
+ @return The input coordinate in display coordinates.
+ */
+- (MaplyCoordinate3dD)displayPointFromGeoDD:(MaplyCoordinateD)geoCoord;
+
+/**
+ If you've paused the animation earlier, this will start it again.
+
+ The renderer relies on a CADisplayLink. If it's paused, this will unpause it.
+ */
+- (void)startAnimation;
+
+/**
+ Pause the animation.
+
+ The renderer relies on a CADisplayLink. This will pause it. You'll want to do this if your app is going into the background or if you generally want the OpenGL ES code to stop doing anything.
+ */
+- (void)stopAnimation;
+
+/**
+ This shuts down the rendering and it cannot be restarted.
+
+ There are times we need to explicitly shut down the rendering rather than wait for an unload or release. This will do that.
+ */
+- (void)teardown;
+
+/**
+ Add a compiled shader. We'll refer to it by the scene name.
+
+ Once you've create a MaplyShader, you'll need to add it to the scene to use it.
+
+ @param shader The working shader (be sure valid is true) to add to the scene.
+
+ |Scene Name|Purpose|
+ |:---------|:------|
+ |kMaplyShaderDefaultTri|The shader used on triangles by default when there is lighting.|
+ |kMaplyShaderDefaultTriNoLighting|The shader used when lighting is explicitly turned off.|
+ |kMaplyShaderDefaultTriMultiTex|The shader used when drawables have more than one texture.|
+ |kMaplyShaderDefaultLine|The shader used for line drawing on the globe. This does a tricky bit of backface culling.|
+ |kMaplyShaderDefaultLineNoBackface|The shader used for line drawing on the map. This does no backface culling.|
+ */
+- (void)addShaderProgram:(MaplyShader *__nonnull)shader;
+
+/**
+ Look for a shader with the given name.
+
+ This is the shader's own name as specified in the init call, not the scene name as might be specified in addShaderProgram:sceneName:
+
+ @return Returns the registered shader if it found one.
+ */
+- (MaplyShader *__nullable)getShaderByName:(NSString *__nonnull)name;
+
+/**
+ Remove a shader that was added earlier.
+ */
+- (void)removeShaderProgram:(MaplyShader *__nonnull)shader;
+
+/**
+ Return the current map scale from the viewpoint.
+
+ Calculate the map scale denominator (ala Mapnik) based on the current screen size and the 3D viewport.
+
+ @return Returns the map scale denominator or MAXFLOAT if the system is not yet initialized.
+ */
+- (float)currentMapScale;
+
+/**
+ Calculate the height that corresponds to a given Mapnik-style map scale.
+
+ Figure out the viewer height that corresponds to a given scale denominator (ala Mapnik).
+
+ This height will probably be use for visibility ranges on geometry. This works as a mechanism for making geometry appear at certain map scales and disappear at others.
+
+ @return Returns the height or 0.0 if the system isn't initialized yet.
+ */
+- (float)heightForMapScale:(float)scale;
+
+/**
+ Takes a snapshot of the current OpenGL view and returns it.
+ */
+- (UIImage *__nullable)snapshot;
+
+/**
+ Return the raw data for a render target.
+
+ Copies the pixels for a render target out after rendering and returns them in an NSData object.
+ This is not fast. Don't call it often.
+ */
+- (NSData * __nullable)shapshotRenderTarget:(MaplyRenderTarget * __nonnull)renderTarget;
+
+/** Add a snapshot delegate.
+
+ If you need more regular snapshots, you can fill this in to get a callback every frame.
+ Don't snapshot the screen or even offscreen render targets every frame. It'll be slow.
+ */
+- (void)addSnapshotDelegate:(NSObject<MaplySnapshotDelegate> *__nonnull)snapshotDelegate;
+
+/** Remove your snapshot delegate.
+
+ Don't getting screenshots/render target snapshots? Get rid of your delegate. They're expensive.
+ */
+- (void)removeSnapshotDelegate:(NSObject<MaplySnapshotDelegate> *__nonnull)snapshotDelegate;
+
+
+/**
+ Return the current map zoom from the viewpoint.
+
+ Calculate the map zoom (TMS) based on the current screen size and the 3D viewport.
+
+ @param coordinate the location to calculate for. This is needed because zoom is dependant on latitude.
+
+ @return Returns the map zoom or MAXFLOAT if the system is not yet initialized.
+ */
+- (float)currentMapZoom:(MaplyCoordinate)coordinate;
+
+/**
+ Return the coordinate system being used for the display.
+
+ This returns the local coordinate system, which is used to unroll the earth (for the globe) or via a scaling factor (for the flat map).
+ */
+- (MaplyCoordinateSystem *__nullable)coordSystem;
+
+/**
+ Convert from a local coordinate (probably spherical mercator) to a display coordinate.
+
+ This converts from a local coordinate (x,y,height) in the view controller's coordinate system (probably spherical mercator) to a coordinate in display space. For the globe display space is based on a radius of 1.0. For the flat map it's just stretched with a similar factor.
+ */
+- (MaplyCoordinate3d)displayCoordFromLocal:(MaplyCoordinate3d)localCoord;
+
+/**
+ Convert from a local coordinate (probably spherical mercator) to a display coordinate.
+
+ This converts from a local coordinate (x,y,height) in the view controller's coordinate system (probably spherical mercator) to a coordinate in display space. For the globe display space is based on a radius of 1.0. For the flat map it's just stretched with a similar factor.
+ */
+- (MaplyCoordinate3dD)displayCoordFromLocalD:(MaplyCoordinate3dD)localCoord;
+
+/**
+ Convert from a coordinate in the given system to display space.
+
+ This converts from a coordinate (3d) in the given coordinate system to the view controller's display space. For the globe, display space is based on a radius of 1.0.
+ */
+- (MaplyCoordinate3d)displayCoord:(MaplyCoordinate3d)localCoord fromSystem:(MaplyCoordinateSystem *__nonnull)coordSys;
+
+/**
+ Convert from a coordinate in the given system to display space.
+
+ This converts from a double coordinate (3d) in the given coordinate system to the view controller's display space. For the globe, display space is based on a radius of 1.0.
+ */
+- (MaplyCoordinate3dD)displayCoordD:(MaplyCoordinate3dD)localCoord fromSystem:(MaplyCoordinateSystem *__nonnull)coordSys;
+
+/**
+ enable 3d touch object selection.
+
+ @param previewDataSource Data source to provide 3d touch preview view controllers.
+
+ @return true if 3d touch could be enabled
+ */
+- (BOOL)enable3dTouchSelection:(NSObject<Maply3dTouchPreviewDatasource> *__nonnull)previewDataSource;
+
+/**
+ Disable 3dtouch object selection
+ */
+- (void)disable3dTouchSelection;
+
+/**
+ Return all the selectable vector objects at the given location.
+
+ Objects can be selected via the delegate or the search can be run directly here.
+
+ This is not thread safe and will block the main thread.
+ */
+- (NSArray * _Nullable)objectsAtCoord:(MaplyCoordinate)coord;
+
+/**
+ Return all the selectable labels and markers at the given location.
+
+ Objects can be selected via the delegate or the search can be run directly here.
+
+ This is not thread safe and will block the main thread.
+ */
+- (NSArray * _Nullable)labelsAndMarkersAtCoord:(MaplyCoordinate)coord;
+
+/// Turn on/off performance output (goes to the log periodically).
+@property (nonatomic,assign) bool performanceOutput;
+
+/// Turn on/off debug outlines for layout objects
+@property (nonatomic,assign) bool showDebugLayoutBoundaries;
+
+/**
+ See derived class method.
+ */
+- (void)requirePanGestureRecognizerToFailForGesture:(UIGestureRecognizer *__nullable)other;
+
+/**
+ Start location tracking
+
+ @param delegate The MaplyLocationTrackerDelegate for receiving location event callbacks
+
+ @param useHeading Use location services heading information (requires physical magnetometer)
+
+ @param useCourse Use location services course information as fallback if heading unavailable
+ */
+- (void)startLocationTrackingWithDelegate:(NSObject<MaplyLocationTrackerDelegate> *__nullable)delegate
+ useHeading:(bool)useHeading
+ useCourse:(bool)useCourse;
+
+/**
+ Start location tracking
+
+ @param delegate The MaplyLocationTrackerDelegate for receiving location event callbacks
+
+ @param simulator The MaplyLocationSimulatorDelegate for producing locations
+
+ @param simInterval The time interval on which to update
+
+ @param useHeading Use location services heading information (requires physical magnetometer)
+
+ @param useCourse Use location services course information as fallback if heading unavailable
+ */
+- (void)startLocationTrackingWithDelegate:(NSObject<MaplyLocationTrackerDelegate> *__nullable)delegate
+ simulator:(NSObject<MaplyLocationSimulatorDelegate> *__nullable)simulator
+ simInterval:(NSTimeInterval)simInterval
+ useHeading:(bool)useHeading
+ useCourse:(bool)useCourse;
+
+/**
+ Return the current location tracker, if there is one.
+ */
+- (MaplyLocationTracker * __nullable)getLocationTracker;
+
+/**
+ Change lock type for location tracking
+
+ @param lockType The MaplyLocationLockType value for lock behavior
+ */
+- (void)changeLocationTrackingLockType:(MaplyLocationLockType)lockType;
+
+/**
+ Change lock type for location tracking
+
+ @param lockType The MaplyLocationLockType value for lock behavior
+
+ @param forwardTrackOffset The vertical offset if using MaplyLocationLockHeadingUpOffset (positive values are below the view center)
+ */
+- (void)changeLocationTrackingLockType:(MaplyLocationLockType)lockType forwardTrackOffset:(int)forwardTrackOffset;
+
+/**
+ Stop location tracking
+ */
+- (void)stopLocationTracking;
+
+/**
+ Get the current location tracker device location
+
+ @return The coordinate if valid, else kMaplyNullCoordinate
+ */
+- (MaplyCoordinate)getDeviceLocation;
+
+/**
+ Exposes MaplyLocationTracker's location manager for use elsewhere
+
+ @return The CLLocationmanager if it exists, else nil
+ */
+- (CLLocationManager * _Nullable )getTrackingLocationManager;
+
+/**
+ Return all layers loaded by user.
+
+ All layers loaded by user than are currently loaded.
+ */
+-(NSArray * _Nonnull)loadedLayers;
+
+/// Return the renderer type being used
+- (MaplyRenderType)getRenderType;
+
+/**
+ Blocks to be called after the view is set up, or immediately if it is already set up.
+ Similar to `addPostSurfaceRunnable` on Android.
+*/
+- (void)addPostInitBlock:(_Nonnull InitCompletionBlock)block;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyBillboard.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyBillboard.h
new file mode 100644
index 0000000..f29eb87
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyBillboard.h
@@ -0,0 +1,74 @@
+/*
+ * MaplyBillboard.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 10/28/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyScreenObject.h>
+
+/**
+ A billboard is tied to a specific point, but rotates to face the user.
+
+ The billboard object represents a rectangle which is rooted at a specific point, but will rotate to face the user. These are typically used in 3D, when the globe or map has a tilt. They make little sense in 2D.
+ */
+@interface MaplyBillboard : NSObject
+
+/**
+ The point this billboard is rooted at.
+
+ The x and y coordinates are radians. The z coordinate is in meters.
+ */
+@property (nonatomic) MaplyCoordinate3d center;
+
+/// Set if you want to select these
+@property (nonatomic) bool selectable;
+
+/// The 2D polygonal description of what the billboard should be
+@property (nonatomic,strong) MaplyScreenObject * __nullable screenObj;
+
+/**
+ Vertex attributes to apply to this billboard.
+
+ MaplyVertexAttribute objects are passed all the way to the shader. Read that page for details on what they do.
+
+ The array of vertex attributes provided here will be copied onto all the vertices we create for the shader. This means you can use these to do things for a single billboard in your shader.
+ */
+@property (nonatomic,strong) NSArray * __nullable vertexAttributes;
+
+/**
+ User data object for selection
+
+ When the user selects a feature and the developer gets it in their delegate, this is an object they can use to figure out what the screen label means to them.
+ */
+@property (nonatomic,strong) id __nullable userObject;
+
+/**
+ Initialize with a single image, a given background and a size.
+
+ This will create a simple billboard with a single image pasted on it.
+
+ @param texture This can either be a UIImage or a MaplyTexture.
+
+ @param color Color for the polygon that makes up the billboard.
+
+ @param size Size of the billboard in display space.
+ */
+- (nullable instancetype)initWithImage:(id __nonnull)texture color:(UIColor * __nonnull)color size:(CGSize)size;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyBridge.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyBridge.h
new file mode 100644
index 0000000..d0e9832
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyBridge.h
@@ -0,0 +1,23 @@
+/* MaplyBridge.h
+ * MaplyBridge
+ *
+ * Created by jmnavarro on 7/19/15.
+ * Copyright 2015-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyComponent.h>
+#import <WhirlyGlobe/MaplyBaseViewController.h>
+#import <WhirlyGlobe/WhirlyGlobeViewController.h>
+#import <WhirlyGlobe/MaplyGlobeRenderController.h>
+#import <WhirlyGlobe/MaplyViewController.h>
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyCluster.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyCluster.h
new file mode 100644
index 0000000..d874bb3
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyCluster.h
@@ -0,0 +1,147 @@
+/*
+ * MaplyCluster.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 9/29/15.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyScreenMarker.h>
+#import <WhirlyGlobe/MaplyShader.h>
+
+@class MaplyBaseViewController;
+
+/**
+ Information about the group of objects to cluster.
+
+ This object is passed in when the developer needs to make an image for a group of objects.
+ */
+@interface MaplyClusterInfo : NSObject
+
+/// Number of objects being clustered
+@property (nonatomic,assign) int numObjects;
+
+/// All the unique IDs from the
+@property (nonatomic,retain) NSArray<NSString *> * __nullable uniqueIDs;
+
+@end
+
+/**
+ Visual representation for a group of markers.
+
+ Fill this in when you're implementing a MaplyClusterGenerator.
+ */
+@interface MaplyClusterGroup : NSObject
+
+/// The image to use for the group
+@property (nonatomic,strong) id __nonnull image;
+
+/// Screen size to use for the resulting marker
+@property (nonatomic,assign) CGSize size;
+
+/// Size used for layout. If it's not set, we use the regular size.
+@property (nonatomic,assign) CGSize layoutSize;
+
+@end
+
+/**
+ Fill in this protocol to provide images when individual markers/labels are clustered.
+
+ This is the protocol for marker/label clustering. You must fill this in and register the cluster
+ */
+@protocol MaplyClusterGenerator <NSObject>
+
+/**
+ Called at the start of clustering.
+
+ Called right before we start generating clusters. Do you setup here if need be.
+ */
+- (void) startClusterGroup;
+
+/**
+ Generate a cluster group for a given collection of markers.
+
+ Generate an image and size to represent the number of marker/labels we're consolidating.
+
+ @note Will not be called if @c -showMarkerWithHighestImportance returns @c true.
+ */
+- (MaplyClusterGroup *__nonnull) makeClusterGroup:(MaplyClusterInfo *__nonnull)clusterInfo;
+
+/**
+ Called at the end of clustering.
+
+ If you were doing optimization (for image reuse, say) clean it up here.
+ */
+- (void) endClusterGroup;
+
+/// Return the cluster number we're covering
+- (int) clusterNumber;
+
+/// The size of the cluster that will be created.
+/// This is the biggest cluster you're likely to create. We use it to figure overlaps between clusters.
+- (CGSize) clusterLayoutSize;
+
+/// Use appearance and coordinate of cluster group marker with highest importance. If not set then an average of coordinates will be used
+- (bool) showMarkerWithHighestImportance;
+
+/// Set this if you want cluster to be user selectable. On by default.
+- (bool) selectable;
+
+/// How long to animate markers the join and leave a cluster
+- (double) markerAnimationTime;
+
+/// The shader to use for moving objects around
+/// If you're doing animation from point to cluster you need to provide a suitable shader.
+- (MaplyShader *__nullable) motionShader;
+
+@end
+
+/**
+ The basic cluster generator installed by default.
+
+ This cluster generator will make images for grouped clusters of markers/labels.
+ */
+@interface MaplyBasicClusterGenerator : NSObject <MaplyClusterGenerator>
+
+/**
+ Initialize with a list of colors.
+
+ Initialize with a list of colors. Each order of magnitude will use another color. Must provide at least 1.
+ */
+- (nonnull instancetype)initWithColors:(NSArray *__nonnull)colors clusterNumber:(int)clusterNumber size:(CGSize)markerSize viewC:(NSObject<MaplyRenderControllerProtocol> *__nonnull)viewC;
+
+/// The ID number corresponding to the cluster. Every marker/label with this cluster ID will be grouped together.
+@property (nonatomic,assign) int clusterNumber;
+
+/// The size of the cluster that will be created.
+/// This is the biggest cluster you're likely to create. We use it to figure overlaps between clusters.
+@property (nonatomic) CGSize clusterLayoutSize;
+
+/// Set to use appearance and coordinate of cluster group marker with highest importance. Off by default.
+@property (nonatomic) bool showMarkerWithHighestImportance;
+
+/// Set this if you want cluster to be user selectable. On by default.
+@property (nonatomic) bool selectable;
+
+/// How long to animate markers the join and leave a cluster
+@property (nonatomic) double markerAnimationTime;
+
+/// The shader to use when moving objects around
+/// When warping objects to their new locations we use a motion shader. Set this if you want to override the default.
+@property (nonatomic,strong) MaplyShader * __nullable motionShader;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyColorRampGenerator.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyColorRampGenerator.h
new file mode 100644
index 0000000..95d2331
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyColorRampGenerator.h
@@ -0,0 +1,42 @@
+//
+// MaplyColorRampGenerator.h
+// WhirlyGlobe-MaplyComponent
+//
+// Created by Steve Gifford on 4/20/16.
+//
+//
+
+#import <UIKit/UIKit.h>
+
+/** The color ramp generator will take a set of color values
+ and generate a linear ramp of those colors in an output
+ image. You typically feed the color ramp image into a shader.
+ */
+@interface MaplyColorRampGenerator : NSObject
+
+// If set we'll stretch the colors out to the whole image
+// On by default.
+@property (nonatomic,assign) bool stretch;
+
+/// Add a color as a hex value.
+- (void)addHexColor:(int)hexColor;
+
+/// This color has an alpha too
+- (void)addHexColorWithAlpha:(int)hexColor;
+
+/// A color that's present in only one entry
+- (void)addSingleEntryColor:(UIColor *)color;
+
+/// Add a color as a UIColor
+- (void)addColor:(UIColor *)color;
+
+/// Add color with values expressed as integers 0-255
+- (void)addByteRed:(int)red green:(int)green blue:(int)blue alpha:(int)alpha;
+
+/// Generate the image with the color ramp in it
+- (UIImage *)makeImage:(CGSize)size;
+
+/// Get a list of colors (rather than generating an image)
+- (NSArray *)getColors;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyComponent.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyComponent.h
new file mode 100644
index 0000000..1d51b1b
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyComponent.h
@@ -0,0 +1,102 @@
+/* MaplyComponent.h
+ * MaplyComponent
+ *
+ * Created by Steve Gifford on 9/6/12.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplySharedAttributes.h>
+
+#import <WhirlyGlobe/NSData+Zlib.h>
+#import <WhirlyGlobe/NSDictionary+StyleRules.h>
+
+#import <WhirlyGlobe/MaplyGeomBuilder.h>
+#import <WhirlyGlobe/MaplyIconManager.h>
+#import <WhirlyGlobe/MaplyLocationTracker.h>
+#import <WhirlyGlobe/MaplyTextureBuilder.h>
+
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+#import <WhirlyGlobe/MaplyMatrix.h>
+
+#import <WhirlyGlobe/MaplyActiveObject.h>
+#import <WhirlyGlobe/MaplyAnnotation.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+#import <WhirlyGlobe/MaplyUpdateLayer.h>
+#import <WhirlyGlobe/MaplyViewTracker.h>
+#import <WhirlyGlobe/MaplyControllerLayer.h>
+#import <WhirlyGlobe/MaplyViewController.h>
+#import <WhirlyGlobe/MaplyBaseViewController.h>
+
+#import <WhirlyGlobe/MaplyComponentObject.h>
+#import <WhirlyGlobe/MaplyBillboard.h>
+#import <WhirlyGlobe/MaplyCluster.h>
+#import <WhirlyGlobe/MaplyLabel.h>
+#import <WhirlyGlobe/MaplyGeomModel.h>
+#import <WhirlyGlobe/MaplyMarker.h>
+#import <WhirlyGlobe/MaplyMoon.h>
+#import <WhirlyGlobe/MaplyParticleSystem.h>
+#import <WhirlyGlobe/MaplyPoints.h>
+#import <WhirlyGlobe/MaplySticker.h>
+#import <WhirlyGlobe/MaplyShape.h>
+#import <WhirlyGlobe/MaplyScreenLabel.h>
+#import <WhirlyGlobe/MaplySun.h>
+#import <WhirlyGlobe/MaplyScreenObject.h>
+#import <WhirlyGlobe/MaplyScreenMarker.h>
+#import <WhirlyGlobe/MaplyStarsModel.h>
+#import <WhirlyGlobe/MaplyTexture.h>
+#import <WhirlyGlobe/MaplyVectorObject.h>
+
+#import <WhirlyGlobe/MapboxVectorTiles.h>
+#import <WhirlyGlobe/MapboxVectorInterpreter.h>
+
+#import <WhirlyGlobe/SLDStyleSet.h>
+#import <WhirlyGlobe/SLDExpressions.h>
+#import <WhirlyGlobe/SLDOperators.h>
+#import <WhirlyGlobe/SLDSymbolizers.h>
+#import <WhirlyGlobe/SLDWellKnownMarkers.h>
+#import <WhirlyGlobe/MaplyVectorStyle.h>
+#import <WhirlyGlobe/MaplyVectorStyleSimple.h>
+#import <WhirlyGlobe/MaplyVectorTileLineStyle.h>
+#import <WhirlyGlobe/MaplyVectorTileMarkerStyle.h>
+#import <WhirlyGlobe/MaplyVectorTilePolygonStyle.h>
+#import <WhirlyGlobe/MaplyVectorTileStyle.h>
+#import <WhirlyGlobe/MaplyVectorTileTextStyle.h>
+#import <WhirlyGlobe/MapboxVectorStyleSet.h>
+#import <WhirlyGlobe/MapnikStyle.h>
+#import <WhirlyGlobe/MapnikStyleRule.h>
+#import <WhirlyGlobe/MapnikStyleSet.h>
+
+#import <WhirlyGlobe/MaplyQuadLoader.h>
+#import <WhirlyGlobe/MaplyImageTile.h>
+#import <WhirlyGlobe/MaplyQuadImageLoader.h>
+#import <WhirlyGlobe/MaplyQuadImageFrameLoader.h>
+#import <WhirlyGlobe/MaplyQuadPagingLoader.h>
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplySimpleTileFetcher.h>
+#import <WhirlyGlobe/MaplyQuadSampler.h>
+#import <WhirlyGlobe/MaplyRemoteTileFetcher.h>
+#import <WhirlyGlobe/GeoJSONSource.h>
+
+#import <WhirlyGlobe/MaplyWMSTileSource.h>
+#import <WhirlyGlobe/MaplyMBTileFetcher.h>
+
+#import <WhirlyGlobe/MaplyVariableTarget.h>
+#import <WhirlyGlobe/MaplyAtmosphere.h>
+#import <WhirlyGlobe/MaplyColorRampGenerator.h>
+#import <WhirlyGlobe/MaplyLight.h>
+#import <WhirlyGlobe/MaplyRenderTarget.h>
+#import <WhirlyGlobe/MaplyShader.h>
+#import <WhirlyGlobe/MaplyVertexAttribute.h>
+
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyComponentObject.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyComponentObject.h
new file mode 100644
index 0000000..59ccde6
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyComponentObject.h
@@ -0,0 +1,37 @@
+/*
+ * MaplyComponentObject.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 9/18/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+/**
+ Used to represent the view controller resources attached to one or more visual objects.
+
+ When you add one or more objects to a view controller, you'll get a component object back. It's an opaque object (seriously, don't look inside) that we use to track various resources within the toolkit.
+
+ You can keep these around to remove the visual objects you added earlier, but that's about all the interaction you'll have with them.
+ */
+@interface MaplyComponentObject : NSObject
+
+/// Construct with a description. Uses the kMaplyEnable.
+- (nonnull instancetype)initWithDesc:(NSDictionary *__nonnull)desc;
+
+@end
+
+typedef MaplyComponentObject WGComponentObject;
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyControllerLayer.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyControllerLayer.h
new file mode 100644
index 0000000..d8775d0
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyControllerLayer.h
@@ -0,0 +1,44 @@
+/*
+ * MaplyControllerLayer.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 10/25/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+/**
+ The View Controller Layer is a base class for other display layers.
+
+ You don't create these directly. This is a base class for other things. Its hooks into the rest of the system are hidden.
+ */
+@interface MaplyControllerLayer : NSObject
+
+/**
+ Set the priority for drawing.
+
+ This is how you control where the geometry produced by this layer shows up with respect to other layers and other geometry. This must be set immediately after creation. It will have undefined behavior after the layer has started.
+ */
+@property (nonatomic,assign) int drawPriority;
+
+/**
+ Set as unique identifier, or group...
+
+ use this property in order to localize this layer in the Globe/Map, you use in a predicate to catch as a load layer in Globe...
+ */
+@property (nonatomic, strong) NSString *identifier;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyCoordinate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyCoordinate.h
new file mode 100644
index 0000000..753b77e
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyCoordinate.h
@@ -0,0 +1,336 @@
+/*
+ * MaplyCoordinate.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 7/21/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+#import <CoreLocation/CoreLocation.h>
+
+/**
+ A 2D coordinate representation.
+
+ The Maply Coordinate is a simple 2 dimensional coordinate
+ passed around to numerous methods. For geo-coordinates x
+ maps to longitude and y to latitude and the values are
+ in radians.
+ */
+typedef struct
+{
+ float x,y;
+} MaplyCoordinate;
+
+
+extern const MaplyCoordinate kMaplyNullCoordinate;
+
+
+/**
+ Double precision version of 2D coordinate.
+
+ This works the same was as the MaplyCoordinate, but has
+ more precision.
+ */
+typedef struct
+{
+ double x,y;
+} MaplyCoordinateD;
+
+extern const MaplyCoordinateD kMaplyNullCoordinateD;
+
+
+/**
+ A 3D coordinate representation.
+
+ The 3D version of the Maply Coordinate adds a z values, often
+ in meters, but not always. Consult the appropriate method to
+ be sure.
+ */
+typedef struct
+{
+ float x,y,z;
+} MaplyCoordinate3d;
+
+/**
+ An NSObject based wrapper for 3D coordinates.
+
+ This wrapper encapsulates a MaplyCoordinate3d so we can pass them around in NSDictionary objects.
+ */
+@interface MaplyCoordinate3dWrapper : NSObject
+
+/// Initialize with a 3D coordinate
+- (instancetype)initWithCoord:(MaplyCoordinate3d)coord;
+
+/// 3D coordinate
+@property (nonatomic,readonly) MaplyCoordinate3d coord;
+
+@end
+
+typedef struct
+{
+ double x,y,z;
+} MaplyCoordinate3dD;
+
+extern const MaplyCoordinate3dD kMaplyNullCoordinate3dD;
+
+/**
+ An NSObject based wrapper for 3D coordinates.
+
+ This wrapper encapsulates a MaplyCoordinate3d so we can pass them around in NSDictionary objects.
+ */
+@interface MaplyCoordinate3dDWrapper : NSObject
+
+/// Initialize with a 3D coordinate
+- (instancetype)initWithCoord:(MaplyCoordinate3dD)coord;
+
+/// 3D coordinate
+@property (nonatomic,readonly) MaplyCoordinate3dD coord;
+
+@end
+
+/**
+ Represents a bounding box in a particular coordinate system.
+
+ ll is the lower left and ur is the upper right.
+ */
+typedef struct
+{
+ MaplyCoordinate ll;
+ MaplyCoordinate ur;
+} MaplyBoundingBox;
+
+extern const MaplyBoundingBox kMaplyNullBoundingBox;
+
+/**
+ A category that uses NSValue to store MaplyCoordinate data
+ */
+@interface NSValue (MaplyCoordinate)
++ (instancetype)valueWithMaplyCoordinate:(MaplyCoordinate)value;
+@property (readonly) MaplyCoordinate maplyCoordinateValue;
+@end
+
+/**
+ A category that uses NSValue to store MaplyCoordinateD data
+ */
+@interface NSValue (MaplyCoordinateD)
++ (instancetype)valueWithMaplyCoordinateD:(MaplyCoordinateD)value;
+@property (readonly) MaplyCoordinateD maplyCoordinateDValue;
+@end
+
+/**
+ A category that uses NSValue to store MaplyBoundingBox data
+ */
+@interface NSValue (MaplyBoundingBox)
++ (instancetype)valueWithMaplyBoundingBox:(MaplyBoundingBox)value;
+@property (readonly) MaplyBoundingBox maplyBoundingBoxValue;
+@end
+
+/**
+ Represents a bounding box in a particular coordinate system.
+
+ ll is the lower left and ur is the upper right.
+ */
+typedef struct
+{
+ MaplyCoordinateD ll;
+ MaplyCoordinateD ur;
+} MaplyBoundingBoxD;
+
+extern const MaplyBoundingBoxD kMaplyNullBoundingBoxD;
+
+#if __cplusplus
+extern "C" {
+#endif
+
+/**
+ Construct a MaplyCoordiante with longitude and latitude values in radians.
+
+ MaplyCoordinate's are in radians when they represent lon/lat values. This constructs one with radians as input.
+
+ @return A 2D MaplyCoordinate in radians (if representing a lon/lat value).
+ */
+MaplyCoordinate MaplyCoordinateMake(float radLon,float radLat);
+
+/**
+ Construct a MaplyCoordianteD with longitude and latitude values in radians.
+
+ MaplyCoordinate's are in radians when they represent lon/lat values. This constructs one with radians as input.
+
+ @return A 2D MaplyCoordinateD in radians (if representing a lon/lat value).
+ */
+MaplyCoordinateD MaplyCoordinateDMake(double radLon,double radLat);
+
+/**
+ Construct a MaplyGeoCoordinate with longitude and latitude values in degrees.
+
+ MaplyCoordinate's are in radians when they represent lon/lat values. This function does that conversion for you.
+
+ @param degLon The longitude value (east to west) in degrees.
+
+ @param degLat The latitude value (north to south) in degrees.
+
+ @return A 2D MaplyCoordinate in radians (if representing a lon/lat value).
+ */
+MaplyCoordinate MaplyCoordinateMakeWithDegrees(float degLon,float degLat);
+
+/**
+ Construct a MaplyGeoCoordinate with longitude and latitude values in degrees.
+
+ MaplyCoordinate's are in radians when they represent lon/lat values. This function does that conversion for you.
+
+ @param degLon The longitude value (east to west) in degrees.
+
+ @param degLat The latitude value (north to south) in degrees.
+
+ @return A 2D MaplyCoordinate in radians (if representing a lon/lat value).
+ */
+MaplyCoordinateD MaplyCoordinateDMakeWithDegrees(double degLon,double degLat);
+
+/**
+ Construct a MaplyCoordinateD with a MaplyCoordinate.
+
+ This function constructs a MaplyCoordinateD with the component values of the input MaplyCoordinate.
+
+ @param c The input MaplyCoordinate value.
+
+ @return A 2D MaplyCoordinateD in radians (if representing a lon/lat value).
+ */
+MaplyCoordinateD MaplyCoordinateDMakeWithMaplyCoordinate(MaplyCoordinate c);
+
+/**
+ Construct a MaplyCoordinate with a MaplyCoordinateD.
+
+ This function constructs a MaplyCoordinate with the component values of the input MaplyCoordinateD.
+
+ @param c The input MaplyCoordinateD value.
+
+ @return A 2D MaplyCoordinate in radians (if representing a lon/lat value).
+ */
+MaplyCoordinate MaplyCoordinateMakeWithMaplyCoordinateD(MaplyCoordinateD c);
+
+/**
+ Construct a MaplyCoordinat3d from the values given.
+
+ @param x The x value, or longitude in radians if we're making geo coordinates.
+
+ @param y The y value, or latitude in radians if we're making geo coordinates.
+
+ @param z The z value, sometimes this is display coordinates (radius == 1.0 for a sphere)
+ and sometimes this is meters. It depends on how you're using it.
+
+ @return A 3D MaplyCoordinate3d in radians + other (if representing a lon/lat value).
+ */
+MaplyCoordinate3d MaplyCoordinate3dMake(float x,float y,float z);
+
+/**
+ Construct a MaplyCoordinat3d from the values given.
+
+ @param x The x value, or longitude in radians if we're making geo coordinates.
+
+ @param y The y value, or latitude in radians if we're making geo coordinates.
+
+ @param z The z value, sometimes this is display coordinates (radius == 1.0 for a sphere)
+ and sometimes this is meters. It depends on how you're using it.
+
+ @return A 3D MaplyCoordinate3d in radians + other (if representing a lon/lat value).
+ */
+MaplyCoordinate3dD MaplyCoordinate3dDMake(double x,double y,double z);
+
+/**
+ Construct a MaplyBoundingBox from the values given.
+
+ The inputs are in degrees and the order is longitude *then* latitude.
+
+ @param degLon0 The left side of the bounding box in degrees.
+
+ @param degLat0 The bottom of the bounding box in degrees.
+
+ @param degLon1 The right side of the bounding box in degrees.
+
+ @param degLat1 The top of the bounding box in degrees.
+
+ @return A MaplyBoundingBox in radians.
+ */
+MaplyBoundingBox MaplyBoundingBoxMakeWithDegrees(float degLon0,float degLat0,float degLon1,float degLat1);
+
+/** Double version of MaplyBoundingBoxMakeWithDegrees
+ */
+MaplyBoundingBoxD MaplyBoundingBoxDMakeWithDegrees(double degLon0,double degLat0,double degLon1,double degLat1);
+
+/**
+ Check if two bounding boxes overlap.
+
+ @return Returns true if they did overlap, false otherwise.
+ */
+bool MaplyBoundingBoxesOverlap(MaplyBoundingBox bbox0,MaplyBoundingBox bbox1);
+
+/**
+ Check if a bounding contains a given coordinate.
+
+ @return Returns true if the bounding box contains the coordinate.
+ */
+bool MaplyBoundingBoxContains(MaplyBoundingBox bbox, MaplyCoordinate c);
+
+/**
+ Set up a bounding box from a list of 2D locations.
+ */
+MaplyBoundingBox MaplyBoundingBoxFromLocations(const CLLocationCoordinate2D locs[], unsigned int numLocs);
+
+/**
+ Set up a bounding box from a list of 2D coordinates
+ */
+MaplyBoundingBox MaplyBoundingBoxFromCoordinates(const MaplyCoordinate coords[], unsigned int numCoords);
+MaplyBoundingBox MaplyBoundingBoxFromCoordinatesD(const MaplyCoordinateD coords[], unsigned int numCoords);
+MaplyBoundingBoxD MaplyBoundingBoxDFromCoordinates(const MaplyCoordinate coords[], unsigned int numCoords);
+MaplyBoundingBoxD MaplyBoundingBoxDFromCoordinatesD(const MaplyCoordinateD coords[], unsigned int numCoords);
+
+/**
+ Expand a bounding box with a list of 2D coordinates
+ */
+MaplyBoundingBox MaplyBoundingBoxAddCoordinates(MaplyBoundingBox box, const MaplyCoordinate coords[], unsigned int numCoords);
+MaplyBoundingBox MaplyBoundingBoxAddCoordinatesD(MaplyBoundingBox box, const MaplyCoordinateD coords[], unsigned int numCoords);
+MaplyBoundingBoxD MaplyBoundingBoxDAddCoordinates(MaplyBoundingBoxD box, const MaplyCoordinate coords[], unsigned int numCoords);
+MaplyBoundingBoxD MaplyBoundingBoxDAddCoordinatesD(MaplyBoundingBoxD box, const MaplyCoordinateD coords[], unsigned int numCoords);
+
+/**
+ Return the intersection of two bounding boxes.
+ */
+MaplyBoundingBox MaplyBoundingBoxIntersection(MaplyBoundingBox bbox0,MaplyBoundingBox bbox1);
+
+/**
+ Expands a bounding box by a given fraction of its size.
+
+ @return Returns the expanded bounding box.
+ */
+MaplyBoundingBox MaplyBoundingBoxExpandByFraction(MaplyBoundingBox bbox, float buffer);
+
+/**
+ Calculate the great circle distance between two geo coordinates.
+
+ This calculates the distance on a sphere between one point and another.
+
+ @param p0 The starting point, lon/lat in radians.
+
+ @param p1 The end point, lon/lat in radians.
+
+ @return The distance between p0 and p1 in meters.
+ */
+double MaplyGreatCircleDistance(MaplyCoordinate p0,MaplyCoordinate p1);
+
+#if __cplusplus
+}
+#endif
+
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyCoordinateSystem.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyCoordinateSystem.h
new file mode 100644
index 0000000..d1ddf69
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyCoordinateSystem.h
@@ -0,0 +1,176 @@
+/* MaplyCoordinateSystem.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 5/13/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+/**
+ Coordinate system for tiling systems and data sources and such.
+
+ This object represents the spatial reference system and bounding box for objects like the MaplyTileSource or vectors or other things. Not all data is in lat/lon geographic (actually MaplyPlateCaree) nor is it always in MaplySphericalMercator. Sometimes it's in one or the other, or a bit of both.
+
+ We use this base class to express the coordinate system and we threw in the bounding box, which we will surely come to regret. Oh well, it's in there.
+
+ This object gets passed around to tell us what coordinate system data is in or how we're displaying things. Right now only MaplySphericalMercator and MaplyPlateCarree are represented. In the future, there will be more.
+ */
+@interface MaplyCoordinateSystem : NSObject
+
+/**
+ Set the bounding box in the local coordinate system.
+
+ This is the bounding box, for things like display coordinates. If the extents would normally be in degrees, use radians. Otherwise, the values are in the local system.
+ */
+- (void)setBounds:(MaplyBoundingBox)bounds;
+
+/**
+ Set the bounding box in the local coordinate system.
+
+ This is the bounding box, for things like display coordinates. If the extents would normally be in degrees, use radians. Otherwise, the values are in the local system.
+ */
+- (void)setBoundsD:(MaplyBoundingBoxD)boundsD;
+
+/**
+ Set the bounding box in the local coordinate system.
+
+ This is the bounding box, for things like display coordinates. If the extents would normally be in degrees, use radians. Otherwise, the values are in the local system.
+ */
+- (void)setBoundsLL:(MaplyCoordinate * __nonnull)ll ur:(MaplyCoordinate * __nonnull)ll;
+
+/**
+ Return the bounding box in local coordinates.
+
+ This is the bounding box in local coordinates, or if the extents would normally be expressed in degrees, it's radians.
+ */
+- (MaplyBoundingBox)getBounds;
+
+/**
+ Return the bounding box in local coordinates.
+
+ This is the bounding box in local coordinates, or if the extents would normally be expressed in degrees, it's radians.
+ */
+- (void)getBoundsLL:(MaplyCoordinate * __nonnull)ret_ll ur:(MaplyCoordinate * __nonnull)ret_ur;
+
+/**
+ Convert a coordinate from geographic to the local coordinate system.
+
+ Take a geo coordinate (lon/lat in radians) and convert to the local space.
+ */
+- (MaplyCoordinate)geoToLocal:(MaplyCoordinate)coord;
+
+/**
+ Convert a coordinate from the local space to geographic.
+
+ This takes a coordinate in this coordinate system and converts it to geographic (lat/lon in radians).
+ */
+- (MaplyCoordinate)localToGeo:(MaplyCoordinate)coord;
+
+/**
+ Convert a 3D coordinate from the local space to geocentric.
+
+ This takes a 3D coordinate (including height) and converts it to geocentric in WGS84.
+ */
+- (MaplyCoordinate3dD)localToGeocentric:(MaplyCoordinate3dD)coord;
+
+/**
+ Convert a 3D coordinate from geocentric to the local space.
+
+ This takes a 3D geocentric coordinate (WGS84) and converts it to the local space, including height;
+ */
+- (MaplyCoordinate3dD)geocentricToLocal:(MaplyCoordinate3dD)coord;
+
+/**
+ Express the coordinate system in an SRS compatible string.
+ */
+- (NSString * __nonnull)getSRS;
+
+/**
+ Can this coordinate system be expressed in degrees?
+
+ This is set for coordinate systems that express their extents in degrees. This is useful for cases where we need to construct some metadata to go along with the system and you'd normally expect it to be in degrees rather than radians.
+ */
+- (bool)canBeDegrees;
+
+@end
+
+/**
+ Plate Carree is lat/lon stretched out to its full extents.
+
+ This coordinate system is used when we're tiling things over the whole earth, from -180 to +180 and from -90 to +90. Use this if you chopped up your data in that way.
+ */
+@interface MaplyPlateCarree : MaplyCoordinateSystem
+
+/// Initialize with Plate Carree covering the whole globe.
+- (nonnull instancetype)init;
+
+/// Initialize with Plate Carree covering the whole globe.
+- (nullable instancetype)initFullCoverage;
+
+/// Initialize with the given bounding box (in radians)
+- (nullable instancetype)initWithBoundingBox:(MaplyBoundingBox)bbox;
+
+/// Initialize with the given bounding box (in radians)
+- (nullable instancetype)initWithBoundingBoxD:(MaplyBoundingBoxD)bbox;
+
+@end
+
+/**
+ Spherical Mercator is what you'll most commonly see on web maps.
+
+ The Spherical Mercator system, with web extents is what MapBox, Google, Bing, etc. use for their maps. If you ever want to annoy a cartographer, suggest that spherical mercator is all you ever really need.
+
+ The drawback with Spherical Mercator is that it doesn't cover the poles and it distorts (and how) its north and south extents. Web Standard refers to the extents you'll find in most online maps. This is probably want you want.
+ */
+@interface MaplySphericalMercator : MaplyCoordinateSystem
+
+/// Initialize with the -85...,+85... extents to match most comm only used online maps
+- (nonnull instancetype)init;
+
+/// Initialize with the -85...,+85... extents to match most commonly used online maps
+- (nonnull instancetype)initWebStandard;
+
+@end
+
+/**
+ A generic coordinate system wrapper around proj4.
+
+ You create one of these with a proj4 string. It'll act like a normal MaplyCoordinateSysterm after that.
+
+ Be sure to check that the system is valid. The proj4 string could be wrong.
+ */
+@interface MaplyProj4CoordSystem : MaplyCoordinateSystem
+
+/**
+ Initialize with a proj4 compatible string
+
+ Since this is just a proj.4 wrapper, we need an initialization string that it can parse.
+ */
+- (nonnull instancetype)initWithString:(NSString * __nonnull)proj4Str;
+
+/// True if the proj.4 string was valid and the coordinate system can work.
+- (bool)valid;
+
+@end
+
+/**
+ Generate the correct coordinate system from a standard EPSG.
+
+ This returns the correct coordinate system from a standard EPSG string.
+
+ The list of available coordinate systems is very short.
+ */
+MaplyCoordinateSystem * __nullable MaplyCoordinateSystemFromEPSG(NSString * __nonnull crs);
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyDoubleTapDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyDoubleTapDelegate.h
new file mode 100644
index 0000000..963d108
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyDoubleTapDelegate.h
@@ -0,0 +1,25 @@
+/* MaplyDoubleTapDelegate.h
+ *
+ * Created by Jesse Crocker on 2/3/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyZoomGestureDelegate.h>
+
+@interface MaplyDoubleTapDelegate : MaplyZoomGestureDelegate
+
+/// How long we animate from starting to end point
+@property (nonatomic) float animTime;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyDoubleTapDragDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyDoubleTapDragDelegate.h
new file mode 100644
index 0000000..53b4233
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyDoubleTapDragDelegate.h
@@ -0,0 +1,22 @@
+/* MaplyDoubleTapDragDelegate.h
+ *
+ * Created by Steve Gifford on 2/7/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyZoomGestureDelegate.h>
+
+@interface MaplyDoubleTapDragDelegate : MaplyZoomGestureDelegate
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyGeomBuilder.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyGeomBuilder.h
new file mode 100644
index 0000000..65a4374
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyGeomBuilder.h
@@ -0,0 +1,301 @@
+/*
+ * MaplyGeomModelBuilder.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 1/20/16
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+#import <WhirlyGlobe/MaplyGeomModel.h>
+
+/**
+ Geometry State is used to describe the visual look of objects as they're added.
+
+ Set the various fields in the geometry state to control how geometry looks when you add it.
+ There are defaults for all of these fields.
+ */
+@interface MaplyGeomState : NSObject
+
+/// Color to use for the geometry
+@property (nonatomic,strong) UIColor *color;
+
+/// Background color for text
+@property (nonatomic,strong) UIColor *backColor;
+
+/// UIImage for MaplyTexture to apply to geometry
+@property (nonatomic,strong) id texture;
+
+/// For more than one texture, use addTexture
+- (void)addTexture:(MaplyTexture *)texture;
+
+@end
+
+/**
+ The geometry builder is used to construct 3D models.
+
+ You use the geometry builder when you have a custom 3D model to build. This can include things like airport runways, buildings, or anything else that's particular to a certain location.
+
+ Start by construting the builder and then adding polygons and strings to it.
+
+ You can combine multiple geometry builders together to build up repeated portions of a model.
+
+ The builder has an "immediate mode" where you add points individually to build up polygons and then add those. This is one of the simpler ways to use the system.
+ */
+@interface MaplyGeomBuilder : NSObject
+
+/// Intialize with the view controller the model will be used in.
+- (id)initWithViewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+/**
+ Create a rectangle around the origin.
+
+ This creates a flat rectangle around the origin (0,0,0) with z = 0.
+
+ @param size The size of the rectangle (x,y).
+
+ @param state The visual state to use when creating the geometry.
+ */
+- (void)addRectangleAroundOrigin:(MaplyCoordinateD)size state:(MaplyGeomState *)state;
+
+/**
+ Create a rectangle around the origin.
+
+ This creates a flat rectangle around the origin (0,0,0) with z = 0.
+
+ @param x Horizontal size of the rectangle.
+
+ @param y Vertical size of the rectangle.
+
+ @param state The visual state to use when creating the geometry.
+ */
+- (void)addRectangleAroundOriginX:(double)x y:(double)y state:(MaplyGeomState *)state;
+
+/**
+ Create a rectangle around the given point.
+
+ This creates a flat rectangle around the point x,y with z = 0.
+
+ @param x X location around which to create the rectangle.
+
+ @param y Y location around which to create the rectangle.
+
+ @param width Horizontal size of the rectangle.
+
+ @param height Vertical size of the rectangle.
+
+ @param state The visual state to use when creating the geometry.
+ */
+- (void)addRectangleAroundX:(double)x y:(double)y width:(double)width height:(double)height state:(MaplyGeomState *)state;
+
+/**
+ Add an attributed string to the geometry builder.
+
+ Add an attributed string, which contains information about color and front to the geometry builder.
+
+ @param str String to add to the geometry.
+
+ @param state The visual state to use when creating the geometry.
+ */
+- (void)addAttributedString:(NSAttributedString *)str state:(MaplyGeomState *)state;
+
+/**
+ Add a string to the geometry.
+
+ Add a string at (0,0) to the geometry with the given font and visual state. The font determines size.
+
+ @param str String to add to geometry.
+
+ @param font Font to use for the string.
+
+ @param state The visual state to use when creating the geometry.
+ */
+- (void)addString:(NSString *)str font:(UIFont *)font state:(MaplyGeomState *)state;
+
+/**
+ Add a string to the geometry.
+
+ Add a string at (0,0) to the geometry with the given font and visual state.
+
+ The string will be scaled to match the width and/or height given. If one of width or height is 0.0 it will be calculated from the other.
+
+ @param str String to add to geometry.
+
+ @param width Width of the string in the final geometry. If set to 0.0, will be calculated.
+
+ @param height Height of the string in the final geometry. If set to 0.0, will be calculated.
+
+ @param font Font to use for the string.
+
+ @param state The visual state to use when creating the geometry.
+ */
+- (void)addString:(NSString *)str width:(double)width height:(double)height font:(UIFont *)font state:(MaplyGeomState *)state;
+
+/**
+ Add a polygon with the given visual state.
+
+ Tesselates the given polygon and adds the resulting triangles to the geometry.
+
+ @param pts An array of 3D points.
+
+ @param numPts Number of points in the 3D array.
+
+ @param state The visual state to use when creating the geometry.
+ */
+- (void)addPolygonWithPts:(MaplyCoordinate3dD *)pts numPts:(int)numPts state:(MaplyGeomState *)state;
+
+/**
+ Add a polygon with the given visual state.
+
+ Tesselates the given polygon and adds the resulting triangles to the geometry.
+
+ @param pts An array of 3D points.
+
+ @param tex Texture coordinates. One for each point.
+
+ @param norms Normals to go with the points.
+
+ @param numPts Number of points in the 3D array.
+
+ @param state The visual state to use when creating the geometry.
+ */
+- (void)addPolygonWithPts:(MaplyCoordinate3dD *)pts tex:(MaplyCoordinateD *)tex norms:(MaplyCoordinate3dD *)norms numPts:(int)numPts state:(MaplyGeomState *)state;
+
+/**
+ Add a point in immediate mode.
+
+ When in immediate mode points are collected until an addCurPoly call. This adds a 3D point.
+ */
+- (void)addCurPointX:(double)x y:(double)y z:(double)z;
+
+/**
+ Add a point in immediate mode
+
+ When in immediate mode points are collected until an addCurPoly call. This add a point at (x,y,0).
+ */
+- (void)addCurPointX:(double)x y:(double)y;
+
+/**
+ Add the current polygon in immediate mode.
+
+ When in immediate mode points are collected until you call this method. Then the points will be tesselated into a set of triangles and added to the geometry with the given visual state.
+ */
+- (void)addCurPoly:(MaplyGeomState *)state;
+
+/**
+ Scale the geometry and strings by this amount.
+
+ The geometry and strings are scaled by the given amount in each dimension.
+ */
+- (void)scale:(MaplyCoordinate3dD)scale;
+
+/**
+ Scale the geometry and strings by the given amount.
+
+ The geometry and strings are scaled by (x,y,z).
+ */
+- (void)scaleX:(double)x y:(double)y z:(double)z;
+
+/**
+ Translate the geometry and strings by the given amount.
+
+ The geometry and strings are translated by the given coordinate.
+ */
+- (void)translate:(MaplyCoordinate3dD)trans;
+
+/**
+ Translate the geometry and strings by the given amount.
+
+ The geometry and strings are translated by (x,y,z).
+ */
+- (void)translateX:(double)x y:(double)y z:(double)z;
+
+/**
+ Rotate the geometry around the given axis by the given angle.
+
+ Roate around the given 3D axis by the number of radians in angle.
+
+ @param angle The angle in radians to rotate by.
+
+ @param axis The axis to rotate around. (0,0,1) would rotate around the Z axis.
+ */
+- (void)rotate:(double)angle around:(MaplyCoordinate3dD)axis;
+
+/**
+ Rotate the geometry around the given axis by the given angle.
+
+ Roate around the given 3D axis by the number of radians in angle.
+
+ @param angle The angle in radians to rotate by.
+
+ @param x X component of the axis to rotate around.
+
+ @param y Y component of the axis to rotate around.
+
+ @param z Z component of the axis to rotate around.
+ */
+- (void)rotate:(double)angle aroundX:(double)x y:(double)y z:(double)z;
+
+/**
+ Apply a transform to the geometry and strings.
+
+ This applies a general 4x4 transform to the geometry and strings. You can construct the MaplyMatrix using a number of different options and combine multiple matrices.
+ */
+- (void)transform:(MaplyMatrix *)matrix;
+
+/**
+ Add the geometry from another builder.
+
+ Multiple geometry builders can be combined to build complex objects.
+
+ This method copies geometry and strings, including their transforms to the current builder.
+ */
+- (void)addGeomFromBuilder:(MaplyGeomBuilder *)modelBuilder;
+
+/**
+ Add the geometry from another builder, applying the given transform.
+
+ Multiple geometry builders can be combined to build complex objects.
+
+ This method transform the source geometry and strings and copies them into the current builder.
+ */
+- (void)addGeomFromBuilder:(MaplyGeomBuilder *)modelBuilder transform:(MaplyMatrix *)matrix;
+
+/**
+ Calculate the bounding box of geometry and strings.
+
+ Calculates the lower left and upper right corners of a rectangular solid that surrounds the geometry and strings for this builder.
+
+ This returns false if there is no valid geometry (or strings) and takes transforms into account if there is.
+ */
+- (bool)getSizeLL:(MaplyCoordinate3dD *)ll ur:(MaplyCoordinate3dD *)ur;
+
+/**
+ Calculate and returns the size of the geometry and strings.
+
+ Calculates the size of the geometry and strings in the builder, taking transforms into account.
+ */
+- (MaplyCoordinate3dD)getSize;
+
+/**
+ Generate a valid MaplyGeomModel that can be instanced and used as a 3D model.
+
+ This call returns a MaplyGeomModel. You'll need a model to make MaplyGeomModelInstance objects and for the addModelInstances:desc:mode: call to a NSObject<MaplyRenderControllerProtocol> (map or globe).
+ */
+- (MaplyGeomModel *)makeGeomModel:(MaplyThreadMode)threadMode;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyGeomModel.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyGeomModel.h
new file mode 100644
index 0000000..7e41021
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyGeomModel.h
@@ -0,0 +1,122 @@
+/*
+ * MaplyGeomModel.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 11/26/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyMatrix.h>
+#import <WhirlyGlobe/MaplyShape.h>
+
+@class MaplyShader;
+
+/**
+ Contains a big pile of geometry and textures (e.g. a model).
+
+ The geometry model
+ */
+@interface MaplyGeomModel : NSObject
+
+/**
+ Initialize with the full path to a Wavefront OBJ model file.
+
+ This creates a model from a Wavefront OBJ file, a standard, simple file format for models. You can then instance and place this model where you might like.
+ */
+- (nullable instancetype)initWithObj:(NSString *__nonnull)fullPath;
+
+/**
+ Initialize with a shape.
+
+ The given shape will be turned into a geometry model so it can be instanced.
+ */
+- (nonnull instancetype)initWithShape:(MaplyShape *__nonnull)shape;
+
+@end
+
+
+/**
+ Place a geometry model at a given location
+
+ Geometry models tend to be expensive so we load and place them in a two step process. First you create the MaplyGeomModel and then you place it in one or more spots with this MaplyGeomModelInstance.
+ */
+@interface MaplyGeomModelInstance : NSObject
+
+/**
+ User data object for selection
+
+ When the user selects a feature and the developer gets it in their delegate, this is an object they can use to figure out what the model instance means to them.
+ */
+@property (nonatomic,strong,nullable) id userObject;
+
+/// The model to instance
+@property (nonatomic,strong,nullable) MaplyGeomModel *model;
+
+/**
+ Where we'd like to place the instanced model.
+
+ This is the center of the object in geographic radians.
+ */
+@property (nonatomic) MaplyCoordinate3d center;
+
+/// Transform used to oriented the model instance
+@property (nonatomic,strong,nullable) MaplyMatrix *transform;
+
+/// Color to force all polygons to use.
+/// If set, this will force all polygons to use this color. nil by default.
+@property (nonatomic,strong,nullable) UIColor *colorOverride;
+
+/// Set if you want to select these
+@property (nonatomic) bool selectable;
+
+@end
+
+/**
+ A version of the geometry model instance that moves.
+
+ This version of the geometry model instance can move in a limited way over time.
+ */
+@interface MaplyMovingGeomModelInstance : MaplyGeomModelInstance
+
+/// The end point for animation
+@property (nonatomic,assign) MaplyCoordinate3d endCenter;
+
+/// How long it will take to get to the endCenter
+@property (nonatomic,assign) NSTimeInterval duration;
+
+@end
+
+/**
+ Sometimes we don't know how many instances there will be of a model until
+ some logic runs on the GPU. We can then take that number and run that
+ number of instances of the given model. [Metal only]
+ */
+@interface MaplyGeomModelGPUInstance : NSObject
+
+/// The model to instance
+@property (nonatomic,strong,nullable) MaplyGeomModel *model;
+
+/// Texture to derive the number of instances from (picked out of the highest, smallest level)
+@property (nonatomic,nullable) MaplyTexture *numInstSource;
+
+/// Need a shader to pull the number of instances out of a texture and shove them in the indirect buffer
+@property (nonatomic,nullable) MaplyShader *numInstShader;
+
+/// Shader to run over for this instance
+@property (nonatomic,nullable) MaplyShader *shader;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyGlobeRenderController.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyGlobeRenderController.h
new file mode 100644
index 0000000..27c7afd
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyGlobeRenderController.h
@@ -0,0 +1,115 @@
+/*
+* MaplyGlobeRenderController.h
+* WhirlyGlobeComponent
+*
+* Created by Steve Gifford on 10/23/10.
+* Copyright 2011-2022 mousebird consulting
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+#import <WhirlyGlobe/MaplyRemoteTileFetcher.h>
+
+/**
+ Animation State used by the WhirlyGlobeViewControllerAnimationDelegate.
+
+ You fill out one of these when you're implementing the animation delegate. Return it and the view controller will set the respective values to match.
+ */
+@interface WhirlyGlobeViewControllerAnimationState : NSObject
+
+/// Heading is calculated from due north
+/// If not set or set to MAXFLOAT, this is ignored
+@property (nonatomic) double heading;
+
+/// Height above the globe
+@property (nonatomic) double height;
+
+/// Tilt as used in the view controller
+/// If not set or set to MAXFLOAT, we calculate tilt the regular way
+@property (nonatomic) double tilt;
+
+/// Roll as used in the view controller
+@property (nonatomic) double roll;
+
+/// Position to move to on the globe
+@property (nonatomic) MaplyCoordinateD pos;
+
+/// If set, this is a point on the screen where pos should be.
+/// By default this is (-1,-1) meaning the screen position is just the middle. Otherwise, this is where the position should wind up on the screen, if it can.
+@property (nonatomic) CGPoint screenPos;
+
+/// If set, the globe will be centered at this point on the screen
+@property (nonatomic) CGPoint globeCenter;
+
+/**
+ Interpolate a new state between the given states A and B.
+
+ This does a simple interpolation (lat/lon, not great circle) between the two animation states.
+ */
++ (nonnull WhirlyGlobeViewControllerAnimationState *)Interpolate:(double)t from:(WhirlyGlobeViewControllerAnimationState *__nonnull)stateA to:(WhirlyGlobeViewControllerAnimationState *__nonnull)stateB;
+
+@end
+
+/**
+ The Globe Render Controller is a standalone renderer for the globe.
+ This is separate from the WhirlyGlobeViewController, but performs a similar function for
+ offline rendering.
+ */
+@interface WhirlyGlobeRenderController : MaplyRenderController
+
+/// Initialize with the size of the target rendering buffer
+- (instancetype __nullable) initWithSize:(CGSize)screenSize mode:(MaplyRenderType)renderType;
+
+/// Initialize as an offline renderer of a given target size with default renderer (Metal)
+- (instancetype __nullable)initWithSize:(CGSize)size;
+
+/** Set this if you're doing frame by frame animation.
+ It will move particles along and run any animations you may have going.
+ **/
+@property (nonatomic,assign) NSTimeInterval currentTime;
+
+/**
+ Set the viewing state all at once
+
+ This sets the position, tilt, height, screen position and heading all at once.
+ */
+- (void)setViewState:(WhirlyGlobeViewControllerAnimationState *__nonnull)viewState;
+
+/**
+ Make a WhirlyGlobeViewControllerAnimationState object from the current view state.
+
+ This returns the current view parameters in a single WhirlyGlobeViewControllerAnimationState.
+ */
+- (nullable WhirlyGlobeViewControllerAnimationState *)getViewState;
+
+/**
+ Takes a snapshot of the current OpenGL view and returns it.
+ */
+- (UIImage *__nullable)snapshot;
+
+/**
+ This version of snapshot just returns the raw NSData from the "screen".
+ */
+- (NSData *__nullable)snapshotData;
+
+
+/**
+ If set, keep north facing upward on the screen as the user moves around.
+
+ Off by default.
+ */
+@property(nonatomic,assign) bool keepNorthUp;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyIconManager.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyIconManager.h
new file mode 100644
index 0000000..7e19b44
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyIconManager.h
@@ -0,0 +1,140 @@
+/*
+ * MaplyIconManager.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 1/11/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+
+/**
+ Holds info about a single style from the MaplySimpleStyleManager.
+ This is enough to build a marker (or other thing, if you like).
+ */
+@interface MaplySimpleStyle : NSObject
+
+/// If there was a title, this is it
+@property (nonatomic,nullable) NSString *title;
+
+/// If there was a description, this is it
+@property (nonatomic,nullable) NSString *desc;
+
+/// Size (in pixels) of the marker to be built
+@property (nonatomic) CGSize markerSize;
+
+/// How big we consider the marker to be when doing layout.
+/// By default, same as the marker size
+@property (nonatomic) CGSize layoutSize;
+
+/// Offset applied to marker
+@property (nonatomic) CGPoint markerOffset;
+
+/// Texture constructed for this icon, if there was a symbol
+@property (nonatomic,nullable) MaplyTexture *markerTex;
+
+/// If this was 0-9 or a-Z instead, this is that
+@property (nonatomic,nullable) NSString *markerString;
+
+/// Color to set for the markert
+@property (nonatomic,nonnull) UIColor *color;
+
+/// Stroke color if there is one
+@property (nonatomic,nonnull) UIColor *strokeColor;
+
+/// Stroke opacity
+@property (nonatomic) float strokeOpacity;
+
+/// Stroke width, if available. Takes scale into account.
+@property (nonatomic) float strokeWidth;
+
+/// Fill color if available
+@property (nonatomic,nonnull) UIColor *fillColor;
+
+/// Fill opacity, if available
+@property (nonatomic) float fillOpacity;
+
+@end
+
+/** Used to generate icons and parse styles for the GeoJSON simple Style spec.
+ https://github.com/mapbox/simplestyle-spec
+
+ Can also be used to define some very simple icon styles directly.
+ */
+@interface MaplySimpleStyleManager : NSObject
+
+/** Fetch the simple UIImage for the icon with the given name.
+ **/
++ (nullable UIImage *)iconForName:(NSString *__nonnull)name size:(CGSize)size;
+
+/** Slightly more complex icon
+ **/
++ (nullable UIImage *)iconForName:(NSString *__nullable)name size:(CGSize)size color:(UIColor *__nullable)color circleColor:(UIColor *__nullable)circleColor strokeSize:(float)strokeSize strokeColor:(UIColor *__nullable)strokeColor;
+
+/** Clear the cache
+ */
++ (void)clearIconCache;
+
+/**
+ Set up the icon manager this way to build textures associated with a particular view controller.
+ */
+- (nonnull id)initWithViewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+/// Markers can be three different sizes. These are the actual sizes associated
+@property (nonatomic) CGSize smallSize,medSize,largeSize;
+
+/// Normal scale from device (e.g. 2x for retina and so on)
+@property (nonatomic) CGFloat scale;
+
+/// We normally put a stroke around generated icons
+/// This is the width (in pixels) of that stroek
+@property (nonatomic) CGFloat strokeWidthForIcons;
+
+/// If set (default) we'll center the marker. If off we'll offset vertically
+@property (nonatomic) bool centerIcon;
+
+/**
+ Mapbox defines a simple style spec that's usually associated with GeoJSON data. Github is a prominent user.
+
+ Pass in a dictionary parsed from JSON (or just make it up yourself) and this will produce (an optional) icon and parse out the rest.
+ This takes screen scale and such into account. It will also cache the same description when passed in multiple times.
+*/
+- (MaplySimpleStyle * __nonnull)makeStyle:(NSDictionary *__nonnull)dict;
+
+/**
+ Takes a single vector object. It will parse out the simple style from the attributes (or provide a default if there is none)
+ and then build the corresponding feature and return a MaplyComponentObject to represent it.
+
+ mode controls if this work is done on this thread or another.
+ */
+- (MaplyComponentObject * __nullable)addFeature:(MaplyVectorObject * __nonnull)vecObj mode:(MaplyThreadMode)mode;
+
+/**
+ Takes an array of vector objects and calls addFeature: on each one.
+
+ mode controls if this work is done on this thread or another.
+ */
+- (NSArray<MaplyComponentObject *> * __nonnull)addFeatures:(NSArray<MaplyVectorObject *> * __nonnull)vecObjs mode:(MaplyThreadMode)mode;
+
+/** Clear the icon cache.
+ Any references to the textures should already be cleared.
+ */
+- (void)clearCache;
+
+/// Delete any cached textures and such
+- (void)shutdown;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyImageTile.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyImageTile.h
new file mode 100644
index 0000000..808634d
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyImageTile.h
@@ -0,0 +1,113 @@
+/*
+ * MaplyImageTile.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 10/18/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+
+@class MaplyElevationChunk;
+
+/**
+ Describes a single tile worth of data, which may be multiple images.
+
+ Delegates can pass back a single UIImage or NSData object, but if they want to do anything more complex, they need to do it with this.
+ */
+@interface MaplyImageTile : NSObject
+
+/**
+ Initialize with an NSData object containing 32 bit pixels.
+
+ This sets up the tile with an NSData object containing raw pixels. The pixels are 32 bit RGBA even if you're targeting a smaller pixel format.
+
+ @param data The NSData object containing 32 bit RGBA pixels.
+
+ @param width The width of the raw image contained in the data object.
+
+ @param height The height of the raw image contained in the data object.
+ */
+- (instancetype)initWithRawImage:(NSData *)data width:(int)width height:(int)height viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+/**
+ Initialize with an NSData object containing 32 bit pixels.
+
+ This sets up the tile with an NSData object containing raw pixels. The pixels are 32 bit RGBA even if you're targeting a smaller pixel format.
+
+ @param data The NSData object containing 32 bit RGBA pixels.
+
+ @param width The width of the raw image contained in the data object.
+
+ @param height The height of the raw image contained in the data object.
+
+ @param comp The number of components (1, 2 or 4)
+ */
+- (instancetype)initWithRawImage:(NSData *)data width:(int)width height:(int)height components:(int)comp viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+/**
+Initialize with an NSData object containing pixels of a given format.
+
+This sets up the tile with an NSData object containing raw pixels. The pixels are defined by the format.
+
+@param data The NSData object containing pixels.
+
+@param format The image format the data is already in.
+
+@param width The width of the raw image contained in the data object.
+
+@param height The height of the raw image contained in the data object.
+*/
+- (instancetype)initWithRawImage:(NSData *)data format:(MaplyQuadImageFormat)format width:(int)width height:(int)height viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+/**
+ Initialize with a single UIImage for the tile.
+
+ This sets up the given UIImage as the return for the given tile. You can then set targetSize and such.
+ */
+- (instancetype)initWithImage:(UIImage *)image viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+/**
+ Initialize with an NSData object containing PNG or JPEG data that can be interpreted by UIImage.
+
+ We're expecting PNG, JPEG or another self identified format (e.g. PKM). These we can interpret ourselves.
+ */
+- (instancetype)initWithPNGorJPEGData:(NSData *)data viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+/**
+ Border size that was set on initialization.
+
+ If there's a built in border as part of the image data passed in during initialization, set it here.
+ Normally this is 0.
+ */
+@property (nonatomic,assign) int borderSize;
+
+/**
+ Target size for the image(s) represented by this tile.
+
+ This instructs the pager to rescale the image(s) to the given target size. This is probably faster than doing it yourself because we can extract the data and rescale in the same step.
+ */
+@property (nonatomic) CGSize targetSize;
+
+/**
+ Preprocess into a simple texture format.
+
+ Extracting from PNG or JPEG or whatever often requires a bit of work. We'll do that work later,
+ if this isn't called. But if you do call it here then you can do that work on your own thread.
+ */
+- (void)preprocessTexture;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyLabel.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyLabel.h
new file mode 100644
index 0000000..ddd52a2
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyLabel.h
@@ -0,0 +1,101 @@
+/*
+ * WGLabel.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 7/24/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+typedef NS_ENUM(NSInteger, MaplyLabelJustify) {
+ MaplyLabelJustifyLeft,
+ MaplyLabelJustifyMiddle,
+ MaplyLabelJustifyRight
+};
+
+/**
+ This is a 3D label.
+
+ The Maply Label is a 3D object that sits on top of the globe (or map) at a specified location. If you want a 2D label that sits on top of everything else, you want the MaplyScreenLabel. Seriously, you probably want that.
+ */
+@interface MaplyLabel : NSObject
+
+/**
+ The location (in geographic) for this label.
+
+ The Maply Label is a 3D object and this is its location on the globe or map. The coordinates are in geographic (lon/lat) and the actual layout is controleld by justify.
+ */
+@property (nonatomic,assign) MaplyCoordinate loc;
+
+/**
+ Size of the label in display units.
+
+ The Maply Label is a 3D object placed on top of the globe or map. This controls the size of that label in display coordinates. For the globe display coordinates are based on a radius of 1.0.
+
+ One or both values of the size can be set. Typically you want to set the height and let the toolkit calculate the width.
+ */
+@property (nonatomic,assign) CGSize size;
+
+/// The text to display on the globe or map at the given location.
+@property (nonatomic,strong) NSString * __nullable text;
+
+/**
+ Text can be accompanied by an optional icon image.
+
+ If set, we'll put this image to the left of the text in the label. The UIImage (or MaplyTexture) will be tracked by the view controller and reused as needed or disposed of when no longer needed.
+
+ The name had to change because Apple's private selector search is somewhat weak.
+ */
+@property (nonatomic,strong) id __nullable iconImage2;
+
+/**
+ An option color override.
+
+ If set, this color will override the color passed in with the NSDictionary in the view controller's add method.
+ */
+@property (nonatomic,strong) UIColor * __nullable color;
+
+/**
+ Label selectability. On by default
+
+ If set, this label can be selected by the user. If not set, this label will never appear in selection results.
+ */
+@property (nonatomic,assign) bool selectable;
+
+/**
+ The text justification based on the location.
+
+ Text can be placed around the location based on this value.
+
+|Justify Value|Description|
+|:------------|:----------|
+|MaplyLabelJustifyLeft|The label will be placed with its left side on the location.|
+|MaplyLabelJustifyMiddle|The label will be centered on the location.|
+|MaplyLabelJustifyRight|The label will be placed with its right side on the location.|
+ */
+@property (nonatomic,assign) MaplyLabelJustify justify;
+
+/**
+ User data object for selection
+
+ When the user selects a feature and the developer gets it in their delegate, this is an object they can use to figure out what the label means to them.
+ */
+@property (nonatomic,strong) id __nullable userObject;
+
+@end
+
+typedef MaplyLabel WGLabel;
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyLight.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyLight.h
new file mode 100644
index 0000000..31c415f
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyLight.h
@@ -0,0 +1,60 @@
+/* MaplyLight.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 1/30/13.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+/**
+ The Light provides a simple interface to basic lighting within the toolkit.
+
+ You can have up to 8 lights in the current version of the toolkit. Obviously this is all shader implementation with OpenGL ES 2.0, so you can always just bypass this and do what you like. However, the default shaders will look for these lights.
+
+ The lights are very simple, suitable for the globe, and contain a position, a couple of colors, and a view dependent flag.
+ */
+@interface MaplyLight : NSObject
+
+/**
+ The location of this particular light in display space.
+
+ This is a single light's location in display space. Display space for the globe is based on a radius of 1.0.
+ */
+@property (nonatomic,assign) MaplyCoordinate3d pos;
+
+/**
+ Controls whether the light takes the model matrix into account or not.
+
+ If set, this light moves with the model (usually the globe). You'd use this for a real sun position. If not set, the light is static and does not move or rotate.
+ */
+@property (nonatomic,assign) bool viewDependent;
+
+/**
+ Ambient color for the light.
+
+ This color will always be added to any given pixel. It provides a baseline lighting value.
+ */
+@property (nonatomic,strong) UIColor *__nullable ambient;
+
+/**
+ Diffuse light color.
+
+ The diffuse color is multiplied by a directional value and so will vary depending on geometry normals.
+ */
+@property (nonatomic,strong) UIColor *__nullable diffuse;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyLocationTracker.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyLocationTracker.h
new file mode 100644
index 0000000..76e6ebc
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyLocationTracker.h
@@ -0,0 +1,174 @@
+/*
+ * MaplyBaseViewController.h
+ * MaplyComponent
+ *
+ * Created by Ranen Ghosh on 11/23/16.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <CoreLocation/CoreLocation.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+#define LOC_TRACKER_POS_MARKER_SIZE 32
+
+@class MaplyBaseViewController;
+
+typedef struct
+{
+ float lonDeg;
+ float latDeg;
+ float headingDeg;
+} MaplyLocationTrackerSimulationPoint;
+
+typedef enum {MaplyLocationLockNone, MaplyLocationLockNorthUp, MaplyLocationLockHeadingUp, MaplyLocationLockHeadingUpOffset} MaplyLocationLockType;
+
+/*
+ Implement the MaplyLocationTrackerDelegate protocol to receive location services callbacks.
+*/
+@protocol MaplyLocationTrackerDelegate
+
+// This is to handle problems / failures further up the line.
+- (void) locationManager:(CLLocationManager * __nonnull)manager didFailWithError:(NSError * __nonnull)error;
+
+- (void) locationManager:(CLLocationManager * __nonnull)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status;
+
+@optional
+
+- (void) updateLocation:(CLLocation * __nonnull)location;
+
+@end
+
+/*
+ Implement the MaplyLocationSimulatorDelegate protocol to provide simulated locations
+*/
+@protocol MaplyLocationSimulatorDelegate
+
+- (MaplyLocationTrackerSimulationPoint)getSimulationPoint;
+
+@optional
+
+- (bool)hasValidLocation;
+
+@end
+
+/*
+ The MaplyLocationTracker class provides support for showing current position and heading on the map or globe.
+
+ Be sure to set NSLocationWhenInUseUsageDescription in your app's Info.plist before using.
+ */
+@interface MaplyLocationTracker : NSObject <CLLocationManagerDelegate>
+
+/// Exposes MaplyLocationTracker's location manager for use elsewhere
+@property (nonatomic, readonly, nullable) CLLocationManager *locationManager;
+
+/**
+ MaplyLocationTracker constructor
+
+ @param viewC The globe or map view controller
+
+ @param useHeading Use location services heading information (requires physical magnetometer)
+
+ @param useCourse Use location services course information as fallback if heading unavailable
+ */
+- (nonnull instancetype)initWithViewC:(MaplyBaseViewController *__nullable)viewC
+ useHeading:(bool)useHeading
+ useCourse:(bool)useCourse;
+
+/**
+ MaplyLocationTracker constructor
+
+ @param viewC The globe or map view controller
+
+ @param delegate The MaplyLocationTrackerDelegate for receiving location event callbacks
+
+ @param useHeading Use location services heading information (requires physical magnetometer)
+
+ @param useCourse Use location services course information as fallback if heading unavailable
+ */
+- (nonnull instancetype)initWithViewC:(MaplyBaseViewController *__nullable)viewC
+ delegate:(NSObject<MaplyLocationTrackerDelegate> *__nullable)delegate
+ useHeading:(bool)useHeading
+ useCourse:(bool)useCourse;
+
+/**
+ MaplyLocationTracker constructor
+
+ @param viewC The globe or map view controller
+
+ @param delegate The MaplyLocationTrackerDelegate for receiving location event callbacks
+
+ @param simulator The MaplyLocationSimulatorDelegate for generating simulated locations
+
+ @param useHeading Use location services heading information (requires physical magnetometer)
+
+ @param useCourse Use location services course information as fallback if heading unavailable
+ */
+- (nonnull instancetype)initWithViewC:(MaplyBaseViewController *__nullable)viewC
+ delegate:(NSObject<MaplyLocationTrackerDelegate> *__nullable)delegate
+ simulator:(NSObject<MaplyLocationSimulatorDelegate> *__nullable)simulator
+ simInterval:(NSTimeInterval)simInterval
+ useHeading:(bool)useHeading
+ useCourse:(bool)useCourse;
+
+/**
+ Min/max visibility for the marker assigned to follow location.
+ */
+@property (nonatomic,assign) float markerMinVis,markerMaxVis;
+
+/**
+ Draw priority for the marker assigned to follow location.
+ */
+@property (nonatomic,assign) int markerDrawPriority;
+
+/**
+ Change lock type
+
+ @param lockType The MaplyLocationLockType value for lock behavior
+
+ @param forwardTrackOffset The vertical offset if using MaplyLocationLockHeadingUpOffset (positive values are below the view center)
+ */
+- (void) changeLockType:(MaplyLocationLockType)lockType forwardTrackOffset:(int)forwardTrackOffset;
+
+/**
+ Stop the MaplyLocationTracker behavior and shut it down.
+ */
+- (void) teardown;
+
+/**
+ Get the current device location
+
+ @return The coordinate if valid, else kMaplyNullCoordinate
+ */
+- (MaplyCoordinate)getLocation;
+
+/**
+ Set the current simulated location.
+ */
+- (void) setLocation:(MaplyLocationTrackerSimulationPoint)point
+ altitude:(double)altitude;
+
+/**
+ Set the current simulated location.
+ */
+- (void) setLocation:(MaplyLocationTrackerSimulationPoint)point
+ altitude:(double)altitude
+ horizontalAccuracy:(double)horizontalAccuracy
+ verticalAccuracy:(double)verticalAccuracy
+ speed:(double)speed;
+;
+
+@end
+
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyMBTileFetcher.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyMBTileFetcher.h
new file mode 100644
index 0000000..278e5dc
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyMBTileFetcher.h
@@ -0,0 +1,46 @@
+/* MaplyMBTileFetcher.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 9/13/18.
+ * Copyright 2011-2022 mousebird consulting inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplySimpleTileFetcher.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+
+/**
+ MBTiles tile fetcher.
+
+ This tile fetcher focuses on a single MBTiles file. You mate this
+ with a QuadImageLoader to do the actual work.
+
+ Will work for image or vector MBTiles files.
+ */
+@interface MaplyMBTileFetcher : MaplySimpleTileFetcher
+
+/// Initialize with the name of the local MBTiles file
+- (nullable instancetype)initWithMBTiles:(NSString *__nonnull)fileName;
+
+/// Initialize with the name of the local MBTiles file and cache size in bytes (rounded up to whole pages)
+- (nullable instancetype)initWithMBTiles:(NSString *__nonnull)fileName
+ cacheSize:(int)cacheSize;
+
+// Coordinate system (probably Spherical Mercator)
+- (MaplyCoordinateSystem * __nonnull)coordSys;
+
+/// Format directly from the metadata
+@property (nonatomic,nullable) NSString *format;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyMarker.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyMarker.h
new file mode 100644
index 0000000..ea31c2d
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyMarker.h
@@ -0,0 +1,85 @@
+/*
+ * WGMarker.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 7/24/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+/**
+ The Marker places a UIImage on the globe or map at a given location.
+
+ The Maply Marker takes a location and image, using those to display a textured rectangle on the globe (or map). Since it's a real 3D object it will get larger and smaller as the user moves around.
+
+ If you want a screen based object that stays the same size and is displayed on top of everything else, look to the MaplyScreenMarker.
+ */
+@interface MaplyMarker : NSObject
+
+/**
+ Center of the marker in geographic coordinates (lon/lat in radians).
+
+ The Maply Marker is a 3D object so this is the center of the marker on the globe or map.
+ */
+@property (nonatomic,assign) MaplyCoordinate loc;
+
+
+/**
+ Size of the marker in display coordinates.
+
+ This is the size of the marker in display coordinates. For the globe display coordinates are based on a radius of 1.0.
+ */
+@property (nonatomic,assign) CGSize size;
+
+/**
+ Image or MaplyTexture to use for the marker.
+
+ If set, we'll display a UIImage at the given location of the given size. If not set, it's just a color rectangle which is not very exciting. The view controller tracks the UIImage and will reuse it as necessary and release it when finished.
+ */
+@property (nonatomic,strong) id __nullable image;
+
+/**
+ Images or MaplyTextures to use for the marker.
+
+ If set we'll animate these images one after the other over the duration.
+ */
+@property (nonatomic,strong) NSArray * __nullable images;
+
+/**
+ The time we'll take to cycle through all the images for the marker.
+
+ If images are passed in, this is the time it will take to cycle through them all. By default this is 5s.
+ */
+@property (nonatomic) double period;
+
+/**
+ Marker selectability. On by default
+
+ If set, this marker can be selected by the user. If not set, this marker will never appear in selection results.
+ */
+@property (nonatomic,assign) bool selectable;
+
+/**
+ User data object for selection
+
+ When the user selects a feature and the developer gets it in their delegate, this is an object they can use to figure out what the label means to them.
+ */
+@property (nonatomic,strong) id __nullable userObject;
+
+@end
+
+typedef MaplyMarker WGMarker;
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyMatrix.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyMatrix.h
new file mode 100644
index 0000000..646a29b
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyMatrix.h
@@ -0,0 +1,65 @@
+/*
+ * MaplyMatrix.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 10/16/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+/**
+ Represents a matrix for position manipulation.
+
+ Encapsulates a 4x4 matrix used for object placement and other things. This is more a wrapper than a full service object.
+ */
+@interface MaplyMatrix : NSObject
+
+/**
+ Construct with yaw, pitch, and roll parameters.
+
+ Construct the matrix with the standard yaw, pitch, and roll used by aircraft.
+ */
+- (nonnull instancetype)initWithYaw:(double)yaw pitch:(double)pitch roll:(double)roll;
+
+/**
+ Construct with a consistent scale in each dimension.
+
+ Construct with the same scale in x,y, and z.
+ */
+- (nonnull instancetype)initWithScale:(double)scale;
+
+/**
+ Construct with a translation.
+
+ Construct with a translation in 3D.
+ */
+- (nonnull instancetype)initWithTranslateX:(double)x y:(double)y z:(double)z;
+
+/**
+ Construct a rotation around the given axis.
+
+ Build a matrix that rotates the given amount (in radians) around the given axis.
+ */
+- (nonnull instancetype)initWithAngle:(double)ang axisX:(double)x axisY:(double)y axisZ:(double)z;
+
+/**
+ Multiply the given matrix with this one and return a new one.
+
+ Multiply the given matrix like so: ret = this * other. Return the new one.
+ */
+- (nonnull instancetype)multiplyWith:(MaplyMatrix * __nonnull)other;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyMoon.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyMoon.h
new file mode 100644
index 0000000..ee967b8
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyMoon.h
@@ -0,0 +1,50 @@
+/* MaplyMoon.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 7/2/15.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyComponentObject.h>
+#import <WhirlyGlobe/WhirlyGlobeViewController.h>
+#import <WhirlyGlobe/MaplyLight.h>
+
+/**
+ Utility for calculating moon position.
+
+ This is a utility class that figures out where the moon is at a given data and provides the position.
+ */
+@interface MaplyMoon : NSObject
+
+/**
+ Initialize with a date.
+
+ Initialize with the given date. The moon position will correspond to that. Must be after 2000.
+ */
+- (nonnull instancetype)initWithDate:(NSDate *__nonnull)date;
+
+/// Location on the globe where the moon would land if it fell straight down. Ouch.
+- (MaplyCoordinate)asCoordinate;
+
+/// Return the location above the globe in lon/lat/distance. Yay geocentric!
+- (MaplyCoordinate3d)asPosition;
+
+/// Illuminated fraction of the moon
+@property (readonly) double illuminatedFraction;
+
+/// Phase of the moon.
+@property (readonly) double phase;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyPanDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyPanDelegate.h
new file mode 100644
index 0000000..bf3dc43
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyPanDelegate.h
@@ -0,0 +1,32 @@
+/* MaplyPanDelegate.h
+ * WhirlyGlobeLib
+ *
+ * Created by Steve Gifford on 1/10/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+
+// Custom pan gesture recognizer that plays well with scroll views.
+@interface MinDelay2DPanGestureRecognizer : UIPanGestureRecognizer
+
+- (void)forceEnd;
+
+@end
+
+@interface MaplyPanDelegate : NSObject <UIGestureRecognizerDelegate>
+
+@property (nonatomic,weak) UIGestureRecognizer *gestureRecognizer;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyParticleSystem.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyParticleSystem.h
new file mode 100644
index 0000000..b5f603c
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyParticleSystem.h
@@ -0,0 +1,215 @@
+/*
+ * MaplyParticleSystem.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 4/26/15.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyShader.h>
+#import <WhirlyGlobe/MaplyRenderTarget.h>
+
+typedef NS_ENUM(NSInteger, MaplyParticleSystemType) {
+ MaplyParticleSystemTypePoint,
+ MaplyParticleSystemTypeRectangle,
+};
+
+/**
+ A particle system is used to spawn large numbers of small moving objects.
+
+ The particle system defines what the objects are and how they're controlled. Actual data is handled through the MaplyParticleBatch.
+
+ You set up a particle system and then add MaplyParticleBatches via a view controller.
+ */
+@interface MaplyParticleSystem : NSObject
+
+/**
+ Name of the particle system.
+
+ The particle system name is used for performance debugging.
+ */
+@property (nonatomic,strong) NSString * __nullable name;
+
+/**
+ The type of the particle system.
+
+ At present particle systems are just point geometry.
+ */
+@property (nonatomic,assign) MaplyParticleSystemType type;
+
+/**
+ Position shader for two stage particles.
+
+ If there is a position shader then it is run first and particle data is then
+ shared between this shader and the regular shader.
+ */
+@property (nonatomic,strong) MaplyShader * __nullable positionShader;
+
+/**
+ Shader to use for rendering particles.
+
+ This can either be a single stage shader or it can be part of a two stage shader with
+ the positionShader.
+ */
+@property (nonatomic,strong) MaplyShader * __nullable renderShader;
+
+/**
+ Individual particle lifetime.
+
+ The created particles will last only a certain amount of time.
+ */
+@property (nonatomic,assign) NSTimeInterval lifetime;
+
+/**
+ The base that particle time is measured from.
+
+ Individual particles will measure their own lifetime against this base value.
+ */
+@property (nonatomic,assign) NSTimeInterval baseTime;
+
+/**
+ Total number of particles to be represented at once.
+
+ This is the most particles we'll have on the screen at any time. Space will be allocated for them, so don't overdo it.
+ */
+@property (nonatomic,assign) int totalParticles;
+
+/**
+ Batch size for MaplyParticleBatch.
+
+ Particles need to be created in large batches for efficiency. This is the size of individual batches.
+
+ Only for OpenGL ES. Metal does particles as one big batch.
+ */
+@property (nonatomic,assign) int batchSize;
+
+/**
+ Metal only.
+ Size of a single to be passed in to the calculation and rendering shaders.
+ */
+@property (nonatomic,assign) int vertexSize;
+
+/**
+ Turn on/off the continuous rendering for particles.
+
+ Normally particle systems force the renderer to draw every frame. That's how the particles move. You can turn that behavior off by setting this to false.
+ */
+@property (nonatomic,assign) bool continuousUpdate;
+
+/**
+ Initialize a particle system with a name.
+
+ The particle system needs the name for performance and debugging. The rest of the values can left to their defaults.
+ */
+- (nonnull instancetype)initWithName:(NSString *__nonnull)name viewC:(NSObject <MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+/**
+ Add an attribute we'll be expecting in each batch.
+
+ Adds an attribute name and type which will be present in each batch.
+
+ OpenGL ES Only. Metal handles things as blocks of memory.
+ */
+- (void)addAttribute:(NSString *__nonnull)attrName type:(MaplyShaderAttrType)type;
+
+/**
+ For two stage shaders, these are the varying outputs from one shader to the next.
+
+ Two stage shaders run a position shader and then a regular render shader
+ from the position output. Add any varying values you want to share per
+ vertex from the former to the latter.
+
+ OpenGL ES Only. Metal does this more simply.
+ */
+- (void)addVarying:(NSString *__nonnull)varyAttrName inputName:(NSString *__nonnull)inputName type:(MaplyShaderAttrType)type;
+
+/**
+ For Metal, we just pass in input and output arrays (at least two) along with the number of entries
+ in those arrays. The shaders do the rest of the work in Metal.
+ */
+- (void)addCalculationNum:(int)numEntries data:(NSMutableArray<NSData *> * __nonnull)dataEntries;
+
+/**
+ Add a texture to the particle system.
+
+ All the textures will be handed over to the shader.
+ */
+- (void)addTexture:(id __nonnull)image;
+
+/**
+ Draw these particles to the given render target.
+
+ Rather than being drawn to the screen, these particles will be drawn to the offscreen render target.
+ */
+- (void)setRenderTarget:(MaplyRenderTarget * __nonnull)renderTarget;
+
+@end
+
+
+/**
+ A particle batch adds a set number of particles to the system.
+
+ The particle batch holds the number of particles defined in the MaplyParticleSystem batchSize property. Each attribute array is added individually via an NSData object. All attributes must be present or the batch is invalid and won't be passed through the system.
+ */
+@interface MaplyParticleBatch : NSObject
+
+/**
+ The particle system this batch belongs to.
+ */
+@property (nonatomic,weak) MaplyParticleSystem * __nullable partSys;
+
+/**
+ The current time.
+
+ This will be set by default. However, you can control what the time basis for a particle batch is.
+ */
+@property (nonatomic,assign) NSTimeInterval time;
+
+/**
+ Initialize with the particle system.
+
+ The batch is initialized with its particle system. You must then call addAttribute:values: repeatedly with attribute arrays.
+ */
+- (nonnull instancetype)initWithParticleSystem:(MaplyParticleSystem *__nonnull)partSys;
+
+/**
+ OpenGL ES only.
+
+ Add an attribute array of the given name.
+
+ Each attribute in the MaplyParticleSystem must be filled in here. The name must correspond and the length of the data must match.
+
+ @return Returns true if the attribute array was valid, false otherwise.
+ */
+- (bool) addAttribute:(NSString *__nonnull)attrName values:(NSData *__nonnull)data;
+
+/**
+ Metal only.
+
+ We add the batch as a single blob of data. Format is up to you and your shader.
+
+ */
+- (void) addData:(NSData * __nonnull)data;
+
+/**
+ Tests if the batch is valid.
+
+ This checks if all the attribute arrays are present and valid.
+ */
+- (bool) isValid;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyPinchDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyPinchDelegate.h
new file mode 100644
index 0000000..06c35b2
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyPinchDelegate.h
@@ -0,0 +1,23 @@
+/* MaplyPinchDelegate.h
+ * WhirlyGlobeLib
+ *
+ * Created by Steve Gifford on 1/10/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyZoomGestureDelegate.h>
+
+@interface MaplyPinchDelegate : MaplyZoomGestureDelegate
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyPoints.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyPoints.h
new file mode 100644
index 0000000..2b2e6fd
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyPoints.h
@@ -0,0 +1,84 @@
+/*
+ * MaplyPoints.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 10/21/15
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+#import <WhirlyGlobe/MaplyMatrix.h>
+
+/**
+ The Maply Points object is used to add a large number of static points to the scene.
+
+ Rather than add a single 3D point we assume you want to add a lot of them all at once. This object lets you do that and lets you assign the various data values to input attributes in your custom shader.
+
+ All the cool kids have custom shaders.
+ */
+@interface MaplyPoints : NSObject
+
+/// Initialie with a hint as to the number of points you'll be adding (not required).
+- (__nonnull id)initWithNumPoints:(int)numPoints;
+
+/// Transform to apply to the point locations. A center is good.
+@property (nonatomic,strong) MaplyMatrix * __nullable transform;
+
+/// Add a geocoordinate in lon/lat and Z (meters).
+- (void)addGeoCoordLon:(float)x lat:(float)y z:(float)z;
+
+/// Directly add a coordinate in display space. Remember the globe is a sphere with radius = 1.0.
+- (void)addDispCoordX:(float)x y:(float)y z:(float)z;
+
+/// Add a display space coordinate, but use doubles for precision.
+- (void)addDispCoordDoubleX:(double)x y:(double)y z:(double)z;
+
+/// Add a color, which will be converted to 8 bits before going to the shader.
+- (void)addColorR:(float)r g:(float)g b:(float)b a:(float)a;
+
+/**
+ Add a new attribute array of the given type.
+
+ If you have a custom shader, this is a convenient way to pass a large array of attributes to it. Just specify the name (attribute name in the shader) and the type and then add the appropriate values. The data will be handed down to the shader at render time.
+
+ @param attrName The name of the attribute as used by the shader.
+
+ @param type The data type of the attribute.
+
+ @return An index (or -1 if invalid) for the attribute. Use this in the addAttribute calls.
+ */
+- (int)addAttributeType:(NSString *__nonnull)attrName type:(MaplyShaderAttrType)type;
+
+/// Add an integer attribute.
+- (void)addAttribute:(int)whichAttr iVal:(int)val;
+
+/// Add a float attribute.
+- (void)addAttribute:(int)whichAttr fVal:(float)val;
+
+/// Add a two component float attribute.
+- (void)addAttribute:(int)whichAttr fValX:(float)valX fValY:(float)valY;
+
+/// Add a three component float attribute.
+- (void)addAttribute:(int)whichAttr fValX:(float)fValX fValY:(float)valY fValZ:(float)valZ;
+
+/// Add a three component float attribute, but we'll store it at doubles until it gets to the shader.
+- (void)addAttribute:(int)whichAttr valX:(double)valX valY:(double)valY valZ:(double)valZ;
+
+/// Add a four commponent float attribute.
+- (void)addAttribute:(int)whichAttr fValX:(float)valX fValY:(float)valY fValZ:(float)valZ fValW:(float)valW;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyQuadImageFrameLoader.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyQuadImageFrameLoader.h
new file mode 100644
index 0000000..b4fea4c
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyQuadImageFrameLoader.h
@@ -0,0 +1,191 @@
+/*
+ * MaplyQuadImageFrameLoader.h
+ *
+ * Created by Steve Gifford on 9/13/18.
+ * Copyright 2012-2022 mousebird consulting inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyQuadImageLoader.h>
+#import <WhirlyGlobe/MaplyActiveObject.h>
+
+@class MaplyQuadImageFrameLoader;
+
+/**
+ Quad Image FrameAnimation runs through the frames in a Quad Image Frame loader over time.
+
+ Set this up with a MaplyQuadImageFrameLoader and it'll run through the available frames from start to finish.
+ At the end it will snap back to the beginning.
+ */
+@interface MaplyQuadImageFrameAnimator : MaplyActiveObject
+
+/// Initialize with the image frame loader and view controller
+- (nonnull instancetype)initWithFrameLoader:(MaplyQuadImageFrameLoader * __nonnull)loader viewC:(MaplyBaseViewController * __nonnull)viewC;
+
+/// How long to animate from start to finish.
+@property (nonatomic,assign) NSTimeInterval period;
+
+/// How long to pause at the end of the sequence before starting back
+@property (nonatomic,assign) NSTimeInterval pauseLength;
+
+/// Remove the animator and stop animating
+- (void)shutdown;
+
+@end
+
+/**
+ The Maply Quad Image Frame Loader can generation per-frame stats. These are them.
+ */
+@interface MaplyQuadImageFrameStats : NSObject
+
+/// Number of tiles this frame is in (loading and loaded)
+@property (nonatomic) int totalTiles;
+
+/// Number of tiles this frame has yet to load
+@property (nonatomic) int tilesToLoad;
+
+@end
+
+/**
+ Stats generated by the Maply Quad Image Frame Loader.
+ */
+@interface MaplyQuadImageFrameLoaderStats : NSObject
+
+/// Total number of tiles managed by the loader
+@property (nonatomic) int numTiles;
+
+/// Per frame stats for current loading state
+@property (nonatomic,nonnull) NSArray<MaplyQuadImageFrameStats *> *frames;
+
+@end
+
+/// How we load frames in the QuadImageFrameLoader
+/// Broad means we load 0 first and the on down
+/// Narrow means we load the frames around the current display first
+typedef NS_ENUM(NSInteger, MaplyLoadFrameMode) {
+ MaplyLoadFrameBroad,
+ MaplyLoadFrameNarrow,
+};
+
+/**
+ The Maply Quad Image Frame Loader is for paging individual frames of image pyramids.
+
+ This works much like the Quad Image Loader, but handles more than one frame. You can animate
+ between the frames with the QuadImageFrameAnimator
+ */
+@interface MaplyQuadImageFrameLoader : MaplyQuadImageLoaderBase
+
+/**
+ Initialize with multiple tile sources (one per frame).
+
+ @param params The sampling parameters describing how to break down the data for projection onto a globe or map.
+ @param tileInfos A list of tile info objects to fetch for each frame.
+ @param viewC the View controller (or renderer) to add objects to.
+ */
+- (nullable instancetype)initWithParams:(MaplySamplingParams *__nonnull)params tileInfos:(NSArray<NSObject<MaplyTileInfoNew> *> *__nonnull)tileInfos viewC:(MaplyBaseViewController * __nonnull)viewC;
+
+/// How frames are loaded (top down vs broad)
+@property (nonatomic,assign) MaplyLoadFrameMode loadFrameMode;
+
+/**
+ Add another rendering focus to the frame loader.
+
+ Normally you'd have one point of focus for a frame loader resulting in one image
+ to be displayed. But if you're using render targets, you may want to have two
+ and combine them in some way yourself. Or more. No idea why you'd do that.
+
+ If you're going to do this, call addFocus right after you create the FrameLoader.
+ */
+- (void)addFocus;
+
+/**
+ Return the number of focii. Normally it's 1.
+
+ See addFocus for what these are. You probably don't need to be using them.
+ */
+- (int)getNumFocus;
+
+/**
+ Set the interpolated location within the array of frames.
+
+ Each set of frames can be accessed from [0.0,numFrames]. Images will be interpolated between
+ those values and may be snapped if data has not yet loaded.
+
+ This value is used once per frame, so feel free to call this as much as you'd like.
+ */
+- (void)setCurrentImage:(double)where;
+
+/**
+ Set the currentImage for the given focus. See addFocus for what those are.
+ */
+- (void)setFocus:(int)focusID currentImage:(double)where;
+
+/**
+ Return the interpolated location within the array of frames.
+ */
+- (double)getCurrentImage;
+
+/**
+ Return the interpolated location within the array of frames for a given focus. See addFocus for what that means.
+ */
+- (double)getCurrentImageForFocus:(int)focusID;
+
+/**
+ Set whether we require the top tiles to be loaded before a frame can be displayed.
+
+ Normally the system wants all the top level tiles to be loaded (just one at level 0)
+ to be in memory before it will display a frame at all. You can turn this off.
+ */
+- (void)setRequireTopTiles:(bool)newVal;
+
+/** Number of tile sources passed in as individual frames.
+ */
+- (int)getNumFrames;
+
+/**
+ An optional render target for this loader.
+
+ The loader can draw to a render target rather than to the screen.
+ You use this in a multi-pass rendering setup.
+
+ This version takes a specific focus. See addFocus for what that means.
+ */
+- (void)setFocus:(int)focusID renderTarget:(MaplyRenderTarget *__nonnull)renderTarget;
+
+/**
+ Shader to use for rendering the image frames for a particular focus.
+
+ Consult addFocus for what this means.
+ */
+- (void)setFocus:(int)focusID shader:(MaplyShader * __nullable)shader;
+
+/**
+ Get the frame stats for what's loaded and what's not.
+ */
+- (MaplyQuadImageFrameLoaderStats * __nonnull)getFrameStats;
+
+/**
+ Change the tile sources and reload all the data.
+ <br>
+ You can change the tile source data is being loaded from. This will
+ force a reload and everything visual should change as the data comes in.
+ */
+- (void)changeTileInfos:(NSArray<MaplyTileInfoNew> * __nullable)tileInfo;
+
+/** Turn off the image loader and shut things down.
+ This unregisters us with the sampling layer and shuts down the various objects we created.
+ */
+- (void)shutdown;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyQuadImageLoader.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyQuadImageLoader.h
new file mode 100644
index 0000000..d5b346d
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyQuadImageLoader.h
@@ -0,0 +1,229 @@
+/*
+ * MaplyQuadImageLoader.h
+ *
+ * Created by Steve Gifford on 4/10/18.
+ * Copyright 2012-2022 Saildrone Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyControllerLayer.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+#import <WhirlyGlobe/MaplyQuadSampler.h>
+#import <WhirlyGlobe/MaplyRemoteTileFetcher.h>
+#import <WhirlyGlobe/MaplyQuadLoader.h>
+
+/**
+ This version of the loader return is used by the MaplyImageLoaderInterpreter.
+
+ When image tiles load, the interpeter fills in these contents, which can
+ include any sort of ComponentObject and, of course, images.
+ */
+@interface MaplyImageLoaderReturn : MaplyLoaderReturn
+
+/// Initialize with the loader this will be attached to
+- (id __nonnull)initWithLoader:(MaplyQuadLoaderBase * __nonnull)loader;
+
+/// Add an image to this loaded return.
+/// You can add multiple, but the interpreter should be expecting that
+- (void)addImageTile:(MaplyImageTile * __nonnull)image;
+
+/// Add a UIImage to the loader return
+/// This just adds a MaplyImageTile wrapper around the UIImage.
+- (void)addImage:(UIImage * __nonnull)image;
+
+/// Return an array of Images
+- (NSArray<MaplyImageTile *> * __nonnull)getImages;
+
+/// Clear out any images. Presumably to replace them.
+- (void)clearImages;
+
+/// If any component objects are associated with the tile, these are them.
+/// They need to start disabled. The system will enable and delete them when it is time.
+- (void)addCompObjs:(NSArray<MaplyComponentObject *> * __nonnull)compObjs;
+
+/// Return the component objects added for this loader return
+- (NSArray<MaplyComponentObject *> *__nonnull)getCompObjs;
+
+/// Clear out any component objects, presumably to replace them
+- (void)clearCompObjs;
+
+/// These component objects are assumed to be overlaid and so only one
+/// set will be displayed at a time.
+- (void)addOvlCompObjs:(NSArray<MaplyComponentObject *> * __nonnull)compObjs;
+
+/// Return the overlay component objects added for this loader return
+- (NSArray<MaplyComponentObject *> *__nonnull)getOvlCompObjs;
+
+/// Clear out any component objects, presumably to replace them
+- (void)clearOvlCompObjs;
+
+@end
+
+/**
+ Image loader intrepreter turns NSData objects into MaplyImageTiles.
+
+ This is the default interpreter used by the MaplyQuadImageLoader.
+ */
+@interface MaplyImageLoaderInterpreter : NSObject<MaplyLoaderInterpreter>
+@end
+
+/**
+ This loader interpreter sticks a designator in the middle of tiles
+ and a line around the edge. Nice for debugging.
+ */
+@interface MaplyOvlDebugImageLoaderInterpreter : MaplyImageLoaderInterpreter
+
+// Intialize with the loader we're using. Need this for extents of tiles
+- (instancetype __nonnull)initWithViewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+@end
+
+/**
+ This loader interpreter makes up an image for the given frame/tile
+ and returns that. It doesn't use any returned data.
+ */
+@interface MaplyDebugImageLoaderInterpreter : MaplyImageLoaderInterpreter
+
+- (instancetype __nonnull)initWithViewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+@end
+
+/**
+ This loader interpreter treats input image data objects as PNGs containing raw data.
+ The difference is we'll use a direct PNG reader to tease it out, rather than UIImage.
+ */
+@interface MaplyRawPNGImageLoaderInterpreter : MaplyImageLoaderInterpreter
+
+/// In some cases we just want to pick values out of the input
+- (void)addMappingFrom:(int)inVal to:(int)outVal;
+
+@end
+
+/// Name of the shared MaplyRemoteTileFetcher
+extern NSString * _Nonnull const MaplyQuadImageLoaderFetcherName;
+
+/**
+ Base object for Maply Quad Image loader.
+
+ Look to the subclasses for actual functionality. This holds methods they share.
+ */
+@interface MaplyQuadImageLoaderBase : MaplyQuadLoaderBase
+
+/** Set the base priority values for produced tiles.
+
+ The system will use a range of values to deal with overlaps.
+ This is the base value.
+ */
+@property (nonatomic) int baseDrawPriority;
+
+// Offset between levels for a calculated draw priority
+@property (nonatomic) int drawPriorityPerLevel;
+
+// Base color for geometry produced
+@property (nonatomic,retain,nonnull) UIColor *color;
+
+// Write to the z buffer when rendering. On by default
+@property (nonatomic,assign) bool zBufferWrite;
+
+// Read from the z buffer when rendering. Off by default
+@property (nonatomic,assign) bool zBufferRead;
+
+// Turn display of loader on or off. Will still load, though.
+@property bool enable;
+
+/**
+ Shader to use for rendering the image frames.
+
+ If not set we'll pick the default visual shader.
+ */
+- (void)setShader:(MaplyShader * __nullable)shader;
+
+/**
+ An optional render target for this loader.
+
+ The loader can draw to a render target rather than to the screen.
+ You use this in a multi-pass rendering setup.
+ */
+- (void)setRenderTarget:(MaplyRenderTarget *__nonnull)renderTarget;
+
+/**
+ In special cases we may have tiles that already have borders baked in. In that case, call this
+ method to set both the total textures size and the number of border pixels around the outside.
+
+ By default this functionality is off.
+ */
+- (void)setTextureSize:(int)texSize borderSize:(int)borderSize;
+
+/**
+ Set the image format for internal imagery storage.
+
+ OpenGL ES offers us several image formats that are more efficient than 32 bit RGBA, but they're not always appropriate. This property lets you choose one of them. The 16 or 8 bit ones can save a huge amount of space and will work well for some imagery, most maps, and a lot of weather overlays.
+
+ Be sure to set this at layer creation, it won't do anything later on.
+
+ | Image Format | Description |
+ |:-------------|:------------|
+ | MaplyImageIntRGBA | 32 bit RGBA with 8 bits per channel. The default. |
+ | MaplyImageUShort565 | 16 bits with 5/6/5 for RGB and none for A. |
+ | MaplyImageUShort4444 | 16 bits with 4 bits for each channel. |
+ | MaplyImageUShort5551 | 16 bits with 5/5/5 bits for RGB and 1 bit for A. |
+ | MaplyImageUByteRed | 8 bits, where we choose the R and ignore the rest. |
+ | MaplyImageUByteGreen | 8 bits, where we choose the G and ignore the rest. |
+ | MaplyImageUByteBlue | 8 bits, where we choose the B and ignore the rest. |
+ | MaplyImageUByteAlpha | 8 bits, where we choose the A and ignore the rest. |
+ | MaplyImageUByteRGB | 8 bits, where we average RGB for the value. |
+ | MaplyImage4Layer8Bit | 32 bits, four channels of 8 bits each. Just like MaplyImageIntRGBA, but a warning not to do anything too clever in sampling. |
+ */
+@property (nonatomic) MaplyQuadImageFormat imageFormat;
+
+@end
+
+/**
+ The Maply Quad Image Loader is for paging image pyramids local or remote.
+
+ This layer pages image pyramids. They can be local or remote, in any coordinate system Maply supports and you provide a MaplyTileInfoNew conformant object to do the actual image tile fetching.
+
+ You probably don't have to implement your own tile source. Go look at the MaplyRemoteTileFetcher and MaplyMBTileFetcher objects. Those will do remote and local fetching.
+ */
+@interface MaplyQuadImageLoader : MaplyQuadImageLoaderBase
+
+/**
+ Initialize with a single tile info object and the sampling parameters.
+
+ @param params The sampling parameters describing how to break down the data for projection onto a globe or map.
+ @param tileInfo A single tile info object describing where the data is and how to get it.
+ @param viewC the View controller (or renderer) to add objects to.
+ */
+- (nullable instancetype)initWithParams:(MaplySamplingParams *__nonnull)params tileInfo:(NSObject<MaplyTileInfoNew> *__nullable)tileInfo viewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+/**
+ Initialize with multiple tile sources and sampling parameters.
+
+ @param params The sampling parameters describing how to break down the data for projection onto a globe or map.
+ @param tileInfos A list of tile info objects to fetch for each tile. If one fails, the tile fails to load.
+ @param viewC the View controller (or renderer) to add objects to.
+ */
+- (nullable instancetype)initWithParams:(MaplySamplingParams *__nonnull)params tileInfos:(NSArray<NSObject<MaplyTileInfoNew> *> *__nonnull)tileInfos viewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+/**
+ Change the tile source and reload all the data.
+ <br>
+ You can change the tile source data is being loaded from. This will
+ force a reload and everything visual should change as the data comes in.
+ */
+- (void)changeTileInfo:(NSObject<MaplyTileInfoNew> *__nonnull)tileInfo;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyQuadLoader.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyQuadLoader.h
new file mode 100644
index 0000000..65ad61f
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyQuadLoader.h
@@ -0,0 +1,236 @@
+/*
+ * MaplyQuadLoader.h
+ *
+ * Created by Steve Gifford on 2/12/19.
+ * Copyright 2012-2022 Saildrone Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+#import <WhirlyGlobe/MaplyControllerLayer.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+#import <WhirlyGlobe/MaplyQuadSampler.h>
+#import <WhirlyGlobe/MaplyRemoteTileFetcher.h>
+
+@class MaplyQuadLoaderBase;
+
+/**
+ Passed in to and returned by the Loader Interpreter.
+
+ We pass this into the interpreter with the unparsed data. It parses it and passes that
+ data back, possibly with an error.
+ */
+@interface MaplyLoaderReturn : NSObject
+
+/// Initialize with the loader this will be attached to
+- (id __nonnull)initWithLoader:(MaplyQuadLoaderBase * __nonnull)loader;
+
+/// Tile this is the data for
+@property (nonatomic) MaplyTileID tileID;
+
+/// If set, the frame. -1 by default
+@property (nonatomic,readonly) int frame;
+
+/// Data returned from a tile request. Unparsed.
+/// You can add multiple of these, but the interpreter should be expecting that
+- (void)addTileData:(id __nonnull) tileData;
+
+/// Return the tile NSData objects as an array
+- (NSArray<id> * __nonnull)getTileData;
+
+/// Return the first data object. You're probably only expecting the one.
+- (id __nullable)getFirstData;
+
+/// Set when the QuadLoader cancels a tile. You can check this in your dataForTile:
+- (bool)isCancelled;
+
+/// If this is set, the tile failed to parse
+/// You can set it and the system will deal with the results
+@property (nonatomic,strong) NSError * __nullable error;
+
+@end
+
+/**
+ Loader Interpreter converts raw data into images and objects.
+
+ Converts data returned from a remote source (or cache) into images and/or
+ MaplyComponentObjects that have already been added to the view (disabled).
+ */
+@protocol MaplyLoaderInterpreter<NSObject>
+
+/** Set when the loader first starts up.
+
+ If you need to tweak loader settings, do it here.
+ */
+- (void)setLoader:(MaplyQuadLoaderBase * __nonnull)loader;
+
+/**
+ Parse the data coming back from a remote request and turn it into something we can use.
+
+ Convert the NSData passed in to image and component objects (e.g. add stuff to the view controller).
+ Everything added should be disabled to start.
+ */
+- (void)dataForTile:(MaplyLoaderReturn * __nonnull)loadReturn loader:(MaplyQuadLoaderBase * __nonnull)loader;
+
+/**
+ Notification that the tile was unloaded by the system. If you're tracking your own resources, you may need this.
+ */
+- (void)tileUnloaded:(MaplyTileID)tileID;
+
+@end
+
+/** Base class for the quad loaders.
+
+ The image, frame, and data paging loaders all share much of the same functionality.
+ */
+@interface MaplyQuadLoaderBase : NSObject
+
+/**
+ Control how tiles are indexed, either from the lower left or the upper left.
+
+ If set, we'll use the OSM approach (also Google Maps) to y indexing. That's that default and it's normally what you're run into.
+
+ Strictly speaking, TMS addressing (the standard) is flipped the other way. So if your tile source looks odd, try setting this to false.
+
+ Default value is true.
+ */
+@property (nonatomic) bool flipY;
+
+/// Set for a lot of debugging output
+@property (nonatomic,assign) bool debugMode;
+
+/// View controller this is attached to.
+/// Useful for delegate calls that might not be tracking that.
+@property (nonatomic,readonly,weak,nullable) NSObject<MaplyRenderControllerProtocol> *viewC;
+
+/// If set, we'll call the interpreter on this queue
+@property (nonatomic,nullable,strong) dispatch_queue_t queue;
+
+/// Number of simulataneous tiles we'll parse
+/// This is really just a limit on the number of tiles we'lll parse concurrently to keep memory use under control
+@property (nonatomic) unsigned int numSimultaneousTiles;
+
+// True if the loader is not currently loading anything
+- (bool)isLoading;
+
+/**
+ Calculate the bounding box for a single tile in geographic.
+
+ This is a utility method for calculating the extents of a given tile in geographic (e.g. lon/lat).
+
+ @param tileID The ID for the tile we're interested in.
+
+ @return The lower left and upper right corner of the tile in geographic coordinates. Returns kMaplyNullBoundingBox in case of error
+ */
+- (MaplyBoundingBox)geoBoundsForTile:(MaplyTileID)tileID;
+
+/**
+ Calculate the bounding box for a single tile in geographic using doubles.
+
+ This is a utility method for calculating the extents of a given tile in geographic (e.g. lon/lat).
+
+ @param tileID The ID for the tile we're interested in.
+
+ @return The lower left and upper right corner of the tile in geographic coordinates. Returns kMaplyNullBoundingBoxD in case of error
+ */
+- (MaplyBoundingBoxD)geoBoundsForTileD:(MaplyTileID)tileID;
+
+/**
+ Calculate the bounding box for a single tile in the local coordinate system.
+
+ This utility method calculates the bounding box for a tile in the coordinate system used for the layer.
+
+ @param tileID The ID for the tile we're interested in.
+
+ @return The lower left and upper right corner of the tile in local coordinates.
+ */
+- (MaplyBoundingBox)boundsForTile:(MaplyTileID)tileID;
+
+/**
+ Calculate the bounding box for a single tile in the local coordinate system using doubles.
+
+ This utility method calculates the bounding box for a tile in the coordinate system used for the layer.
+
+ @param tileID The ID for the tile we're interested in.
+
+ @return The lower left and upper right corner of the tile in geographic coordinates.
+ */
+- (MaplyBoundingBoxD)boundsForTileD:(MaplyTileID)tileID;
+
+/**
+ Return the center of the tile in display coordinates.
+
+ @param tileID The ID for the tile we're interested in.
+
+ @return Return the center in display space for the given tile.
+ */
+- (MaplyCoordinate3d)displayCenterForTile:(MaplyTileID)tileID;
+
+/**
+ Each sampling layer allocates a slot to keep track of continuous zoom levels.
+ Those are passed all the way through to the individual shaders.
+ */
+- (int)getZoomSlot;
+
+/// Use a specific tile fetcher rather than the one shared by everyone else
+- (void)setTileFetcher:(NSObject<MaplyTileFetcher> * __nonnull)tileFetcher;
+
+/// Set the interpreter for the data coming back. If you're just getting images, don't set this.
+- (void)setInterpreter:(NSObject<MaplyLoaderInterpreter> * __nonnull)interp;
+
+/// Return the current interpreter
+- (NSObject<MaplyLoaderInterpreter> * __nullable)getInterpreter;
+
+/**
+ Change the interpreter and reload all the data.
+ <br>
+ You can change the tile interpreter being used to build objects and images.
+ This will then force a reload of the tiles (hopefully from cache) and the
+ visuals will change as everything comes in.
+ */
+- (void)changeInterpreter:(NSObject<MaplyLoaderInterpreter> *__nonnull)interp;
+
+/**
+ Force a reload of the data.
+ <br>
+ All the current loads will be cancelled, any in flight will be ignored
+ and the loader will ask for a whole new set of data.
+ */
+- (void)reload;
+
+/**
+ Force a reload of the tiles overlapping a bounding box.
+ <br>
+ All the current loads will be cancelled, any in flight will be ignored
+ and the loader will ask for a whole new set of data.
+ */
+- (void)reloadArea:(MaplyBoundingBox)bounds;
+
+
+/**
+ Force a reload of the tiles overlapping a set of bounding boxes
+ <br>
+ All the current loads will be cancelled, any in flight will be ignored
+ and the loader will ask for a whole new set of data.
+ */
+- (void)reloadAreas:(NSArray<NSValue*>* __nullable)bounds;
+
+/** Turn off the loader and shut things down.
+ This unregisters us with the sampling layer and shuts down the various objects we created.
+ */
+- (void)shutdown;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyQuadPagingLoader.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyQuadPagingLoader.h
new file mode 100644
index 0000000..18d8b18
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyQuadPagingLoader.h
@@ -0,0 +1,82 @@
+/*
+ * MaplyQuadPagingLoader.h
+ *
+ * Created by Steve Gifford on 2/21/91.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyQuadLoader.h>
+
+/**
+ This version of the loader return is used by the MaplyQuadPagingLoader.
+
+ The Object pager is only expecting Component Objects and will manage
+ those as things are loaded in and out.
+ */
+@interface MaplyObjectLoaderReturn : MaplyLoaderReturn
+
+/// Initialize with the loader this will be attached to
+- (id __nonnull)initWithLoader:(MaplyQuadLoaderBase *__nonnull)loader;
+
+/// If any component objects are associated with the tile, these are them.
+/// They need to start disabled. The system will enable and delete them when it is time.
+- (void)addCompObjs:(NSArray<MaplyComponentObject *> * __nonnull)compObjs;
+
+/// Add a component object to the collection if it's non null
+- (void)addCompObj:(MaplyComponentObject * __nullable)compObj;
+
+/// Return an array of component objects that were added to this loader return
+- (NSArray<MaplyComponentObject *> * __nonnull)getCompObjs;
+
+@end
+
+/** General purpose quad paging loader.
+
+ This quadtree based paging loader is for fetching and load general geometry.
+ There are other loaders that handle images and image animations. This one is
+ purely for geometry.
+
+ You need to fill in at least a MaplyLoaderInterpreter, which is probably your own
+ implementation.
+
+ This replaces the QuadPagingLayer from WhirlyGlobe-Maply 2.x.
+ */
+@interface MaplyQuadPagingLoader : MaplyQuadLoaderBase
+
+/**
+ Initialize with a single tile info object, the interpreter and the sampling parameters.
+
+ @param params The sampling parameters describing how to break down the data for projection onto a globe or map.
+ @param tileInfo A optional tile info object describing where the data is and how to get it.
+ @param loadInterp The interpreter makes geometry from the input data. Or just makes it up if there is no input.
+ @param viewC the View controller (or renderer) to add objects to.
+ */
+- (nullable instancetype)initWithParams:(MaplySamplingParams *__nonnull)params
+ tileInfo:(NSObject<MaplyTileInfoNew> *__nullable)tileInfo
+ loadInterp:(NSObject<MaplyLoaderInterpreter> *__nullable)loadInterp
+ viewC:(MaplyBaseViewController * __nonnull)viewC;
+
+/**
+ Force a reload of the data.
+ <br>
+ All the current loads will be cancelled, any in flight will be ignored and the loader will ask for a whole new set of data.
+ */
+- (void)reload;
+
+- (void)reloadArea:(MaplyBoundingBox)bound;
+
+- (void)reloadAreas:(NSArray<NSValue*>* __nullable)bounds;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyQuadSampler.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyQuadSampler.h
new file mode 100644
index 0000000..5381a95
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyQuadSampler.h
@@ -0,0 +1,103 @@
+/*
+ * MaplyQuadSampler.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 3/27/18.
+ * Copyright 2011-2022 Saildrone Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyControllerLayer.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+
+/**
+ Sampling parameters.
+
+ These are used to describe how we want to break down the globe or
+ flat projection onto the globe.
+ */
+@interface MaplySamplingParams : NSObject
+
+/// The coordinate system we'll be sampling from.
+@property (nonatomic,nonnull,strong) MaplyCoordinateSystem *coordSys;
+
+/// Min zoom level for sampling. Don't set this to anything other than 0 or 1
+@property (nonatomic) int minZoom;
+
+/// Max zoom level for sampling
+@property (nonatomic) int maxZoom;
+
+/// We may want to calculate zoom levels beyond what we actually load.
+/// Useful for zoom scaled features and enable/disable based on zoome
+@property (nonatomic) int reportedMaxZoom;
+
+/// Maximum number of tiles to load
+@property (nonatomic) int maxTiles;
+
+/// Cutoff for loading tiles. This is size in screen space (pixels^2)
+@property (nonatomic) double minImportance;
+
+/// Normally we always load the lowest level
+/// If this is set we only load those lowest level tiles that pass this test
+/// Must be greater than zero and not equal to minImportance to take effect.
+@property (nonatomic) double minImportanceTop;
+
+/// Generate geometry to cover the north and south poles
+/// Only works for world-wide projections
+@property (nonatomic) bool coverPoles;
+
+/// If set, generate skirt geometry to hide the edges between levels
+@property (nonatomic) bool edgeMatching;
+
+/// Tesselation values per level for breaking down the coordinate system (e.g. globe)
+@property (nonatomic) int tessX,tessY;
+
+/// If set, we'll scale the bounding boxes of individual tiles by this before evaluating
+@property (nonatomic) float boundScale;
+
+/// If set, we'll always load the lowest level first and then whatever the target level is
+/// Turn this off to get true single level loading
+/// `forceMinLevelHeight` must be greater than zero for this to have any effect.
+@property (nonatomic) bool forceMinLevel;
+
+/// If set, we'll turn on forceMinLevel and only use it when the viewer is above this height
+@property (nonatomic) double forceMinLevelHeight;
+
+/// If set, we'll try to load a single level
+@property (nonatomic) bool singleLevel;
+
+/// If set, the tiles are clipped to this boundary
+@property (nonatomic) MaplyBoundingBoxD clipBounds;
+@property (nonatomic,readonly) bool hasClipBounds;
+
+/**
+ Detail the levels you want loaded in target level mode.
+
+ The layer calculates the optimal target level. The entries in this array are relative to that level or absolute. For example [0,-4,-2] means the layer will always try to load levels 0, targetLevel-4 and targetLevel-2, but only the latter two if they make sense.
+ */
+@property (nonatomic,nullable,strong) NSArray *levelLoads;
+
+/**
+ Set the min importance for just one level.
+
+ This is useful if you want your lower levels loaded more aggressively.
+ */
+- (void)setMinImportance:(double)minImportance forLevel:(int)level;
+
+/// Decide if these sampling params are the same as others
+- (bool)isEqualTo:(MaplySamplingParams *__nonnull)other;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyRemoteTileFetcher.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyRemoteTileFetcher.h
new file mode 100644
index 0000000..cc26370
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyRemoteTileFetcher.h
@@ -0,0 +1,288 @@
+/*
+ * MaplyRemoteTileFetcher.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 6/15/18.
+ * Copyright 2011-2022 Saildrone Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+
+/**
+ Remote Tile Info Object (New)
+
+ Not to be confused with the old one, which works with the older loading subsystem,
+ the new remote tile info object contains min/max zoom, coordinate system and URL
+ information for fetching individual data tiles.
+ */
+@interface MaplyRemoteTileInfoNew : NSObject<MaplyTileInfoNew>
+
+/**
+ Initialize with enough information to fetch remote tiles.
+
+ This version of the init method takes all the explicit
+ information needed to fetch remote tiles. This includes the
+ base URL and min and max zoom levels.
+
+ @param baseURL The base URL for fetching TMS tiles. This is a replacement URL with {x}, {y}, and {z} in the string.
+
+ @param minZoom The minimum zoom level to fetch. This really should be 0.
+
+ @param maxZoom The maximum zoom level to fetch.
+
+ @return The MaplyRemoteTileInfoNew object or nil on failure.
+ */
+- (nonnull instancetype)initWithBaseURL:(NSString *__nonnull)baseURL minZoom:(int)minZoom maxZoom:(int)maxZoom;
+
+/// Base URL
+@property (nonatomic,readonly,retain,nonnull) NSString *baseURL;
+
+/// Min zoom level
+@property (nonatomic,readonly,assign) int minZoom;
+
+/// Max zoom level
+@property (nonatomic,readonly,assign) int maxZoom;
+
+/**
+ The timeout assigned to the NSMutableURLRequest we're using to fetch tiles.
+
+ This is not set by default. If set, we'll use this value as the timeout on the NSMutableURLRequest we use for fetching tiles. This lets you extent it where appropriate or shorten it if you like.
+ */
+@property (nonatomic,assign) float timeOut;
+
+/**
+ The cache directory for data tiles.
+
+ In general, we want to cache. The globe, in particular,
+ is going to fetch the same tiles over and over, quite a lot.
+ The cacheing behavior is a little dumb. It will just write
+ files to the given directory forever. If you're interacting
+ with a giant image pyramid, that could be problematic.
+ */
+@property (nonatomic, retain,nullable) NSString *cacheDir;
+
+/**
+ Optional headers to add to the NSURLRequest.
+
+ These are name/data pairs which will be stuck in the NSURLRequest header.
+ */
+@property (nonatomic, retain) NSDictionary * __nullable headers;
+
+/**
+ Optional coordinate system describing the tile set.
+
+ This coordinate system is required if the tile info will need
+ to evaluate valid tiles as defined by the addValidBounds:coordSystem: call.
+ */
+@property (nonatomic, retain) MaplyCoordinateSystem * __nullable coordSys;
+
+/**
+ Add a bounding box that defines validity for any tile before it's fetched.
+
+ Not all data sources cover all possible tiles. If you know your data source does not,
+ you can specify what area is valid ahead of times. Tiles that do not overlap that area
+ will not be loaded.
+ */
+- (void)addValidBounds:(MaplyBoundingBoxD)bbox coordSystem:(MaplyCoordinateSystem * __nonnull)coordSys;
+
+@end
+
+/**
+ Fetch Info for remote tile fetches.
+
+ The URL (required) and cacheFile (optional) for the given fetch.
+ This is the object the RemoteTileFetcher expects for the fetchInfo member of the TileFetchRequest.
+ */
+@interface MaplyRemoteTileFetchInfo : NSObject
+
+/// URL to fetch from
+@property (nonatomic,nonnull,retain) NSURLRequest *urlReq;
+
+/// File name for cached file (if present). Save it here when fetched if set.
+@property (nonatomic,nullable,retain) NSString *cacheFile;
+
+/// If you're using local storage (separate from the cache) this will be passed on to the MaplyTileLocalStorage manager
+@property (nonatomic,nullable,retain) id localStorageKey;
+
+@end
+
+/**
+ If you provide LocalStore the RemoteTileFetcher will look for data in local storage first,
+ then try the local file cache and lastly go to the network.
+
+ You can provide the local storage by filling out this protocol and passing it to the RemoteTileFetcher.
+
+ Expect to be called on a random thread and block appropriately.
+ */
+@protocol MaplyTileLocalStorage <NSObject>
+
+/**
+ Return the data for the given tile. nil means you don't have the tile, so we'll try other sources.
+ fetchInfo is a MaplyRemoteTileFetchInfo describing the rest of the tile characteristics.
+ tileID is the tile in question.
+ */
+- (id __nullable)dataForTile:(MaplyRemoteTileFetchInfo * __nonnull)fetchInfo tileID:(MaplyTileID)tileID;
+
+@end
+
+/**
+ If a tile fetch request fails, this object allows you second chance to provide the data.
+ Maybe you have an old version in a cache somewhere. Provide that. Or fail and
+ the tile fetch will continue to fail.
+ */
+@protocol MaplyTileSecondChance <NSObject>
+
+/**
+ Return data for a tile that's already failed to load from local cache and remote fetch.
+ This might be an old version of the data you have lying around. It's up to you.
+ Returning nil means the fetch fails as normal.
+ */
+- (id __nullable)dataForTile:(MaplyRemoteTileFetchInfo * __nonnull)fetchInfo tileID:(MaplyTileID)tileID;
+
+@end
+
+@class MaplyRemoteTileFetcherStats;
+@class MaplyRemoteTileFetcherLog;
+
+/**
+ Remote Tile fetcher fetches tiles from remote URLs.
+
+ The tile fetcher interacts with loaders that want tiles, as demanded by samplers.
+ It's complicated. There's a default one of these that will get used if you pass in nil to the MaplyQuadImageLoader.
+ */
+@interface MaplyRemoteTileFetcher : NSObject<MaplyTileFetcher>
+
+/// Initialize with the number of connections the fetcher can have open at once
+- (instancetype __nonnull)initWithName:(NSString * __nonnull)name connections:(int)numConnections;
+
+/// Number of outstanding connections in parallel
+@property (nonatomic) int numConnections;
+
+/// Local storage is for pre-downloaded tiles, rather than a cache. This is consulted *before* we go out to the network.
+/// If it fails, then we hit the local file cache and then we hit the network
+- (void)setLocalStorage:(NSObject<MaplyTileLocalStorage> * __nullable)localStorage;
+
+/// After a tile fails to load from local storage, local cache and then a remote request, you have one more chance to provide the data
+/// Useful if you've got an old version of the tile lying around you might use in a pinch
+- (void)setSecondChance:(NSObject<MaplyTileSecondChance> * __nullable)secondChance;
+
+/// Return the fetching stats since the beginning or since the last reset
+- (MaplyRemoteTileFetcherStats * __nullable)getStats:(bool)allTime;
+
+/// Reset the counters for one variant of stat
+- (void)resetStats;
+
+/// Reset just the active counters
+- (void)resetActiveStats;
+
+/// Start logging request (and times and such)
+- (void)startLogging;
+
+/// Stop logging and return the log itself
+- (MaplyRemoteTileFetcherLog * __nullable)stopLogging;
+
+// If set, you get way too much debugging output
+@property (nonatomic,assign) bool debugMode;
+
+@end
+
+/// Stats collected by the fetcher
+@interface MaplyRemoteTileFetcherStats : NSObject
+
+@property (nonatomic,readonly,weak,nullable) MaplyRemoteTileFetcher *fetcher;
+
+// Start of stats collection
+@property (nonatomic,nonnull,strong) NSDate *startDate;
+
+// Total requests, remote and cached
+@property (nonatomic) int totalRequests;
+
+// Requests that resulted in a remote HTTP call
+@property (nonatomic) int remoteRequests;
+
+// Total requests cancelled
+@property (nonatomic) int totalCancels;
+
+// Requests failed
+@property (nonatomic) int totalFails;
+
+// Bytes of remote data loaded
+@property (nonatomic) int remoteData;
+
+// Bytes of cached data loaded
+@property (nonatomic) int localData;
+
+// Total time spent waiting for successful remote data requests
+@property (nonatomic) NSTimeInterval totalLatency;
+
+// The maximum number of requests we've had at once (since the last reset)
+@property (nonatomic) int maxActiveRequests;
+
+// Current number of active requests
+@property (nonatomic) int activeRequests;
+
+// Add the given stats to ours
+- (void)addStats:(MaplyRemoteTileFetcherStats * __nonnull)stats;
+
+// Print out the stats
+- (void)dump;
+
+@end
+
+/**
+ Single entry for the logging. Reports on the status of a specific fetch.
+ */
+@interface MaplyRemoteTileFetcherLogEntry : NSObject
+
+/// URL this is about
+@property (nonatomic,nonnull) NSURLRequest *urlReq;
+
+/// Total size of data
+@property (nonatomic) int size;
+
+/// Did we get it at all?
+@property (nonatomic) bool success;
+
+/// True if it was cached on local storage
+@property (nonatomic) bool wasCached;
+
+/// Time when the request was first presented to the RemotetTileFetcher
+@property (nonatomic) NSTimeInterval queuedTime;
+
+/// Time when the remote request was initiated by the system
+@property (nonatomic) NSTimeInterval startedTime;
+
+/// If successful, when we got the request back
+@property (nonatomic) NSTimeInterval finishedTime;
+
+@end
+
+/// Log of remote fetches, how long they took, their results and so on
+@interface MaplyRemoteTileFetcherLog : NSObject
+
+/// When this log begins
+@property (nonatomic) NSTimeInterval startTime;
+
+/// When the log ends
+@property (nonatomic) NSTimeInterval endTime;
+
+/// Individual log entries sorted by finishedTime (probably)
+- (NSArray<MaplyRemoteTileFetcherLogEntry *> * __nullable)getEntries;
+
+/// Print it all out
+- (NSString * __nonnull)dump;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyRenderController.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyRenderController.h
new file mode 100644
index 0000000..0c7c36d
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyRenderController.h
@@ -0,0 +1,1007 @@
+/*
+ * MaplyRenderController.h
+ * WhirlyGlobeMaplyComponent
+ *
+ * Created by Stephen Gifford on 1/19/18.
+ * Copyright 2012-2022 Saildrone Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyScreenMarker.h>
+#import <WhirlyGlobe/MaplyVectorObject.h>
+#import <WhirlyGlobe/MaplyComponentObject.h>
+#import <WhirlyGlobe/MaplySharedAttributes.h>
+#import <WhirlyGlobe/MaplyLight.h>
+#import <WhirlyGlobe/MaplyShader.h>
+#import <WhirlyGlobe/MaplyTexture.h>
+#import <WhirlyGlobe/MaplyParticleSystem.h>
+#import <WhirlyGlobe/MaplyPoints.h>
+#import <WhirlyGlobe/MaplyCluster.h>
+#import <WhirlyGlobe/MaplyRenderTarget.h>
+#import <WhirlyGlobe/MaplyActiveObject.h>
+#import <WhirlyGlobe/MaplyControllerLayer.h>
+
+@class MaplyRemoteTileFetcher;
+
+/// Where we'd like an add to be executed. If you need immediate feedback,
+/// then be on the main thread and use MaplyThreadCurrent. Any is the default.
+typedef NS_ENUM(NSInteger, MaplyThreadMode) {
+ MaplyThreadCurrent,
+ MaplyThreadAny,
+};
+
+/// The various image formats we support. RGBA is the default, and most expensive.
+typedef NS_ENUM(NSInteger, MaplyQuadImageFormat) {
+ MaplyImageIntRGBA,
+ MaplyImageUShort565,
+ MaplyImageUShort4444,
+ MaplyImageUShort5551,
+ MaplyImageUByteRed,MaplyImageUByteGreen,MaplyImageUByteBlue,MaplyImageUByteAlpha,
+ MaplyImageUByteRG,
+ MaplyImageUByteRGB,
+ MaplyImageETC2RGB8,MaplyImageETC2RGBA8,MaplyImageETC2RGBPA8,
+ MaplyImageEACR11,MaplyImageEACR11S,MaplyImageEACRG11,MaplyImageEACRG11S,
+ MaplyImage4Layer8Bit,
+ // Metal only
+ MaplyImageSingleFloat16,MaplyImageSingleFloat32,MaplyImageDoubleFloat16,MaplyImageDoubleFloat32,MaplyImageQuadFloat16,MaplyImageQuadFloat32,
+ MaplyImageInt16,MaplyImageUInt32,MaplyImageDoubleUInt32,MaplyImageQuadUInt32
+};
+
+/// Wrap values for certain types of textures
+#define MaplyImageWrapNone (0)
+#define MaplyImageWrapX (1<<0)
+#define MaplyImageWrapY (1<<1)
+
+@class MaplyRenderController;
+
+/// The system can set up as either GL or Metal
+typedef NS_ENUM(NSInteger, MaplyRenderType) {
+// MaplyRenderGLES,
+ MaplyRenderMetal,
+ MaplyRenderUnknown
+};
+
+/**
+ Render Controller Protocol defines the methods required of a render controller.
+
+ The view controllers and offscreen renderers implement this protocol.
+ */
+@protocol MaplyRenderControllerProtocol <NSObject>
+
+/**
+ Set the offset for the screen space objects.
+
+ In general you want the screen space objects to appear on top of everything else. There used to be structural versions for this, but now you can mix and match where everything appears. This controls the offset that's used to push screen space objects behind everything else in the list (and thus, on top).
+
+ If you set this to 0, you can control the ordering of everything more precisely.
+ */
+@property (nonatomic,assign) int screenObjectDrawPriorityOffset;
+
+/**
+ Clear all the currently active lights.
+
+ There are a default set of lights, so you'll want to do this before adding your own.
+ */
+- (void)clearLights;
+
+/**
+ Reset the lighting back to its default state at startup.
+
+ This clears out all the lights and adds in the default starting light source.
+ */
+- (void)resetLights;
+
+/**
+ Add the given light to the list of active lights.
+
+ This method will add the given light to our active lights. Most shaders will recognize these lights and do the calculations. If you have a custom shader in place, it may or may not use these.
+
+ Triangle shaders use the lights, but line shaders do not.
+ */
+- (void)addLight:(MaplyLight *__nonnull)light;
+
+/// Remove the given light (assuming it's active) from the list of lights.
+- (void)removeLight:(MaplyLight *__nonnull)light;
+
+/**
+ Set the rendering hints to control how the renderer is configured.
+
+ This is a bit vestigial, but still has a few important uses. The hints should be set right after the init call. Any later and they'll probably be ignored.
+
+ The rendering hints are as follows.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyRenderHintZBuffer|bool|If set, we'll explicitly turn on the Z buffer. Normally it's off until a drawable requests it, allowing us to play neat tricks with overlays. The only time you should be turning this on is if you're doing 3D elevation. The default is off.|
+ |kMaplyRenderHintCulling|bool|If set, we'll use the internal culling logic. Texture and drawable atlases have largely made this pointless. Leave it off unless you have a compelling reason to turn it on.|
+ |kMaplyRendererLightingMode|NSString|This can be set to @"none", in which case we use optimized shaders that do no lighting or "regular". The latter is the default.|
+ */
+- (void)setHints:(NSDictionary *__nonnull)hintsDict;
+
+/**
+ Add a cluster generator for making clustered marker images on demand.
+
+ When the layout system clusters a bunch of markers or labels together, it needs new images to represent the cluster.
+
+ You can provide a custom image for each group of markers by filling in one of these generates and passing it in.
+ */
+- (void)addClusterGenerator:(NSObject <MaplyClusterGenerator> *__nonnull)clusterGen;
+
+/**
+ Add one or more screen markers to the current scene.
+
+ This method will add the given MaplyScreenMaker objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param markers An NSArray of MaplyScreenMarker objects.
+
+ @param desc The desciption dictionary which controls how the markers will be constructed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|The color we'll use for the rectangle that makes up a marker. White by default.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The marker will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The marker will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyDrawPriority|NSNumber|If set, the markers are sorted by this number. Larger numbers will be sorted later.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a marker in when it appears and out when it disappears.|
+ |kMaplyFadeIn|NSNumber|The number of seconds to fade a marker in when it appears. This overrides kMaplyFade.|
+ |kMaplyFadeOut|NSNumber|The number of seconds to fade a marker out when it disappears. This override kMaplyFade.|
+ |kMaplyFadeOutTime|NSNumber|If you want to create an object, just to have it fade out at a specific time, this is what you set.|
+ |kMaplyShader|NSString|If set, this is the name of the MaplyShader to use when rendering the screen markers.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyEnableStart|NSNumber|If set, this controls when the resulting objects will be activated.|
+ |kMaplyEnableEnd|NSNumber|If set, this controls when the resulting objects will be deactivated.|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+ |kMaplyClusterGroup|NSNumber|If set, the screen markers will be clustered together according to the given group ID. Off by default, but 0 is the default cluster.|
+
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addScreenMarkers:(NSArray *__nonnull)markers desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more 3D markers to the current scene.
+
+ This method will add the given MaplyMarker objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param markers An NSArray of MaplyMarker objects.
+
+ @param desc The desciption dictionary which controls how the markers will be constructed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|The color we'll use for the rectangle that makes up a marker. White by default.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The marker will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The marker will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a marker in when it appears and out when it disappears.|
+ |kMaplyFadeIn|NSNumber|The number of seconds to fade a marker in when it appears. This overrides kMaplyFade.|
+ |kMaplyFadeOut|NSNumber|The number of seconds to fade a marker out when it disappears. This override kMaplyFade.|
+ |kMaplyFadeOutTime|NSNumber|If you want to create an object, just to have it fade out at a specific time, this is what you set.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyMarkerDrawPriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's off by default, meaning that the geometry will draw on top of anything (respecting the kMaplyDrawPriority).|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addMarkers:(NSArray *__nonnull)markers desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more screen labels to the current scene.
+
+ This method will add the given MaplyScreenLabel objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param labels An NSArray of MaplyScreenLabel objects.
+
+ @param desc The desciption dictionary which controls how the labels will be constructed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyTextColor|UIColor|Color we'll use for the text. Black by default.|
+ |kMaplyBackgroundColor|UIColor|Color we'll use for the rectangle background. Use clearColor to make this invisible.|
+ |kMaplyFont|UIFont|The font we'll use for the text.|
+ |kMaplyLabelHeight|NSNumber|Height of the text in points.|
+ |kMaplyLabelWidth|NSNumber|Width of the text in points. It's best to set Height and leave this out. That way the width will be calculated by the toolkit.|
+ |kMaplyJustify|NSString|This can be set to @"middle", @"left", or @"right" to justify the text around the location.|
+ |kMaplyTextJustify|NSString|This can be kMaplyTextJustifyRight, kMaplyTextJustifyCenter, or kMaplyTextJustifyLeft|
+ |kMaplyShadowSize|NSNumber|If set, we'll draw a shadow with the kMaplyShadowColor offset by this amount. We recommend using an outline instead.|
+ |kMaplyShadowColor|UIColor|If we're drawing a shadow, this is its color.|
+ |kMaplyTextOutlineSize|NSNumber|If set, we'll draw an outline around the text (really draw it twice). The outline will be this large.|
+ |kMaplyTextOutlineColor|UIColor|If we're drawing an outline, it's in this color.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The label will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The label will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyDrawPriority|NSNumber|If set, the labels are sorted by this number. Larger numbers will be sorted later.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a screen label in when it appears and out when it disappears.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyEnableStart|NSNumber|If set, this controls when the resulting objects will be activated.|
+ |kMaplyEnableEnd|NSNumber|If set, this controls when the resulting objects will be deactivated.|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addScreenLabels:(NSArray *__nonnull)labels desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more 3D labels to the current scene.
+
+ This method will add the given MaplyLabel objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param labels An NSArray of MaplyLabel objects.
+
+ @param desc The desciption dictionary which controls how the labels will be constructed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyTextColor|UIColor|Color we'll use for the text. Black by default.|
+ |kMaplyBackgroundColor|UIColor|Color we'll use for the rectangle background. Use clearColor to make this invisible.|
+ |kMaplyFont|UIFont|The font we'll use for the text.|
+ |kMaplyLabelHeight|NSNumber|Height of the text in display coordinates. For the globe these are based on radius = 1.0.|
+ |kMaplyLabelWidth|NSNumber|Width of the text in display coordinates. It's best to set Height and leave this out. That way the width will be calculated by the toolkit.|
+ |kMaplyJustify|NSString|This can be set to @"middle", @"left", or @"right" to justify the text around the location.|
+ |kMaplyShadowSize|NSNumber|If set, we'll draw a shadow with the kMaplyShadowColor offset by this amount. We recommend using an outline instead.|
+ |kMaplyShadowColor|UIColor|If we're drawing a shadow, this is its color.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The label will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The label will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a label in when it appears and out when it disappears.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyLabelDrawPriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's off by default, meaning that the geometry will draw on top of anything (respecting the kMaplyDrawPriority).|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addLabels:(NSArray *__nonnull)labels desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more vectors to the current scene.
+
+ This method will add the given MaplyVectorObject objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param vectors An NSArray of MaplyVectorObject objects.
+
+ @param desc The desciption dictionary which controls how the vectors will look. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the vector features.|
+ |kMaplyVecWidth|NSNumber|If the geometry is not filled, this is the width of the GL lines.|
+ |kMaplyFilled|NSNumber boolean|If set, the areal geometry will be tesselated, taking holes into account. The resulting triangles will be displayed instead of the vectors.|
+ |kMaplySubdivType|NSString|When present, this requests that the geometry be broken up to follow the globe (really only makes sense there). It can be set to kMaplySubdivGreatCircle or kMaplySubdivSimple which do a great circle subdivision and a simple 3-space subdivision respectively. If the key is missing, we do no subdivision at all.|
+ |kMaplySubdivEpsilon|NSNumber|If there's a kMaplySubdivType set this is the epsilon we'll pass into the subdivision routine. The value is in display coordinates. 0.01 is a reasonable value. Smaller results in more subdivision.|
+ |kMaplyVecTexture|UIImage|If set and the kMaplyFilled attribute is set, we will apply the given texture across any areal features. How the texture is applied can be controlled by kMaplyVecTexScaleX, kMaplyVecTexScaleY, kMaplyVecCenterX, kMaplyVecCenterY, and kMaplyVecTextureProjection|
+ |kMaplyVecTexScaleX,kMaplyVecTexScaleY|NSNumber|These control the scale of the texture application. We'll multiply by these numbers before generating texture coordinates from the vertices.|
+ |kMaplyVecCenterX,kMaplyVecCenterY|NSNumber|These control the center of a texture application. If not set we'll use the areal's centroid. If set, we'll use these instead. They should be in local coordinates (probably geographic radians).|
+ |kMaplyVecTextureProjection|NSString|This controls how a texture is projected onto an areal feature. By default we just use the geographic coordinates and stretch them out. This looks odd for very large features. If you set this to kMaplyProjectionTangentPlane then we'll take the center of the feature, make a tangent plane and then project the coordinates onto that tangent plane to get texture coordinates. This looks nice at the poles. If set to kMaplyProjectionScreen the texture is mapped on after screen space projection around the center of the feature.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a vector in when it appears and out when it disappears.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyVectorDrawPriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's off by default, meaning that the geometry will draw on top of anything (respecting the kMaplyDrawPriority).|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplySelectable|NSNumber boolean|Off by default. When enabled, the vector feature will be selectable by a user.|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addVectors:(NSArray *__nonnull)vectors desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Make a copy of the base object and apply the attributes given for the new version.
+
+ This call makes a cheap copy of the vectors in the given MaplyComponentObject and applies the given description to them. You can use this to make a wider or thinner version of a set of vectors, or change their color, while continuing to draw the originals. Or not, as the case may be.
+
+ This is useful for vector maps where we tend to reuse the same geometry at multiple levels and with different colors and line widths.
+
+ Instancing only works with a handful of visual changes. For instance, you can't make a filled and non-filled version.
+
+ @param baseObj The MaplyComponentObject returned by an addVectors: call. This only works for vectors.
+
+ @param desc The description dictionary with controls how vectors will be displayed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the vector features.|
+ |kMaplyVecWidth|NSNumber|If the geometry is not filled, this is the width of the GL lines.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyVectorDrawPriorityDefault.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)instanceVectors:(MaplyComponentObject *__nonnull)baseObj desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more widened vectors to the current scene.
+
+ Build widened vectors
+
+
+ @param desc The description dictionary which controls how vectors will be displayed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the features.|
+ |kMaplyVecWidth|NSNumber|If the geometry is not filled, this is the width of the lines.|
+ |kMaplyWideVecCoordType|NSNumber|Vectors can be widened in real coordinates (kMaplyWideVecCoordTypeReal) or screen coordinates (kMaplyWideVecCoordTypeScreen). In the latter case they stay the same size now matter how you zoom.|
+ |kMaplyWideVecJoinType|NSNumber|When lines meet in a join there are several options for representing them. These include kMaplyWideVecMiterJoin, which is a simple miter join and kMaplyWideVecBevelJoin which is a more complicated bevel. See http://www.w3.org/TR/SVG/painting.html#StrokeLinejoinProperty for how these look.|
+ |kMaplyWideVecMiterLimit|NSNumber|When using miter joins you can trigger them at a certain threshold.|
+ |kMaplyWideVecTexRepeatLen|NSNumber|This is the repeat size for a texture applied along the widened line. For kMaplyWideVecCoordTypeScreen this is pixels.|
+ |kMaplyVecTexture|UIImage or MaplyTexture|This the texture to be applied to the widened vector.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyVectorDrawPriorityDefault.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addWideVectors:(NSArray *__nonnull)vectors desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more model instances.
+
+ Each MaplyGeomInstance points to a MaplyGeomModel. All those passed in here will be grouped and processed together.
+
+
+ @param desc The description dictionary which controls how the models are displayed, selected, and so forth.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplySelectable|NSNumber boolean|Off by default. When enabled, the vector feature will be selectable by a user.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addModelInstances:(NSArray *__nonnull)modelInstances desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or raw geometry models.
+
+ Each MaplyGeometryModel holds points and triangles in display space. These are relatively "raw" geometry and are passed to the geometry manager as is.
+
+
+ @param desc The description dictionary which controls how the geometry is displayed, selected, and so forth.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplySelectable|NSNumber boolean|Off by default. When enabled, the vector feature will be selectable by a user.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addGeometry:(NSArray *__nonnull)geom desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more MaplyShape children to the current scene.
+
+ This method will add the given MaplyShape derived objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param shapes An NSArray of MaplyShape derived objects.
+
+ @param desc The desciption dictionary which controls how the shapes will look. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the shape features.|
+ |kMaplyShapeSampleX|NSNumber|Number of samples to use in one direction when converting to polygons.|
+ |kMaplyShapeSampleY|NSNumber|Number of samples to use in the other direction when converting to polygons.|
+ |kMaplyShapeInsideOut|NSNumber boolean|If set to YES, we'll make the spheres inside out and such. Set to NO by default.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The shapes will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The shapes will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a shape in when it appears and out when it disappears.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyVectorShapePriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's on by default, meaning that the geometry can be occluded by things drawn first.|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addShapes:(NSArray *__nonnull)shapes desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more MaplySticker objects to the current scene.
+
+ This method will add the given MaplySticker objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param stickers An NSArray of MaplySticker derived objects.
+
+ @param desc The desciption dictionary which controls how the stickers will look. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the stickers.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The stickers will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The stickers will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a sticker in when it appears and out when it disappears.|
+ |kMaplySampleX|NSNumber|Stickers are broken up along two dimensions to adhere to the globe. By default this is done adaptively. If you want to override it, this is the X dimension for the sticker.|
+ |kMaplySampleY|NSNumber|If you want to override it, this is the Y dimension for the sticker.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyVectorShapePriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's off by default, meaning that it will draw on top of things before it..|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyShader|NSString|If set, this is the name of the MaplyShader to use when rendering the sticker(s).|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addStickers:(NSArray *__nonnull)stickers desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Modify an existing sticker. This only supports changing the active textures.
+
+ This method will change attributes of a sticker that's currently in use. At present that's just the images it's displaying.
+
+ @param compObj The component object representing one or more existing stickers.
+
+ @param desc The description dictionary for changes we're making to the sticker.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyStickerImages|NSARray|The array of images to apply to the sticker. You can reuse old ones or introduce new ones.|
+ */
+- (void)changeSticker:(MaplyComponentObject *__nonnull)compObj desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more MaplyBillboard objects to the current scene.
+
+ This method will add the given MaplyBillboard objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param billboards An NSArray of MaplyBillboard objects.
+
+ @param desc The description dictionary that controls how the billboards will look. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the billboards.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The billboards will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The billboards will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyBillboardDrawPriorityDefault.|
+ |kMaplyBillboardOrient|NSNumber|Controls the billboard orientation. It's either directly toward the eye with kMaplyBillboardOrientEye or takes the ground into account with kMaplyBillboardOrientGround. Ground is the default.
+
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+ */
+- (MaplyComponentObject *__nullable)addBillboards:(NSArray *__nonnull)billboards desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add a particle system to the scene.
+
+ This adds a particle system to the scene, but does not kick off any particles.
+
+ @param partSys The particle system to start.
+
+ @param desc Any additional standard parameters (none at present).
+
+ @param threadMode MaplyThreadAny will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread. For particles, it's best to make a separate thread and use MaplyThreadCurrent.
+ */
+- (MaplyComponentObject *__nullable)addParticleSystem:(MaplyParticleSystem *__nonnull)partSys desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Change the render target for a particle system.
+
+ This changes the render target for an existing particle system that's already been created.
+ Can pass in nil, which means the particles are rendered to the screen directly.
+ This change takes place immediately, so call it on the main thread.
+ */
+- (void)changeParticleSystem:(MaplyComponentObject *__nonnull)compObj renderTarget:(MaplyRenderTarget *__nullable)target;
+
+/**
+ Add a batch of particles to the current scene.
+
+ Particles are short term objects, typically very small. We create them in large groups for efficience.
+
+ You'll need to fill out the MaplyParticleSystem initially and then the MaplyParticleBatch to create them.
+
+ @param batch The batch of particles to add to an active particle system.
+
+ @param threadMode MaplyThreadAny will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread. For particles, it's best to make a separate thread and use MaplyThreadCurrent.
+ */
+- (void)addParticleBatch:(MaplyParticleBatch *__nonnull)batch mode:(MaplyThreadMode)threadMode;
+
+/**
+ Change the representation of the given vector features.
+
+ This will change how any vector features represented by the compObj look.
+
+ You can change kMaplyColor, kMaplyMinVis, kMaplyMaxVis, and kMaplyDrawPriority.
+
+ This version takes a thread mode.
+ */
+- (void)changeVector:(MaplyComponentObject *__nonnull)compObj desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Adds the MaplyVectorObject's passed in as lofted polygons.
+
+ Lofted polygons are filled polygons draped on top of the globe with height. By using a transparent color, these can be used to represent selection or relative values on the globe (or map).
+
+
+ @param polys An NSArray of MaplyVectorObject.
+
+ @param desc The desciption dictionary which controls how the lofted polys will look. It takes the following entries.
+
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the lofted polygons. A bit of alpha looks good.|
+ |kMaplyLoftedPolyHeight|NSNumber|Height of the top of the lofted polygon in display units. For the globe display units are based on a radius of 1.0.|
+ |kMaplyLoftedPolyBase|NSNumber|If present, we'll start the lofted poly at this height. The height is in globe units, based on a radius of 1.0.|
+ |kMaplyLoftedPolyTop|NSNumber boolean|If on we'll create the geometry for the top. On by default.|
+ |kMaplyLoftedPolySide|NSNumber boolean|If on we'll create geometry for the sides. On by default.|
+ |kMaplyLoftedPolyGridSize|NSNumber|The size of the grid (in degrees) we'll use to chop up the vector features to make them follow the sphere (for a globe).|
+ |kMaplyLoftedPolyOutline|NSNumber boolean|If set to @(YES) this will draw an outline around the top of the lofted poly in lines.|
+ |kMaplyLoftedPolyOutlineBottom|NSNumber boolean|If set to @(YES) this will draw an outline around the bottom of the lofted poly in lines.|
+ |kMaplyLoftedPolyOutlineColor|UIColor|If the outline is one this is the outline's color.|
+ |kMaplyLoftedPolyOutlineWidth|NSNumber|This is the outline's width if it's turned on.|
+ |kMaplyLoftedPolyOutlineDrawPriority|NSNumber|Draw priority of the lines created for the lofted poly outline.|
+ |kMaplyLoftedPolyOutlineSide|NSNumber boolean|If set and we're drawing an outline, this will create lines up the sides.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The lofted polys will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The lofted polys will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a lofted poly in when it appears and out when it disappears.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyLoftedPolysShapePriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's on by default, meaning that it can be occluded by geometry coming before it.|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addLoftedPolys:(NSArray *__nonnull)polys desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add a group of points to the display.
+
+ Adds a group of points all at once. We're assuming you want to draw a lot of points, so you have to group them together into a MaplyPoints.
+
+
+ @param points The points to add to the scene.
+
+ @param desc The desciption dictionary which controls how the points will look. It takes the following entries.
+
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the lofted polygons. A bit of alpha looks good.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The lofted polys will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The lofted polys will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a lofted poly in when it appears and out when it disappears.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyLoftedPolysShapePriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's on by default, meaning that it can be occluded by geometry coming before it.|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addPoints:(NSArray * __nonnull)points desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Represent an image as a MaplyTexture.
+
+ This version of addTexture: allows more precise control over how the texture is represented. It replaces the other addTexture: and addTextureToAtlas calls.
+
+ @param image The UIImage to add as a texture.
+
+ @param desc A description dictionary controlling how the image is converted to a texture and represented in the system.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyTexFormat|NSNumber|The texture format to use for the image. Consult addTexture:imageFormat:wrapFlags:mode: for a list. Default is MaplyImageIntRGBA.|
+ |kMaplyTexMinFilter|NSNumber|Filter to use for minification. This can be kMaplyMinFilterNearest or kMaplyMinFilterLinear. Default is kMaplyMinFilterLinear.|
+ |kMaplyTexMagFilter|NSNumber|Filter to use for magnification. This can be kMaplyMinFilterNearest or kMaplyMinFilterLinear. Default is kMaplyMinFilterLinear.|
+ |kMaplyTexWrapX|NSNumber boolean|Texture wraps in x direction. Off by default.|
+ |kMaplyTexWrapY|NSNumber boolean|Texture wraps in y direction. Off by default.|
+ |kMaplyTexAtlas|NSNumber boolean|If set, the texture goes into an appropriate atlas. If not set, it's a standalone texture (default).|
+
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred.
+ */
+- (MaplyTexture *__nullable)addTexture:(UIImage *__nonnull)image desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Create an empty texture and return it.
+
+ Empty textures are used for offscreen rendering and other crazy stuff. You probably don't want to do this.
+
+ @param spec The description dictionary controlling the format and other textures goodies.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyTexFormat|NSNumber|The texture format to use for the image. Consult addTexture:imageFormat:wrapFlags:mode: for a list. Default is MaplyImageIntRGBA.|
+ |kMaplyTexMinFilter|NSNumber|Filter to use for minification. This can be kMaplyMinFilterNearest or kMaplyMinFilterLinear. Default is kMaplyMinFilterLinear.|
+ |kMaplyTexMagFilter|NSNumber|Filter to use for magnification. This can be kMaplyMinFilterNearest or kMaplyMinFilterLinear. Default is kMaplyMinFilterLinear.|
+ |kMaplyTexWrapX|NSNumber boolean|Texture wraps in x direction. Off by default.|
+ |kMaplyTexWrapY|NSNumber boolean|Texture wraps in y direction. Off by default.|
+ |kMaplyTexAtlas|NSNumber boolean|If set, the texture goes into an appropriate atlas. If not set, it's a standalone texture (default).|
+ |kMaplyTexMipmap|NSNumber boolean|If set, we'll create the given texture with mipmap levels.|
+
+ @param sizeX The horizontal size of the textures (in pixels).
+
+ @param sizeY Vertical size of the texture (in pixels).
+ */
+- (MaplyTexture *__nullable)createTexture:(NSDictionary * _Nullable)spec sizeX:(int)sizeX sizeY:(int)sizeY mode:(MaplyThreadMode)threadMode;
+
+/**
+ Creates a new texture that references part of an existing texture.
+
+ @param x Horizontal offset within the existing texture.
+ @param y Vertical offset within the existing texture.
+ @param width Width of the chunk to make a new texture.
+ @param height Height of the chunk to make a new texture.
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred if you're on the main thread.
+ */
+- (MaplyTexture *__nullable)addSubTexture:(MaplyTexture *__nonnull)tex xOffset:(int)x yOffset:(int)y width:(int)width height:(int)height mode:(MaplyThreadMode)threadMode;
+
+/**
+ Remove the OpenGL ES textures associated with the given MaplyTextures.
+
+ MaplyTextures will remove their associated OpenGL textures when they go out of scope. This method does it expicitly and clears out the internals of the MaplyTexture.
+
+ Only call this if you're managing the texture explicitly and know you're finished with them.
+ */
+- (void)removeTextures:(NSArray *__nonnull)texture mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add a render target to the system
+
+ Sets up a render target and will start rendering to it on the next frame.
+
+ Keep the render target around so you can remove it later.
+ */
+- (void)addRenderTarget:(MaplyRenderTarget * _Nonnull)renderTarget;
+
+/**
+ Set the texture a given render target is writing to.
+
+ Render targets start out with one, but you may wish to change it.
+ */
+- (void)changeRenderTarget:(MaplyRenderTarget * __nonnull)renderTarget tex:(MaplyTexture * __nullable)tex;
+
+/**
+ Remove the given render target from the system.
+
+ Ask the system to stop drawing to the given render target. It will do this on the next frame.
+ */
+- (void)removeRenderTarget:(MaplyRenderTarget * _Nonnull)renderTarget;
+
+/**
+ Set up the the mask render target. We use it to keep one set of features from render on top of another set.
+ */
+- (void)startMaskTarget:(NSNumber * __nullable)scale;
+
+/**
+ Turn off the render target for masks.
+ */
+- (void)stopMaskTarget;
+
+/**
+ Normally the layout layer runs periodically if you change something or when you move around.
+ You can ask it to run ASAP right here. Layout runs on its own thread, so there may still be a delay.
+ */
+- (void)runLayout;
+
+/**
+ Request a one time clear for the render target.
+
+ Rather than clearing every frame, you may want to specifically request a clear. This will
+ be executed at the next frame and then not again.
+*/
+- (void)clearRenderTarget:(MaplyRenderTarget * _Nonnull)renderTarget mode:(MaplyThreadMode)threadMode;
+
+/**
+ Remove all information associated with the given MaplyComponentObject's.
+
+ Every add call returns a MaplyComponentObject. This will remove any visible features, textures, selection data, or anything else associated with it.
+
+ @param theObjs The MaplyComponentObject's we wish to remove.
+
+ @param threadMode For MaplyThreadAny we'll do the removal on another thread. For MaplyThreadCurrent we'll block the current thread to finish the removal. MaplyThreadAny is preferred.
+ */
+- (void)removeObjects:(NSArray *__nonnull)theObjs mode:(MaplyThreadMode)threadMode;
+
+/**
+ Disable a group of MaplyComponentObject's all at once.
+
+ By default all of the geometry created for a given object will appear. If you set kMaplyEnable to @(NO) then it will exist, but not appear. This has the effect of setting kMaplyEnable to @(NO).
+
+ @param theObjs The objects to disable.
+
+ @param threadMode For MaplyThreadAny we'll do the disable on another thread. For MaplyThreadCurrent we'll block the current thread to finish the disable. MaplyThreadAny is preferred.
+ */
+- (void)disableObjects:(NSArray *__nonnull)theObjs mode:(MaplyThreadMode)threadMode;
+
+/**
+ Enable a group of MaplyComponentObject's all at once.
+
+ By default all of the geometry created for a given object will appear. If you set kMaplyEnable to @(NO) then it will exist, but not appear. This has the effect of setting kMaplyEnable to @(YES).
+
+ @param theObjs The objects to enable.
+
+ @param threadMode For MaplyThreadAny we'll do the enable on another thread. For MaplyThreadCurrent we'll block the current thread to finish the enable. MaplyThreadAny is preferred.
+ */
+- (void)enableObjects:(NSArray *__nonnull)theObjs mode:(MaplyThreadMode)threadMode;
+
+/**
+ Set the representation to use for one or more UUIDs
+
+ @param uuids Array of NSString UUIDs to update
+ @param repName The representation name to apply, nil to return to the default
+ @param threadMode For MaplyThreadAny we'll do the enable on another thread. For MaplyThreadCurrent we'll block the current thread to finish the enable. MaplyThreadAny is preferred.
+ */
+- (void)setRepresentation:(NSString *__nullable)repName
+ ofUUIDs:(NSArray<NSString *> *__nonnull)uuids
+ mode:(MaplyThreadMode)threadMode;
+
+/**
+ Set the representation to use for one or more UUIDs
+
+ @param uuids Array of NSString UUIDs to update
+ @param repName The representation name to apply, nil to return to the default
+ @param fallbackRepName The representation to use of no item with `repName` exists.
+ @param threadMode For MaplyThreadAny we'll do the enable on another thread. For MaplyThreadCurrent we'll block the current thread to finish the enable. MaplyThreadAny is preferred.
+ */
+- (void)setRepresentation:(NSString *__nullable)repName
+ fallbackRepName:(NSString *__nullable)fallbackRepName
+ ofUUIDs:(NSArray<NSString *> *__nonnull)uuids
+ mode:(MaplyThreadMode)threadMode;
+
+/**
+ Pass a uniform block through to a shader. Only for Metal.
+
+ Custom Metal shaders may have their own uniform blocks associated with a known bufferID.
+ This is how you pass those through for objects you've already created.
+ Useful for things like custom animation.
+ */
+- (void)setUniformBlock:(NSData *__nonnull)uniBlock buffer:(int)bufferID forObjects:(NSArray<MaplyComponentObject *> *__nonnull)compObjs mode:(MaplyThreadMode)threadMode;
+
+/**
+ Call this to start journaling changes for this thread.
+
+ Your can collect up your add/remove/enable changes on the current thread. Call startChanges to start collecting and endChanges to flush the changes.
+
+ This has no real meaning on the main thread and don't collect too many changes. They take memory.
+ */
+- (void)startChanges;
+
+/**
+ Call this to flush your journal changes out ot the scene.
+
+ This is the other end of startChanges.
+ */
+- (void)endChanges;
+
+/**
+ Add a compiled shader. We'll refer to it by the scene name.
+
+ Once you've create a MaplyShader, you'll need to add it to the scene to use it.
+
+ @param shader The working shader (be sure valid is true) to add to the scene.
+ */
+- (void)addShaderProgram:(MaplyShader *__nonnull)shader;
+
+/**
+ Look for a shader with the given name.
+
+ This is the shader's own name as specified in the init call, not the scene name as might be specified in addShaderProgram:sceneName:
+
+ @return Returns the registered shader if it found one.
+ */
+- (MaplyShader *__nullable)getShaderByName:(NSString *__nonnull)name;
+
+/**
+ Remove a shader that was added earlier.
+ */
+- (void)removeShaderProgram:(MaplyShader *__nonnull)shader;
+
+/**
+ Return the coordinate system being used for the display.
+
+ This returns the local coordinate system, which is used to unroll the earth (for the globe) or via a scaling factor (for the flat map).
+ */
+- (MaplyCoordinateSystem *__nullable)coordSystem;
+
+- (void)setClearColor:(UIColor *__nonnull)clearColor;
+
+/// Return the framebuffer size in pixels (no scale)
+- (CGSize)getFramebufferSize;
+
+// For internal use only
+- (MaplyRenderController * __nullable)getRenderControl;
+
+/// Return the renderer type being used
+- (MaplyRenderType)getRenderType;
+
+/**
+ Add the given active object to the scene.
+
+ Active objects are used for immediate, frame based updates. They're fairly expensive, so be careful. After you create one, you add it to the scene here.
+ */
+- (void)addActiveObject:(MaplyActiveObject *__nonnull)theObj;
+
+/// Remove an active object from the scene.
+- (void)removeActiveObject:(MaplyActiveObject *__nonnull)theObj;
+
+/// Remove an array of active objects from the scene
+- (void)removeActiveObjects:(NSArray *__nonnull)theObjs;
+
+/**
+ Add a MaplyControllerLayer to the globe or map.
+
+ At present, layers are for paged geometry such as image tiles or vector tiles. You can create someting like a MaplyQuadImageTilesLayer, set it up and then hand it to addLayer: to add to the scene.
+ */
+- (bool)addLayer:(MaplyControllerLayer *__nonnull)layer;
+
+/// Remove a MaplyControllerLayer from the globe or map.
+- (void)removeLayer:(MaplyControllerLayer *__nonnull)layer;
+
+/// Remove zero or more MaplyControllerLayer objects from the globe or map.
+- (void)removeLayers:(NSArray *__nonnull)layers;
+
+/// Remove all the user created MaplyControllerLayer objects from the globe or map.
+- (void)removeAllLayers;
+
+/// Return a tile fetcher we may share between loaders
+- (MaplyRemoteTileFetcher * __nullable)addTileFetcher:(NSString * __nonnull)name;
+
+/**
+ If in Metal rendering mode, return the Metal device being used.
+ */
+- (id<MTLDevice> __nullable)getMetalDevice;
+
+/**
+ If in Metal rendering mode, return the shader library set up by the toolkit.
+ */
+- (id<MTLLibrary> __nullable)getMetalLibrary;
+
+/**
+ An explicit teardown. For render controllers you allocate standalone, this is a good idea.
+ */
+- (void)teardown;
+
+@end
+
+/**
+ The Render Controller is a standalone WhirlyGlobe-Maply renderer.
+
+ This Render Controller is used for offline rendering.
+ */
+@interface MaplyRenderController : NSObject<MaplyRenderControllerProtocol>
+
+/// Initialize as an offline renderer of a given target size of the given rendering type
+- (instancetype __nullable)initWithSize:(CGSize)size mode:(MaplyRenderType)renderType;
+
+/// Initialize as an offline renderer of a given target size with default renderer (Metal)
+- (instancetype __nullable)initWithSize:(CGSize)size;
+
+/// If set up in offline mode, this is how we draw
+- (UIImage * __nullable)renderToImage;
+
+/// Return the raw RGBA pixels from the rendered image rather than a UIImage
+- (NSData * __nullable)renderToImageData;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyRenderTarget.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyRenderTarget.h
new file mode 100644
index 0000000..5f6034c
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyRenderTarget.h
@@ -0,0 +1,119 @@
+/*
+ * MaplyRenderTarget.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 1/13/17.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyTexture.h>
+
+typedef NS_ENUM(NSUInteger,MaplyMipmapType) {
+ /// Don't generate a mipmap
+ MaplyMipmapNone,
+ /// Generate a basic mipmap
+ MaplyMipmapAverage,
+ /// Generate a mipmap using Gauss blurring
+ MaplyMipmapGauss
+};
+
+/**
+ Represents a render target (other than the screen)
+
+ Individual objects can ask to be drawn somewhere other than the screen.
+ This is how we do that.
+
+ A render target is just a link between a render every frame and a MaplyTexture. To get at the actual image you use the MaplyTexture.
+
+ At the moment a render target can only draw the full screen, possibly at a lower resolution.
+ */
+@interface MaplyRenderTarget : NSObject
+
+/**
+ The texture we'll draw into.
+
+ This is the texture we'll draw into. Use createTexture to set it up.
+ */
+@property (nonatomic,strong) MaplyTexture *texture;
+
+/**
+ If set, we'll clear the target textures every frame before rendering to it.
+
+ If not set, we won't clear the render target texture between frames.
+
+ True by default.
+ */
+@property (nonatomic) bool clearEveryFrame;
+
+/**
+ If we're generating a mipmap for the attached texture of a render target, this controls
+ how we do it. The default is none.
+ */
+@property (nonatomic) MaplyMipmapType mipmapType;
+
+/**
+ If set, we'll caclulate the min/max for this render target every frame.
+ This is a GPU based calculation for Metal.
+ */
+@property (nonatomic) bool calculateMinMax;
+
+/**
+ Clear the render target to this color every frame.
+
+ Default is clear black.
+ */
+@property (nonatomic,strong) UIColor *clearColor;
+
+
+/**
+ Clear the render target to this value on every frame.
+
+ This is for render targets that are not purely color, such as multiple floats.
+ */
+@property (nonatomic,assign) float clearVal;
+
+/**
+ If set, anything rendered to this render target will blend with what's there.
+
+ If not set, what's rendered will replace what was there before.
+ This is the way it normally works for screen rendering.
+
+ Set to false by default.
+ */
+@property (nonatomic) bool blend;
+
+/**
+ Retrieves a single data value out of the render target. Size is the number of components * size of components.
+ It's best to call this in the snapshot callback. We know the destination isn't being written to at the moment.
+ Metal only.
+ */
+- (NSData *)getValueAtX:(int)x y:(int)y;
+
+/**
+ Returns the whole render target snapshot in the NSData.
+ It's best to call this in the snapshot callback. We know the destination isn't being written to at the moment.
+ Metal only.
+ */
+- (NSData *)getSnapshot;
+
+/**
+ Retreives the min/max data values if those are being calculated.
+ It's best to call this in the snapshot callback. We know the destination isn't being written to at the moment.
+ Metal only.
+ */
+- (NSData *)getMinMaxValues;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyRotateDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyRotateDelegate.h
new file mode 100644
index 0000000..2cb073b
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyRotateDelegate.h
@@ -0,0 +1,29 @@
+/* MaplyRotateDelegate.h
+ * WhirlyGlobeLib
+ *
+ * Created by rghosh0 around 9/26/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+
+@interface MaplyRotateDelegate : NSObject <UIGestureRecognizerDelegate>
+
+//The gesture recognizer
+@property (nonatomic,retain) UIGestureRecognizer* gestureRecognizer;
+
+/// The minimum angle (degrees) that must be subtended before rotation begins
+@property(nonatomic,assign) float rotateThreshold;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyScreenLabel.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyScreenLabel.h
new file mode 100644
index 0000000..f0c00e6
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyScreenLabel.h
@@ -0,0 +1,187 @@
+/*
+ * WGScreenLabel.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 7/24/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+@class MaplyVectorObject;
+
+/// Don't move the label at all
+#define kMaplyLayoutNone (1<<0)
+/// Okay to place centered on point
+#define kMaplyLayoutCenter (1<<1)
+/// Okay to place to the right of a point
+#define kMaplyLayoutRight (1<<2)
+/// Okay to place it to the left of a point
+#define kMaplyLayoutLeft (1<<3)
+/// Okay to place on top of a point
+#define kMaplyLayoutAbove (1<<4)
+/// Okay to place below a point
+#define kMaplyLayoutBelow (1<<5)
+
+/**
+ The Screen Label is a 2D label that tracks a given geographic location.
+
+ This screen label will track the given geographic position. If it's behind the globe it will disappear. The label is rendered in a fixed size and will always appear on top of other geometry.
+ */
+@interface MaplyScreenLabel : NSObject
+
+/**
+ Location of the screen label in geographic (lat/lon) in radians.
+
+ The screen label will track this position. If it would be behind the globe (in globe mode), then it will disappear.
+ */
+@property (nonatomic,assign) MaplyCoordinate loc;
+
+/**
+ An optional rotation to apply to the screen label.
+
+ This is a rotation we'll apply after the screen position has been calculated. You can use this to do things like track the orientation of roads.
+
+ Rotation is in radians counter-clockwise from north.
+ */
+@property (nonatomic,assign) float rotation;
+
+/**
+ When the screen is rotated, try to keep the label upright.
+
+ This tells the layout and display engine to keep the label oriented upright no matter what. In practice this means it will manipulate the rotation by 180 degrees.
+ */
+@property (nonatomic,assign) bool keepUpright;
+
+/**
+ The actual text to display.
+
+ This is a simple NSString for the text. Things like font are set in the NSDictionary passed in to the add call in the view controller.
+ */
+@property (nonatomic,strong) NSString * __nullable text;
+
+/**
+ Text can be accompanied by an optional icon image.
+
+ If set, we'll put this image to the left of the text in the screen label. The UIImage will be tracked by the view controller and reused as needed or disposed of when no longer needed.
+
+ The name had to change because Apple's private selector search is somewhat weak.
+ */
+@property (nonatomic,strong) UIImage * __nullable iconImage2;
+
+/**
+ Icon size in points.
+
+ If there is an icon image, this is how big it is.
+ */
+@property (nonatomic,assign) CGSize iconSize;
+
+/**
+ An optional offset for the whole screen label.
+
+ If set, we'll move the screen label around by this amount before rendering it. These are screen coordinates, not geographic.
+ */
+@property (nonatomic,assign) CGPoint offset;
+
+/**
+ An optional color override.
+
+ If set, this color will override the color passed in with the NSDictionary in the view controller's add method.
+ */
+@property (nonatomic,strong) UIColor * __nullable color;
+
+/**
+ Label selectability. On by default
+
+ If set, this label can be selected by the user. If not set, this screen label will never appear in selection results.
+ */
+@property (nonatomic,assign) bool selectable;
+
+/**
+ The layout importance compared to other features, 0 by default.
+
+ The toolkit has a simple layout engine that runs several times per second. It controls the placement of all participating screen based features, such as MaplyScreenLabel and MaplyScreenMaker objects. This value controls the relative importance of this particular object. By default that importance is 0 so the object must compete with others. Setting it to MAXFLOAT will bypass the layout engine entirely and the object will always appear.
+ */
+@property (nonatomic,assign) float layoutImportance;
+
+/**
+ The placement rules for the layout engine to follow.
+
+ The layout engine isn't the brightest bulb in the string and it needs placement hints. This value tells the engine where we can move the label around. These are bit flags, so OR them together as needed. The default is everything.
+
+|Layout Flag|Meaning|
+|:----------|:------|
+|kMaplyLayoutRight|The layout engine can put this label to the right of the location point.|
+|kMaplyLayoutLeft|The layout engine can put this label to the left of the location point.|
+|kMaplyLayoutAbove|The layout engine may put this label above the location point, centered.|
+|kMaplyLayoutBelow|The layout engine may put this albel below the location point, centered.|
+ */
+@property (nonatomic,assign) int layoutPlacement;
+
+/**
+ The size of the label for layout purposes.
+
+ If layoutImportance is not set to MAXFLOAT, the screen label will get throw into the mix when doing screen layout. With this, you can set the size of the label when considering layout. If you set this to (0,0) the maker will take up no space, but still be considered in the layout.
+ */
+@property (nonatomic,assign) CGSize layoutSize;
+
+/**
+ If this is present, we'll render an ID into the mask layer to be used by other features to mask against.
+ */
+@property (nonatomic,retain,nullable) NSString *maskID;
+
+/**
+ If set, we'll lay out the the text along the given linear or areal feature.
+ Takes the first feature in the vector, if there are multiple.
+ */
+@property (nonatomic,retain,nullable) MaplyVectorObject *layoutVec;
+
+
+/**
+ Used to resolve to resolve labels that show the same thing.
+
+ By default this is nil and not used to resolve conflicts. When you set it to
+ something, such as a string, it will be used to resolve display conflicts.
+ Only one object that has this unique ID (evaluated with isEqualToString:) will be displayed.
+ Importance is evaluated first, so the most important will be placed first.
+ */
+@property (nonatomic,retain,nullable) NSString *uniqueID;
+
+/**
+ User data object for selection
+
+ When the user selects a feature and the developer gets it in their delegate, this is an object they can use to figure out what the screen label means to them.
+ */
+@property (nonatomic,strong) id __nullable userObject;
+
+@end
+
+/**
+ A version of the maply screen label that moves.
+
+ This version of the screen label can move in a limited way over time.
+ */
+@interface MaplyMovingScreenLabel : MaplyScreenLabel
+
+/// The end point for animation
+@property (nonatomic,assign) MaplyCoordinate endLoc;
+
+/// How long it will take the screen label to get to endLoc
+@property (nonatomic,assign) NSTimeInterval duration;
+
+@end
+
+typedef MaplyScreenLabel WGScreenLabel;
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyScreenMarker.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyScreenMarker.h
new file mode 100644
index 0000000..8ed1bab
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyScreenMarker.h
@@ -0,0 +1,168 @@
+/* MaplyScreenMarker.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 7/21/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+@class MaplyVectorObject;
+
+/**
+ The Screen Marker is a 2D object that displays an image on the screen tracking a given location.
+
+ The screen marker will track the given geographic location and display a centered rectangle with the given image. Essentially it's a free floating icon, similar to the MaplyScreenLabel and it will always be drawn on top of other objects. If the location would be behind the globe (in globe mode), the marker will disappear.
+
+ If you're looking for a 3D marker object, that's the MaplyMarker.
+ */
+@interface MaplyScreenMarker : NSObject
+
+/**
+ The location we're tracking for this particular screen marker.
+
+ Locations are in geographic (lon/lat in radians).
+ */
+@property (nonatomic,assign) MaplyCoordinate loc;
+
+/**
+ Screen size in points.
+
+ The marker will always be this size on the screen. The size is specified in pixels.
+ */
+@property (nonatomic,assign) CGSize size;
+
+/**
+ An optional rotation to apply to the screen marker.
+
+ This is a rotation we'll apply after the screen position has been calculated. The angle is in radians counter-clockwise from north.
+ */
+@property (nonatomic,assign) double rotation;
+
+/**
+ Image or texture to use for the marker.
+
+ If set we'll stretch this UIImage (or MaplyTexture) out over the marker rectangle. If not set, the marker will just be a colored rectangle. The view controller tracks this object and will reuse its texture and dispose of it as needed.
+ */
+@property (nonatomic,strong) id __nullable image;
+
+/**
+ Images to display on the sticker.
+
+ If this is set rather than image, we will cycle through these images on the screen marker. It will take period time to cycle through them all.
+ */
+@property (nonatomic,strong) NSArray * __nullable images;
+
+/**
+ The time we'll take to cycle through all the images for the marker.
+
+ If images are passed in, this is the time it will take to cycle through them all. By default this is 5s.
+ */
+@property (nonatomic) double period;
+
+/**
+ Color for this particular marker.
+
+ If set, this the color we'll use for the marker or how we'll tint the image.
+
+ This overrides the color set in the description dictionary.
+ */
+@property (nonatomic,strong) UIColor * __nullable color;
+
+/**
+ The layout importance compared to other features, 0 by default.
+
+ The toolkit has a simple layout engine that runs several times per second. It controls the placement of all participating screen based features, such as MaplyScreenLabel and MaplyScreenMaker objects. This value controls the relative importance of this particular object. By default that importance is 0 so the object must compete with others. Setting it to MAXFLOAT will bypass the layout engine entirely and the object will always appear.
+ */
+@property (nonatomic,assign) float layoutImportance;
+
+/**
+ The size of the marker for layout purposes.
+
+ If layoutImportance is not set to MAXFLOAT, the screen marker will get throw into the mix when doing screen layout. With this, you can set the size of the marker when considering layout. If you set this to (0,0) the maker will take up no space, but still be considered in the layout.
+ */
+@property (nonatomic,assign) CGSize layoutSize;
+
+/**
+ Screen markers are usually grouped together for rendering efficiency. This controls the order of the marker within that grouping.
+ orderBy is less important than drawPriority.
+ Default is 0 and means no ordering.
+ */
+@property (nonatomic,assign) long orderBy;
+
+/**
+ Offset in screen coordinates.
+
+ Set to zero by default, this is the offset we'll apply to a given screen marker before it's drawn. The values are screen points.
+ */
+@property (nonatomic,assign) CGPoint offset;
+
+/**
+ Vertex attributes to apply to this screen marker.
+
+ MaplyVertexAttribute objects are passed all the way to the shader. Read that page for details on what they do.
+
+ The array of vertex attributes provided here will be copied onto all the vertices we create for the shader. This means you can use these to do things for a single billboard in your shader.
+ */
+@property (nonatomic,strong) NSArray * __nullable vertexAttributes;
+
+/**
+ Screen marker selectability. On by default
+
+ If set, this marker can be selected by the user. If not set, this screen marker will never appear in selection results.
+ */
+@property (nonatomic,assign) bool selectable;
+
+/**
+ A unique identifier for the marker that's propagated through the system.
+ */
+@property (nonatomic,retain,nullable) NSString *uniqueID;
+
+/**
+ If this is present, we'll render an ID into the mask layer to be used by other features to mask against.
+ */
+@property (nonatomic,retain,nullable) NSString *maskID;
+
+/**
+ If set, we'll lay out the marker along the given linear or areal feature.
+ Takes the first feature in the vector, if there are multiple.
+ */
+@property (nonatomic,retain,nullable) MaplyVectorObject *layoutVec;
+
+/**
+ User data object for selection
+
+ When the user selects a feature and the developer gets it in their delegate, this is an object they can use to figure out what the screen marker means to them.
+ */
+@property (nonatomic,strong) id __nullable userObject;
+
+@end
+
+/**
+ A version of the maply screen marker that moves.
+
+ This version of the screen marker can move in a limited way over time.
+ */
+@interface MaplyMovingScreenMarker : MaplyScreenMarker
+
+/// The end point for animation
+@property (nonatomic,assign) MaplyCoordinate endLoc;
+
+/// How long it will take the screen marker to get to endLoc
+@property (nonatomic,assign) NSTimeInterval duration;
+
+@end
+
+typedef MaplyScreenMarker WGScreenMarker;
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyScreenObject.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyScreenObject.h
new file mode 100644
index 0000000..4779746
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyScreenObject.h
@@ -0,0 +1,106 @@
+/*
+ * MaplyScreenObject
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 2/28/15
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+
+/**
+ The Maply Screen Object is used to build up a more complex screen object from multiple pieces.
+
+ You can use one or more of these to build up a combination of labels and images that form a single marker, label, or billboard.
+ */
+@interface MaplyScreenObject : NSObject
+
+/**
+ Add a string to the screen object
+
+ @param str The string to add
+
+ @param font The font to use
+
+ @param color The foreground color of the string.
+ */
+- (void)addString:(NSString *)str font:(UIFont *)font color:(UIColor *)color;
+
+/**
+ Add an attributed string to the screen object.
+
+ This adds an annotated string to the screen object. The size will be based on the length of the string and the font.
+ */
+- (void)addAttributedString:(NSAttributedString *)str;
+
+/**
+ Add an image scaled to the given size.
+
+ Adds a UIImage or MaplyTexture object scaled to the given size.
+ */
+- (void)addImage:(id)image color:(UIColor *)color size:(CGSize)size;
+
+/**
+ Add an image scaled to the given size and offset by the given amount.
+
+ The other version of this call centers around (0,0) so this lets you nudge it.
+ */
+- (void)addImage:(id)image color:(UIColor *)color size:(CGSize)size offset:(CGPoint)offset;
+
+/**
+ Calculate and return the current bounding box of the screen object.
+ */
+- (MaplyBoundingBox)getSize;
+
+/**
+ Apply a scale to all the pieces of the screen object.
+ */
+- (void)scaleX:(double)x y:(double)y;
+
+/**
+ Apply a translation to all the pieces of the screen object.
+ */
+- (void)translateX:(double)x y:(double)y;
+
+/**
+ Add the contents of the given screen object to this screen object.
+ */
+- (void)addScreenObject:(MaplyScreenObject *)screenObj;
+
+@end
+
+/**
+ Features missing to replicate ScreenMarker and ScreenLabel.
+ rotation
+ images (for animation)
+ period (for animation)
+ color
+ layoutImportance
+ layoutSize
+ layoutPlacement (right, left, above, below)
+ vertexAttributes
+ keepUpright
+
+ ScreenObjectInstance (new object)
+ location
+ endLoc/duration (moving fields)
+ selectable
+ ScreenObject pointer
+ Selected version ScreenObject pointer
+ uniqueID
+ userObject (for selection)
+ */
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyShader.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyShader.h
new file mode 100644
index 0000000..45e309e
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyShader.h
@@ -0,0 +1,174 @@
+/*
+ * MaplyShader.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 2/7/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+#import <Metal/Metal.h>
+
+@protocol MaplyRenderControllerProtocol;
+@class MaplyTexture;
+
+/**
+ The various types of attributes that can be passed in to shaders.
+ */
+typedef NS_ENUM(NSInteger, MaplyShaderAttrType){
+ MaplyShaderAttrTypeInt,
+ MaplyShaderAttrTypeFloat,
+ MaplyShaderAttrTypeFloat2,
+ MaplyShaderAttrTypeFloat3,
+ MaplyShaderAttrTypeFloat4
+};
+
+/**
+ The shader is a direct interface to OpenGL ES 2.0 shader language.
+
+ You can set your own shader programs in the toolkit! Yeah, that's as complex as it sounds.
+
+ The underyling toolkit makes a distinction between the name of the shader and the scene name. The scene name is used as a way to replace the default shaders we use for triangles and lines. This would let you replace the shaders you're already using with your own. See the addShaderProgram: method in the MaplyBaseViewController.
+
+ You can also add your own shader and hook it up to any features that can call out a specific shader, such as the MaplyQuadImageTilesLayer.
+
+ When writing a new shader, go take a look at DefaultShaderPrograms.mm, particularly the vertexShaderTri and fragmentShaderTri. The documentation here is for the uniforms and attributes the system is going to hook up for you. All of these are optional, but obviously nothing much will happen if you don't use the vertices.
+
+**Uniform Values**
+
+These are uniform values provided to each shader, if requested.
+
+ |uniform|type|description|
+ |:------|:---|:----------|
+ |u_mvpMatrix|mat4| The model/view/projection matrix. Shaders typically run vertices through this. |
+ |u_mvMatrix|mat4| The model/view matrix. Less comonly used. |
+ |u_mvNormalMatrix|mat4| The model/view matrix for normals. A shader typically uses this when we want view dependent lighting. |
+ |u_fade|float| Available in regular drawables, but not yet in big drawables (e.g. atlases). This is intended to fade geometry in and out over time. |
+ |u_interp|float| If we're doing multiple textures, this is how to interpolate them. |
+ |u_numLights|int| The number of active lights to use. |
+ |light[8]|directional_light| A data structure for each active light. See the table below. |
+ |material|material_properties| Material information used to calculate lighting. See the table below. |
+ |u_hasTexture|bool| True if there's a texture available to fetch data from. |
+ |s_baseMapX|sampler2D| s_baseMap0, s_baseMap1 and so forth are references to texture data. |
+
+**Material properties**
+
+These are the fields for the material properties.
+
+|field|type|description|
+|:----|:---|:----------|
+|ambient|vec4| The ambient value for the material. Shaders typically multiply by this value when calculating ambient lighting. |
+|diffuse|vec4| The diffuse value for the material. Shaders typically multiply by this value when calculating diffuse lighting. |
+|specular|vec4| Not currently used. |
+|specular_exponent|float| Not currently used. |
+
+**Light properties**
+
+These are the fields for each individual light.
+
+ |field|type|description|
+ |:----|:---|:----------|
+ |direction|vec3| The light's direction, used in diffuse lighting. |
+ |halfplane|vec3| This would be used in specular lighting. |
+ |ambient|vec4| The ambient value of the light. |
+ |diffuse|vec4| The diffuse value of the light. |
+ |specular|vec4| Not currently used. |
+ |viewdepend|float| If greater than 0.0, the shader should run each normal through the u_mvNormalMatrix. |
+
+**Attributes**
+
+These are the per vertex attributes provided to each vertex shader.
+
+ |field|type|description|
+ |:----|:---|:----------|
+ |a_position|vec3| The position in display space for a vertex. Shaders typically multiply this by u_mvpMatrix. |
+ |a_texCoord0|vec2| If textures are present, this is the texture coordinate for the first one. |
+ |a_texCoord1|vec2| If two textures are present, this is the texture coordinate for the second. |
+ |a_color|vec4| An RGBA color for the vertex. |
+ |a_normal|vec3| A normal in display space. This is used purely for lighting and often run through u_mvNormalMatrix. |
+ |a_elev|float| An optional elevation value provided by the MaplyQuadImageTiles layer. You can use it to do elevation dependent shading. |
+
+ */
+@interface MaplyShader : NSObject
+
+/**
+ Initialize with Metal shader functions tied to a particular view controller. Metal only.
+
+ This initializer just ties the given functions to this MaplyShader. All the real work is
+ done by Metal.
+
+ @param name The name of the shader program. Used for identification and sometimes lookup.
+
+ @param vertexFunc The MTLFunction for vertex processing.
+
+ @param fragFunc The MTLFunction for fragment processing.
+
+ @param baseViewC The view controller where we'll register the new shader.
+
+ @return Returns a shader program if it succeeded. IT may not work, however, so call valid first.
+ */
+- (nullable instancetype)initMetalWithName:(NSString *__nonnull)name vertex:(id<MTLFunction> __nonnull)vertexFunc fragment:(id<MTLFunction> __nullable)fragFunc viewC:(NSObject<MaplyRenderControllerProtocol> *__nonnull)baseViewC;
+
+/**
+ Name of the shader program.
+
+ This is the name passed in to the init call. You can search by this name in some circumstances.
+ */
+@property (nonatomic,strong) NSString * __nullable name;
+
+/**
+ Present a texture to this shader for use. Metal Only.
+
+ For a Metal shader we can pass in zero or more textures starting at WKSTextureEntryLookup (DefaultShadersMTL.h).
+ This index is offset from there. Start at 0.
+ */
+- (void)setTexture:(MaplyTexture * __nonnull)tex forIndex:(int)idx viewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+/**
+ Remove a texture we presented to the Shader ealier. Metal Only.
+
+ The texture itself will not be deleted, just the reference to it in the shader.
+ */
+- (void)removeTexture:(MaplyTexture * __nonnull)tex viewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+/**
+ For Metal shaders we don't set the individual uniform values passed in, we set them all together as a block. These are typically set
+ through the ComponentObject interface, but can be set gobally here.
+
+ Metal Only.
+ */
+- (bool)setUniformBlock:(NSData *__nonnull)uniBlock buffer:(int)bufferID;
+
+/**
+ If set, this program is expecting to be called once for each level of a render target's texture.
+ Essentially, it runs a reduce operation, starting from some source and working its way up to the 1x1 texture at the top.
+ */
+- (void)setReduceMode:(bool)reduceMode;
+
+/**
+ Check if the shader is valid.
+
+ The shader setup can fail in a number of ways. Check this after creating the shader to see if it succeded. If not, look to getError to see why.
+ */
+- (bool)valid;
+
+/**
+ Return the compilation error if there was one.
+
+ Shader construction can fail in a number of interesting ways. Call valid to see if it did fail, and then call this method to see why.
+ */
+- (NSString *__nullable)getError;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyShape.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyShape.h
new file mode 100644
index 0000000..51dc1eb
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyShape.h
@@ -0,0 +1,318 @@
+/*
+ * MaplyShape.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 9/28/12.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyMatrix.h>
+#import <WhirlyGlobe/MaplyTexture.h>
+
+/**
+ Maply Shape is the base class for the actual shape objects.
+
+ The maply shape is just the base class. Look to MaplyShapeCircle, MaplyShapeCylinder, MaplyShapeSphere, MaplyShapeGreatCircle, and MaplyShapeLinear.
+ */
+@interface MaplyShape : NSObject
+
+/**
+ The color of the shape.
+
+ We can set object color in the NSDictionary passed in with the add method. We can also override that here.
+ */
+@property (nonatomic,strong) UIColor * __nullable color;
+
+/**
+ If set, the object is selectable
+
+ The object is selectable if this is set when the object is passed in to an add call. If not set, you'll never see it in selection.
+ */
+@property (nonatomic,assign) bool selectable;
+
+/**
+ User data object for selection
+
+ When the user selects a feature and the developer gets it in their delegate, this is an object they can use to figure out what the shape means to them.
+ */
+@property (nonatomic,strong) id __nullable userObject;
+
+/**
+ If set, this shape is in clip coordinates and will not be transformed.
+
+ Some objects (the rectangle) can be used as overlays in clip coordinates. This is set if that's the case.
+ */
+@property (nonatomic,assign) bool clipCoords;
+
+@end
+
+/**
+ Shows a circle at the given location on the globe or map.
+
+ This object represents a circle at the given geographic location. It needs a radius (in display coordinates) and can optionally have a height above the globe or map.
+ */
+@interface MaplyShapeCircle : MaplyShape
+
+/**
+ Center of the circle in local coordinates.
+
+ This is the center of the circle in geographic.
+ */
+@property (nonatomic,assign) MaplyCoordinate center;
+
+/**
+ Radius of the circle in display units.
+
+ This is the radius of the circle, but not in geographic. It's in display units. Display units for the globe are based on a radius of 1.0. Scale accordingly. For the map, display units typically run from -PI to +PI, depending on the coordinate system.
+ */
+@property (nonatomic,assign) float radius;
+
+/**
+ Offset height above the globe in display units.
+
+ This is the height above the globe for the center of the circle. It's also in display units, like the radius.
+ */
+@property (nonatomic,assign) float height;
+
+@end
+
+typedef MaplyShapeCircle WGShapeCircle;
+
+/**
+ Display a sphere at the given location with the given radius.
+
+ This object represents a sphere at the
+ */
+@interface MaplyShapeSphere : MaplyShape
+
+/**
+ Center of the sphere in local coordinates.
+
+ The x and y coordinates correspond to longitude and latitude and are in geographic (radians). The Z value is in display coordinates. For that globe that's based on a radius of 1.0. Scale accordingly.
+ */
+@property (nonatomic,assign) MaplyCoordinate center;
+
+/**
+ Radius of the sphere in display units.
+
+ This is the radius of the sphere, but not in geographic. It's in display units. Display units for the globe are based on a radius of 1.0. Scale accordingly. For the map, display units typically run from -PI to +PI, depending on the coordinate system.
+ */
+@property (nonatomic,assign) float radius;
+
+/**
+ Offset height above the globe in display units.
+
+ This is the height above the globe for the center of the sphere. It's also in display units, like the radius.
+ */
+@property (nonatomic,assign) float height;
+
+@end
+
+typedef MaplyShapeSphere WGShapeSphere;
+
+/**
+ Represent a cyclinder on the globe or map.
+
+ This object represents a cylinder with it's base tied to the surface of the globe or map and it's top pointed outward (on the globe anyway). The base can be offset and the overall radius and height are adjustable.
+ */
+@interface MaplyShapeCylinder : MaplyShape
+
+/**
+ Center of the cylinder's base in geographic.
+
+ The x and y coordinates correspond to longitude and latitude and are in geographic (radians).
+ */
+@property (nonatomic,assign) MaplyCoordinate baseCenter;
+
+/**
+ Base height above the globe in display units.
+
+ This is an optional base offset from the globe or map. The cylinder will be offset by this amount. It's also in display units, like the radius.
+ */
+@property (nonatomic,assign) float baseHeight;
+
+/**
+ Radius of the cylinder in display units.
+
+ This is the radius of the cylinder, but not in geographic. It's in display units. Display units for the globe are based on a radius of 1.0. Scale accordingly. For the map, display units typically run from -PI to +PI, depending on the coordinate system.
+ */
+@property (nonatomic,assign) float radius;
+
+/**
+ Height of the cylinder in display units.
+
+ This is the height of the cylinder. The top of the cylinder will be at baseHeight+height. It's also in display units, like the radius.
+ */
+@property (nonatomic,assign) float height;
+
+@end
+
+typedef MaplyShapeCylinder WGShapeCylinder;
+
+/**
+ Represents an great circle or great circle with height.
+
+ Great circles are the shortest distance between two points on a globe. We extend that a bit here, by adding height. The result is a curved object that can either sit on top of the globe or rise above it. In either case it begins and ends at the specified points on the globe.
+ */
+@interface MaplyShapeGreatCircle : MaplyShape
+
+/// Starting point in geographic coordinates.
+@property (nonatomic,assign) MaplyCoordinate startPt;
+
+/// End point in geographic coordinates
+@property (nonatomic,assign) MaplyCoordinate endPt;
+
+/**
+ Height of the great circle shape right in its middle.
+
+ This is the height of the great circle right in the middle. It will built toward that height and then go back down as it reaches the endPt. The height is in display units. For the globe that's based on a radius of 1.0.
+ */
+@property (nonatomic,assign) float height;
+
+/**
+ Line width for the great circle geometry.
+
+ The great circle is implemented as a set of lines. This is the width, in pixels, of those lines.
+ */
+@property (nonatomic,assign) float lineWidth;
+
+/**
+ Angle between start and end points in radians
+ */
+- (float)calcAngleBetween;
+
+@end
+
+/**
+ Represents a simple rectangle in 3D.
+
+ The rectangle is a 2D object in 3D. Specify the lower left and upper right coordinates as
+ well as an optional texture.
+ */
+@interface MaplyShapeRectangle : MaplyShape
+
+/// Lower left corner in 3D
+@property (nonatomic,assign) MaplyCoordinate3dD ll;
+
+/// Upper right corner in 3D
+@property (nonatomic,assign) MaplyCoordinate3dD ur;
+
+/// If set, the textures to stretch across the rectangle.
+@property (nonatomic,nullable,strong) NSMutableArray *textures;
+
+/// Add a texture to stretch across the rectangle
+- (void)addTexture:(MaplyTexture * __nonnull)texture;
+
+@end
+
+/**
+ A linear feature offset from the globe.
+
+ The main difference between this object and a regular MaplyVectorObject is that you specify coordiantes in 3D. You can use this to create linear features that are offset from the globe.
+ */
+@interface MaplyShapeLinear : MaplyShape
+
+/**
+ Line width in pixels
+
+ The linear is implemented as a set of line segments in OpenGL ES. This is their line width in pixels.
+ */
+@property (nonatomic,assign) float lineWidth;
+
+/**
+ Initialize with coordinates and coordinate array size
+
+ This initializer will make a copy of the coordinates and use them to draw the lines. The x and y values are in geographic. The z values are offsets from the globe (or map) and are in display units. For the globe display units are based on a radius of 1.0.
+ */
+- (nullable instancetype)initWithCoords:(MaplyCoordinate3d * __nonnull)coords numCoords:(int)numCoords;
+
+/**
+ Return the coordinates for this linear feature.
+
+ @return Returns the number of coordinates and a pointer to the coordinate array.
+ */
+- (int)getCoords:(MaplyCoordinate3d *__nullable *__nonnull)retCoords;
+
+@end
+
+/**
+ An extruded shape with an arbitrary outline.
+
+ This object represents an extruded shape with the given thickness. It can be oriented according to the pitch, roll, yaw and height.
+ */
+@interface MaplyShapeExtruded : MaplyShape
+
+/**
+ Construct with the coordinates for the outline to extrude.
+
+ Pass in pairs of doubles that correspond to the
+ */
+- (nonnull instancetype)initWithOutline:(NSArray * __nonnull)coords;
+
+/**
+ Construct with the coordinates for the outline to extrude.
+
+ Pass in pairs of doubles that correspond to the
+ */
+- (nonnull instancetype)initWithOutline:(double * __nonnull)coords numCoordPairs:(int)numCoordPairs;
+
+/**
+ Number of coordinate pairs in this shape.
+ */
+@property (nonatomic,readonly) int numCoordPairs;
+
+/**
+ Array of coordinate values.
+ */
+@property (nonatomic,readonly) double * __nullable coordData;
+
+/**
+ Where we'd like to place the extruded shape.
+
+ This is the center of the object in geographic radians.
+ */
+@property (nonatomic) MaplyCoordinate center;
+
+/**
+ Scale for coordinates. Set to 1/EarthRadiusInMeters by default.
+
+ The coordinates will be scaled by this before creating the geometry. By default this is set to 1/EarthRadius(m) so you can build your shape in meters. Also applies to thickness and height.
+ */
+@property (nonatomic,assign) double scale;
+
+/**
+ Thickness for the resulting shape.
+
+ We build an extruded shape out of this information and this is its thickness. If this is zero, you just get a double sided polygon.
+ */
+@property (nonatomic,assign) double thickness;
+
+/**
+ Height to place the resulting shape at.
+
+ We'll put this shape at the given height above the surface of the globe or map.
+ */
+@property (nonatomic,assign) double height;
+
+/**
+ The transform to apply to this shape.
+
+ If set, this transform is applied before placing the feature. You can set a transform matrix up with roll, pitch, and yaw.
+ */
+@property (nonatomic,strong) MaplyMatrix * __nullable transform;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplySharedAttributes.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplySharedAttributes.h
new file mode 100644
index 0000000..00bd24d
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplySharedAttributes.h
@@ -0,0 +1,406 @@
+/*
+ * MaplySharedAttributes.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 9/19/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+/// Use this hint to turn the zbuffer on or off. Pass in an NSNumber boolean. Takes effect on the next frame.
+extern NSString* const kMaplyRenderHintZBuffer;
+#define kWGRenderHintZBuffer kMaplyRenderHintZBuffer
+/// Use this hint to turn culling optimization on or off. Pass in an NSNumber boolean.
+extern NSString* const kMaplyRenderHintCulling;
+#define kWGRenderHintCulling kMaplyRenderHintCulling
+/// These are options for lighting modes, basically different default shader programs. Only works with OpenGL ES 2.0 mode.
+/// Accepted values are: none,regular
+extern NSString* const kMaplyRendererLightingMode;
+#define kWGRendererLightingMode kMaplyRendererLightingMode
+
+/// These are used for all object descriptions.
+
+/// If the z buffer is on, this will let you resolve. Takes an NSNumber boolean
+extern NSString* const kMaplyDrawOffset;
+#define kWGDrawOffset kMaplyDrawOffset
+/// This helps decide what order things are drawn in. Useful when the z buffer is off or you're using transparency.
+/// Takes an NSNumber int.
+extern NSString* const kMaplyDrawPriority;
+#define kWGDrawPriority kMaplyDrawPriority
+/// Minimum point at which a feature is visible. Takes an NSNumber float. The radius of the globe is 1.0
+extern NSString* const kMaplyMinVis;
+#define kWGMinVis kMaplyMinVis
+/// Maximum point at which a feature is visible. Takes an NSNumber float. The radius of the globe is 1.0
+extern NSString* const kMaplyMaxVis;
+#define kWGMaxVis kMaplyMaxVis
+/// Minimum distance from the viewer at which to display geometry.
+extern NSString* const kMaplyViewerMinDist;
+/// Maximum distance from the viewer at which to display geometry.
+extern NSString* const kMaplyViewerMaxDist;
+/// Center to use when evaluating distance to viewable geometry (X)
+extern NSString* const kMaplyViewableCenterX;
+/// Center to use when evaluating distance to viewable geometry (Y)
+extern NSString* const kMaplyViewableCenterY;
+/// Center to use when evaluating distance to viewable geometry (Z)
+extern NSString* const kMaplyViewableCenterZ;
+/// The amount of time for a feature to fade in or out. Takes an NSNumber float for seconds.
+extern NSString* const kMaplyFade;
+#define kWGFade kMaplyFade
+/// Fade the feature in over time.
+extern NSString* const kMaplyFadeIn;
+/// Fade the feature out over time
+extern NSString* const kMaplyFadeOut;
+/// When to start fading out
+extern NSString* const kMaplyFadeOutTime;
+/// Enable or disable an object. This can be used to create an object disabled.
+extern NSString* const kMaplyEnable;
+/// If set, we'll enable the objects only between the start and end time
+extern NSString* const kMaplyEnableStart;
+/// If set, we'll enable the objects only between the start and end time
+extern NSString* const kMaplyEnableEnd;
+/// Request a given object take the z buffer into account
+extern NSString* const kMaplyZBufferRead;
+/// Have a given object write itself to the z buffer
+extern NSString* const kMaplyZBufferWrite;
+/// Set the render target if the given geometry type supports it
+extern NSString* const kMaplyRenderTarget;
+/// The the UUID of the object
+extern NSString* const kMaplyUUID;
+/// The representation of the UUID this object embodies
+extern NSString* const kMaplyRepresentation;
+
+/// Assign a shader program to a particular feature. Use the shader program's name
+extern NSString* const kMaplyShader;
+/// An NSDictionary containing uniforms to apply to a shader before drawing
+extern NSString* const kMaplyShaderUniforms;
+
+/// Keep drawing for this number of frames after we'd normally stop
+extern NSString* const kMaplyExtraFrames;
+
+/// Stars, moon, stars, atmosphere
+extern const int kMaplyStarsDrawPriorityDefault;
+extern const int kMaplySunDrawPriorityDefault;
+extern const int kMaplyMoonDrawPriorityDefault;
+extern const int kMaplyAtmosphereDrawPriorityDefault;
+/// Where we start image layer draw priorities
+extern const int kMaplyImageLayerDrawPriorityDefault;
+/// We'll start filling in features right around here
+extern const int kMaplyFeatureDrawPriorityBase;
+extern const int kMaplyStickerDrawPriorityDefault;
+extern const int kMaplyMarkerDrawPriorityDefault;
+extern const int kMaplyVectorDrawPriorityDefault;
+extern const int kMaplyParticleSystemDrawPriorityDefault ;
+extern const int kMaplyLabelDrawPriorityDefault;
+extern const int kMaplyLoftedPolysDrawPriorityDefault;
+extern const int kMaplyShapeDrawPriorityDefault;
+extern const int kMaplyBillboardDrawPriorityDefault;
+extern const int kMaplyModelDrawPriorityDefault;
+extern const int kMaplyMaxDrawPriorityDefault;
+
+#define kWGMarkerDrawPriorityDefault kMaplyMarkerDrawPriorityDefault
+#define kWGVectorDrawPriorityDefault kMaplyVectorDrawPriorityDefault
+#define kWGStickerDrawPriorityDefault kMaplyStickerDrawPriorityDefault
+
+/// These are used just for the screen and regular labels
+
+/// Color of the text being rendered. Takes a UIColor.
+extern NSString* const kMaplyTextColor;
+#define kWGTextColor kMaplyTextColor
+/// Background color for the text. Takes a UIColor.
+extern NSString* const kMaplyBackgroundColor;
+#define kWGBackgroundColor kMaplyBackgroundColor
+/// Font to use in rendering text. Takes a UIFont.
+extern NSString* const kMaplyFont;
+#define kWGFont kMaplyFont
+/// Default height of the text. If for screen space, this in points. If for 3D, remember that
+// the radius of the globe is 1.0. Expects an NSNumber float.
+extern NSString* const kMaplyLabelHeight;
+#define kWGLabelHeight kMaplyLabelHeight
+/// Default width of the text. See height for more info and, in general, use height instead.
+extern NSString* const kMaplyLabelWidth;
+#define kWGLabelWidth kMaplyLabelWidth
+/// Justification for label placement. This takes an NSString with one of:
+/// middle, left, right
+extern NSString* const kMaplyJustify;
+#define kWGJustify kMaplyJustify
+/// If set, we'll draw a shadow behind each label with this as the stroke size
+extern NSString* const kMaplyShadowSize;
+#define kWGShadowSize kMaplyShadowSize
+/// If shadow size is being used, we can control the shadow color like so
+extern NSString* const kMaplyShadowColor;
+#define kWGShadowColor kMaplyShadowColor
+/// If outline is being used, we can control the color
+extern NSString* const kMaplyTextOutlineSize;
+/// Vertical line spacing. Defaults to the Font's line spacing
+extern NSString* const kMaplyTextLineSpacing;
+/// If outline is being used, we can control the stroke size
+extern NSString* const kMaplyTextOutlineColor;
+/// When creating textures, we may pass in the size
+extern NSString* const kMaplyTexSizeX;
+/// When creating textures, we may pass in the size
+extern NSString* const kMaplyTexSizeY;
+
+/// How to justify multi-line text
+extern NSString* const kMaplyTextJustify;
+/// Justify text to the right
+extern NSString* const kMaplyTextJustifyRight;
+/// Justify text to the left
+extern NSString* const kMaplyTextJustifyLeft;
+/// Justify text to the center
+extern NSString* const kMaplyTextJustifyCenter;
+
+/// Controls how text is laid out along a line or polygon. Set a number (- for left or inside, + for right or outside)
+extern NSString* const kMaplyTextLayoutOffset;
+/// If laying out along a line (or polygon), the amount of screen space to leave between labels
+extern NSString* const kMaplyTextLayoutSpacing;
+/// Layout as many labels as possible along a line (or polygon). Set a number (0 for no repeat, -1 for as many as possible, or a number of instances)
+extern NSString* const kMaplyTextLayoutRepeat;
+/// Turn on debugging lines for the layout engine
+extern NSString* const kMaplyTextLayoutDebug;
+
+/// These are used for screen and regular markers.
+extern NSString* const kMaplyClusterGroup;
+
+/// Color is used for the polygon generated for a marker. It will combine with the image,
+/// if there is one or it will be visible if there is no texture. Takes a UIColor
+extern NSString* const kMaplyColor;
+#define kWGColor kMaplyColor
+
+/// Width is used by the vector layer for line widths
+extern NSString* const kMaplyVecWidth;
+#define kWGVecWidth kMaplyVecWidth
+
+/// If filled is set, we draw the areals as filled polygons
+extern NSString* const kMaplyFilled;
+#define kWGFilled kMaplyFilled
+
+/// If set, the texture to apply to the feature
+extern NSString* const kMaplyVecTexture;
+/// The format of the image given by kMaplyVecTexture, default MaplyImage4Layer8Bit
+extern NSString* const kMaplyVecTextureFormat;
+/// X scale for textures applied to vectors
+extern NSString* const kMaplyVecTexScaleX;
+/// Y scale for textures applied to vectors
+extern NSString* const kMaplyVecTexScaleY;
+
+/// The projection to use when generating texture coordinates
+extern NSString* const kMaplyVecTextureProjection;
+/// Tangent plane projection for texture coordinates
+extern NSString* const kMaplyProjectionTangentPlane;
+/// Screen space "projection" for texture coordinates
+extern NSString* const kMaplyProjectionScreen;
+/// No projection for texture coordinates
+extern NSString* const kMaplyProjectionNone;
+
+/// If set to true we'll centered any drawables we create for features
+/// This fixes the jittering problem when zoomed in close
+extern NSString* const kMaplyVecCentered;
+
+/// Center of the feature, to use for texture calculations
+extern NSString* const kMaplyVecCenterX;
+extern NSString* const kMaplyVecCenterY;
+
+/// For wide vectors, we can widen them in screen space or display space
+extern NSString* const kMaplyWideVecCoordType;
+
+/// Widened vectors are widened in real space. The width is in meters.
+extern NSString* const kMaplyWideVecCoordTypeReal;
+/// Widened vectors are widened in screen space. The width is in pixels.
+extern NSString* const kMaplyWideVecCoordTypeScreen;
+
+/// Controls the wide vector implementation. Basic implementation by default.
+extern NSString* const kMaplyWideVecImpl;
+
+/// Default/old implementation of the wide vectors
+extern NSString* const kMaplyWideVecImplDefault;
+
+/// Performance implementation of the wide vectors
+extern NSString* const kMaplyWideVecImplPerf;
+
+/// For wide vectors we can control the line joins
+/// See: http://www.w3.org/TR/SVG/painting.html#StrokeLinejoinProperty
+extern NSString* const kMaplyWideVecJoinType;
+
+/// Widened vectors are joined with miters
+extern NSString* const kMaplyWideVecMiterJoin;
+// Note: Not yet implemented
+/// Widened vectors are joined with a curve
+//extern NSString* const kMaplyWideVecRoundJoin @"round"
+/// Widened vectors are joined with a bevel
+extern NSString* const kMaplyWideVecBevelJoin;
+
+/// Number of pixels to use in blending the edges of the wide vectors
+extern NSString* const kMaplyWideVecEdgeFalloff;
+
+/// For wide vectors we can control the ends
+/// See: http://www.w3.org/TR/SVG/painting.html#StrokeLinecapProperty
+//extern NSString* const kMaplyWideVecLineCapType @"wideveclinecaptype"
+
+// Note: These are not currently implemented
+
+/// Widened vector ends are flush
+//extern NSString* const kMaplyWideVecButtCap;
+/// Widened vector ends are round (e.g. hot dog roads)
+//extern NSString* const kMaplyWideVecRoundCap;
+/// Widened vector ends are extended a bit and then flush
+//extern NSString* const kMaplyWideVecSquareCap;
+
+/// Miter joins will turn to bevel joins past this number of degrees
+extern NSString* const kMaplyWideVecMiterLimit;
+
+/// This is the length you'd like the texture to start repeating after.
+/// It's real world coordinates for kMaplyWideVecCoordTypeReal and pixel size for kMaplyWideVecCoordTypeScreen
+extern NSString* const kMaplyWideVecTexRepeatLen;
+
+/// Offset to left (negative) or right (positive) of the centerline
+extern NSString* const kMaplyWideVecOffset;
+
+/// Close any un-closed areal features when drawing lines for them
+extern NSString* const kMaplyVecCloseAreals;
+
+/// If set we'll break up a vector feature to the given epsilon on a globe surface
+extern NSString* const kMaplySubdivEpsilon;
+/// If subdiv epsilon is set we'll look for a subdivision type. Default is simple.
+extern NSString* const kMaplySubdivType;
+/// Subdivide the vector edges along a great circle
+extern NSString* const kMaplySubdivGreatCircle;
+/// Subdivide the vector edges along a great circle with ellipsoidal math
+extern NSString* const kMaplySubdivGreatCirclePrecise;
+/// Subdivide into a fixed number of segmenets
+extern NSString* const kMaplySubdivStatic;
+/// Subdivide the vectors edges along lat/lon
+extern NSString* const kMaplySubdivSimple;
+/// Clip features along a grid of the given size
+extern NSString* const kMaplySubdivGrid;
+/// Used to turn off selection in vectors
+extern NSString* const kMaplySelectable;
+
+/// These are used for stickers
+
+/// Sampling size along one dimension
+extern NSString* const kMaplySampleX;
+#define kWGSampleX kMaplySampleX
+/// Sampling size along one dimension
+extern NSString* const kMaplySampleY;
+#define kWGSampleY kMaplySampleY
+/// Images to use when changing a sticker
+extern NSString* const kMaplyStickerImages;
+/// Image format to use for the new images
+extern NSString* const kMaplyStickerImageFormat;
+
+/// These are used for billboards
+
+/// Billboard orientation
+extern NSString* const kMaplyBillboardOrient;
+/// Billboards are oriented toward the eye, but rotate on the ground
+extern NSString* const kMaplyBillboardOrientGround;
+/// Billboards are oriented only towards the eye
+extern NSString* const kMaplyBillboardOrientEye;
+
+/// These are used for lofted polygons
+
+/// Height above the ground
+extern NSString* const kMaplyLoftedPolyHeight;
+/// Boolean that turns on/off top (on by default)
+extern NSString* const kMaplyLoftedPolyTop;
+/// Boolean that turns on/off sides (on by default)
+extern NSString* const kMaplyLoftedPolySide;
+/// If present, we'll start the lofted poly above 0 height
+extern NSString* const kMaplyLoftedPolyBase;
+/// Grid size we used to chop the lofted polygons up (10 degress by default)
+extern NSString* const kMaplyLoftedPolyGridSize;
+/// If set to @(YES) this will draw an outline around the top of the lofted poly in lines
+extern NSString* const kMaplyLoftedPolyOutline;
+/// If set to @(YES) this will draw an outline around the bottom of the lofted poly in lines
+extern NSString* const kMaplyLoftedPolyOutlineBottom;
+/// If the outline is one this is the outline's color
+extern NSString* const kMaplyLoftedPolyOutlineColor;
+/// This is the outline's width if it's turned on
+extern NSString* const kMaplyLoftedPolyOutlineWidth;
+/// Draw priority of the lines created for the lofted poly outline
+extern NSString* const kMaplyLoftedPolyOutlineDrawPriority;
+/// If set and we're drawing an outline, this will create lines up the sides
+extern NSString* const kMaplyLoftedPolyOutlineSide;
+
+/// These are used for shapes
+
+/// Samples (x) to use when converting shape to polygons
+extern NSString* const kMaplyShapeSampleX;
+/// Samples (y) to use when converting shape to polygons
+extern NSString* const kMaplyShapeSampleY;
+/// If set to true, we'll tessellate a shape using the opposite vertex ordering
+extern NSString* const kMaplyShapeInsideOut;
+/// Center for the shape geometry
+extern NSString* const kMaplyShapeCenterX;
+extern NSString* const kMaplyShapeCenterY;
+extern NSString* const kMaplyShapeCenterZ;
+
+/// These are used by active vector objects
+extern NSString* const kMaplyVecHeight;
+extern NSString* const kMaplyVecMinSample;
+
+/// These are used by the particle systems
+extern NSString* const kMaplyPointSize;
+extern const float kMaplyPointSizeDefault;
+
+/// These are used by the texture
+extern NSString* const kMaplyTexFormat;
+extern NSString* const kMaplyTexMinFilter;
+extern NSString* const kMaplyTexMagFilter;
+extern NSString* const kMaplyMinFilterNearest;
+extern NSString* const kMaplyMinFilterLinear;
+extern NSString* const kMaplyTexAtlas;
+extern NSString* const kMaplyTexWrapX;
+extern NSString* const kMaplyTexWrapY;
+extern NSString* const kMaplyTexMipmap;
+
+/// These are the various shader programs we set up by default
+extern NSString* const kMaplyShaderDefaultTri;
+extern NSString* const kMaplyDefaultTriangleShader;
+extern NSString* const kMaplyShaderTriExp;
+
+extern NSString* const kMaplyShaderDefaultModelTri;
+
+extern NSString* const kMaplyShaderDefaultTriNoLighting;
+extern NSString* const kMaplyNoLightTriangleShader;
+extern NSString* const kMaplyShaderNoLightTriangleExp;
+extern NSString* const kMaplyShaderDefaultMarker;
+
+extern NSString* const kMaplyShaderDefaultTriScreenTex;
+
+extern NSString* const kMaplyShaderDefaultTriMultiTex;
+extern NSString* const kMaplyShaderDefaultTriMultiTexRamp;
+extern NSString* const kMaplyShaderDefaultTriNightDay;
+
+extern NSString* const kMaplyShaderDefaultLine;
+extern NSString* const kMaplyDefaultLineShader;
+
+extern NSString* const kMaplyShaderDefaultLineNoBackface;
+extern NSString* const kMaplyNoBackfaceLineShader;
+
+extern NSString* const kMaplyShaderBillboardGround;
+extern NSString* const kMaplyShaderBillboardEye;
+
+extern NSString* const kMaplyShaderDefaultWideVector;
+extern NSString* const kMaplyShaderWideVectorPerformance;
+extern NSString* const kMaplyShaderWideVectorExp;
+
+extern NSString* const kMaplyScreenSpaceDefaultMotionProgram;
+extern NSString* const kMaplyScreenSpaceDefaultProgram;
+extern NSString* const kMaplyScreenSpaceMaskProgram;
+extern NSString* const kMaplyScreenSpaceExpProgram;
+
+extern NSString* const kMaplyShaderParticleSystemPointDefault;
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplySimpleTileFetcher.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplySimpleTileFetcher.h
new file mode 100644
index 0000000..78307c2
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplySimpleTileFetcher.h
@@ -0,0 +1,88 @@
+/*
+ * MaplySimpleTileFetcher.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 5/31/19.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+
+/** Simple Tile Fetcher is meant for sub classing.
+
+ Some data sources aren't all that complex. You read from a local source,
+ you return the data. Something else turns it into visible objects. Simple.
+
+ To implement one of those, subclass the Simple Tile Fetcher and let it do the
+ tricky bits.
+ */
+@interface MaplySimpleTileFetcher : NSObject<MaplyTileFetcher>
+
+/// Your Subclass must call this init method
+- (nullable instancetype)initWithName:(NSString * __nonnull)name minZoom:(int)minZoom maxZoom:(int)maxZoom;
+
+/// The quad paging loader variants need a TileInfo object, even if it's very simple
+- (nullable NSObject<MaplyTileInfoNew> *)tileInfo;
+
+/// Dispatch queue the data fetcher is doing its work on
+@property (nonnull) dispatch_queue_t queue;
+
+/// Set by default. We won't every return an error on failing to load. Useful for sparse data sets
+@property bool neverFail;
+
+/// Name used for debugging
+@property NSString * __nonnull name;
+
+/// Min zoom level
+- (int)minZoom;
+
+/// Max zoom level
+- (int)maxZoom;
+
+/** Override dataForTile:tileID: to return your own data for a given tile.
+ The fetchInfo can be a custom object (if you set it up that way) or
+ you can just use the tileID argument.
+
+ You'll be called on the dispatch queue.
+
+ You can return either an NSData or a MaplyLoaderReturn
+ */
+- (id __nullable)dataForTile:(id __nonnull)fetchInfo tileID:(MaplyTileID)tileID;
+
+/** Override the shutdown method.
+
+ Call the superclass shutdown method *first* and then run your own shutdown.
+ */
+- (void)shutdown;
+
+@end
+
+// Internal object used by the QuadImageLoader to generate tile load info
+@interface MaplySimpleTileInfo : NSObject<MaplyTileInfoNew>
+
+// Initialize with a min/max zoom
+- (instancetype __nonnull)initWithMinZoom:(int)inMinZoom maxZoom:(int)inMaxZoom;
+
+@end
+
+
+// Encapsulates a single tile load request
+@interface MaplySimpleTileFetchInfo : NSObject
+
+@property (nonatomic,assign) int x;
+@property (nonatomic,assign) int y;
+@property (nonatomic,assign) int level;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyStarsModel.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyStarsModel.h
new file mode 100644
index 0000000..0cbf7aa
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyStarsModel.h
@@ -0,0 +1,59 @@
+/* MaplyStarsModel.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 6/4/15.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyComponentObject.h>
+#import <WhirlyGlobe/WhirlyGlobeViewController.h>
+
+/**
+ The Stars Model parses and then displays a star field.
+
+ This is used to display a star field around the earth.
+ */
+@interface MaplyStarsModel : NSObject
+
+/// Read stars from the given file
+- (nullable instancetype)initWithFileName:(NSString *__nonnull)fileName;
+
+/// Use the given image for each point.
+/// The given image will be sampled for individual points.
+- (void)setImage:(UIImage *__nonnull)image;
+
+/**
+ Add stars to the given view controller
+
+ Turn the star positions into geometry to display. This object will track the resulting geometry objects.
+
+ @param viewC The view controller to add the start geometry to.
+
+ @param date The date for the
+
+ @param desc Additional parameters that may related to the geometry.
+
+ @param mode Thread mode to use when adding the geometry.
+ */
+- (bool)addToViewC:(WhirlyGlobeViewController *__nonnull)viewC date:(NSDate *__nonnull)date desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)mode;
+
+/**
+ Remove star geometry from the registered view controller.
+
+ Removes any objects created for the star geometry.
+ */
+- (void)removeFromViewC;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplySticker.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplySticker.h
new file mode 100644
index 0000000..5ccf386
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplySticker.h
@@ -0,0 +1,85 @@
+/*
+ * MaplySticker.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 11/27/12.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+
+/**
+ Stickers are rectangles placed on the globe with an image.
+
+ The Maply Sticker will stretch a rectangle (in geographic) over the given extents and tack the given image on top of it. Stickers differ from MaplyMarker objects in that they're big. They can stretch over a larger are and need to be subdivided as such.
+ */
+@interface MaplySticker : NSObject
+
+/// The lower left corner (in geographic) of the sticker
+@property (nonatomic,assign) MaplyCoordinate ll;
+
+/// The upper right corner (in geographic) of the sticker
+@property (nonatomic,assign) MaplyCoordinate ur;
+
+/// Angle of rotation around center
+@property (nonatomic,assign) float rotation;
+
+/**
+ If present, this is the coordinate system the sticker is represented in.
+
+ By default the coordinates are in geographic. If this is present, the coordinates are in this system.
+ */
+@property (nonatomic,strong) MaplyCoordinateSystem * __nullable coordSys;
+
+/**
+ Image (or MaplyTexture) to stretch over the sticker.
+
+ The UIImage (or MaplyTexture) is cached in the view controller, so multiple references will result in the same texture being used. The view controller also cleans up the images when it's done with it.
+ */
+@property (nonatomic,strong) id __nullable image;
+
+/**
+ Images to stretch over the sticker.
+
+ This is an NSArray of UIImages (or MaplyTextures). The images will be cached in the view controller, so multiple references will result in the same texture being used. The view controller also cleans up the images when it's done with them.
+
+ All the images passed in here will be presented to the shader program, if it has variables for them. It's up to you to do something with them in the shader.
+ */
+@property (nonatomic,strong) NSArray * __nullable images;
+
+/**
+ Set the image format for the created textures.
+
+ OpenGL ES offers us several image formats that are more efficient than 32 bit RGBA, but they're not always appropriate. This property lets you choose one of them. The 16 or 8 bit ones can save a huge amount of space and will work well for some imagery, most maps, and a lot of weather overlays.
+
+ | Image Format | Description |
+ |:-------------|:------------|
+ | MaplyImageIntRGBA | 32 bit RGBA with 8 bits per channel. The default. |
+ | MaplyImageUShort565 | 16 bits with 5/6/5 for RGB and none for A. |
+ | MaplyImageUShort4444 | 16 bits with 4 bits for each channel. |
+ | MaplyImageUShort5551 | 16 bits with 5/5/5 bits for RGB and 1 bit for A. |
+ | MaplyImageUByteRed | 8 bits, where we choose the R and ignore the rest. |
+ | MaplyImageUByteGreen | 8 bits, where we choose the G and ignore the rest. |
+ | MaplyImageUByteBlue | 8 bits, where we choose the B and ignore the rest. |
+ | MaplyImageUByteAlpha | 8 bits, where we choose the A and ignore the rest. |
+ | MaplyImageUByteRGB | 8 bits, where we average RGB for the value. |
+ | MaplyImage4Layer8Bit | 32 bits, four channels of 8 bits each. Just like MaplyImageIntRGBA, but a warning not to do anything too clever in sampling. |
+ */
+@property (nonatomic) MaplyQuadImageFormat imageFormat;
+
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplySun.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplySun.h
new file mode 100644
index 0000000..a7722eb
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplySun.h
@@ -0,0 +1,47 @@
+/* MaplySun.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 6/24/15.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyComponentObject.h>
+#import <WhirlyGlobe/WhirlyGlobeViewController.h>
+#import <WhirlyGlobe/MaplyLight.h>
+
+/**
+ Utility for calculating sun position and shading info.
+
+ This is a utility class that figures out where the sun is at a given date and provides positional information for lighting calculations.
+ */
+@interface MaplySun : NSObject
+
+/**
+ Initialize with a date.
+
+ Initialize with the given date. The sun position will correspond to that.
+ */
+- (nonnull instancetype)initWithDate:(NSDate *__nonnull)date;
+
+/// Return the vector corresponding to the sun location from the earth.
+- (MaplyCoordinate3d)getDirection;
+
+/// Makes up a light that corresponds to the sun's location at a given time
+- (nonnull MaplyLight *)makeLight;
+
+/// Returns the location above the globe in lon/lat. Yay geocentrism!
+- (MaplyCoordinate3d)asPosition;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTapDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTapDelegate.h
new file mode 100644
index 0000000..2acf077
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTapDelegate.h
@@ -0,0 +1,30 @@
+/* MaplyTapDelegate.h
+ * WhirlyGlobeLib
+ *
+ * Created by Steve Gifford on 1/20/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyTapMessage.h>
+
+/** Maply tap gesture delegate responds to a tap
+ by sending out a notification.
+ */
+@interface MaplyTapDelegate : NSObject <UIGestureRecognizerDelegate>
+
+/// Gesture recognizer created for the delegate
+@property (nonatomic,weak) UITapGestureRecognizer *gestureRecognizer;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTapMessage.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTapMessage.h
new file mode 100644
index 0000000..6500e2f
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTapMessage.h
@@ -0,0 +1,35 @@
+/* MaplyTapMessage.h
+ * WhirlyGlobeLib
+ *
+ * Created by Steve Gifford on 9/19/11.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+
+/** Tap Message is an
+ indication that the user tapped on the map.
+ It's passed as the object in a notification.
+ */
+@interface MaplyTapMessage : NSObject
+
+/// View that was touched
+@property (nonatomic,retain) UIView *view;
+//// Touch location on view in 2D
+@property (nonatomic,assign) CGPoint touchLoc;
+/// Where the eye was.
+@property (nonatomic,assign) float heightAboveSurface;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTexture.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTexture.h
new file mode 100644
index 0000000..d9eb9df
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTexture.h
@@ -0,0 +1,31 @@
+/*
+ * MaplyTexture.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 10/25/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+/**
+ Represents an OpenGL texture.
+
+ The MaplyTexture is an opaque object used to track OpenGL ES textures. You create one from the MaplyBaseViewController's addImage call. Then that texture will live until this object is released.
+
+ These can be used in place of UIImages in the various objects (e.g. MaplyScreenMarker).
+ */
+@interface MaplyTexture : NSObject
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTextureBuilder.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTextureBuilder.h
new file mode 100644
index 0000000..74d842c
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTextureBuilder.h
@@ -0,0 +1,47 @@
+/*
+ * MaplyTextureBuilder.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 5/30/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+
+/**
+ The Maply Linear Texture Builder is used to construct linear textures
+ for use on widened vectors.
+
+ Linear textures of this type are used to represent dotted and dashed lines. These may come from Mapnik configuration files or you can just make them up yourself.
+
+ After creating an image with this object, you'll want to pass it as a parameter to the widened vector add method.
+ */
+@interface MaplyLinearTextureBuilder : NSObject
+
+/**
+ Set the pattern of dots and empty spaces.
+
+ This is an array of NSNumbers (treated as integers) that specify how big an element in the given pattern is. The first element is on, the next off and so forth.
+ */
+- (void)setPattern:(NSArray *)elements;
+
+/**
+ Build the image from the size and elements specified.
+
+ If you've set a reasonable size and added a pattern, this will render the pattern into the image and return it. If the size of the image differs from the size of the elements, they will be scaled to the image.
+ */
+- (UIImage *)makeImage;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTileSourceNew.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTileSourceNew.h
new file mode 100644
index 0000000..8c5bcd0
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTileSourceNew.h
@@ -0,0 +1,161 @@
+/*
+ * MaplyTileSourceNew.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 9/13/18.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyImageTile.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+
+/**
+ This represents the indentifier for a unique tile in the pyramid.
+
+ Each tile in an image (or vector tile) pyramid can be uniquely
+ identified by an x, y, and level. The levels start at zero and run to
+ a maximum. x and y also start at zero and run to 2^level-1.
+
+
+ How these are interpreted is up to the tile source itself. For example, some tile sources start at the lower left for (0,0) and run to the upper left. Others do it the opposite way. There's a flipY option in the MaplyQuadImageTileLayer to deal with this, but the system doesn't care all that much as long as you are consistent.
+ @see MaplyTileSource
+ @see MaplyQuadPagingLayer
+ @see MaplyQuadImageTilesLayer
+ */
+typedef struct
+{
+ int x, y, level;
+} MaplyTileID;
+
+/// Convert a MaplyTileID to an NSString
+NSString *__nonnull MaplyTileIDString(MaplyTileID tileID);
+
+/**
+ Tile Info Protocol.
+
+ This describes a single source of data tiles. A uses these to
+ figure out what to load when and where. The loader passes the result of
+ fetchInfoForTile to a MaplyTileFetcher to get the data it wants.
+ */
+@protocol MaplyTileInfoNew<NSObject>
+
+/**
+ The minimum zoom level available.
+
+ This is the lowest level we'll try to fetch. Any levels below that will be filled in with placeholders. Those are empty, but they allow us to load tiles beneath.
+ */
+- (int)minZoom;
+
+/**
+ The maximum zoom level available.
+
+ This is the highest level (e.g. largest) that we'll
+ fetch for a given pyramid tile source. The source can sparse,
+ so you are not required to have these tiles available, but this
+ is as high as the loader will fetch.
+ */
+- (int)maxZoom;
+
+/**
+ FetchInfo object for a given tile.
+
+ The FetchInfo object is specific to the type of TileFetcher you're using and
+ tells the fetcher how to get the data you wawnt.
+ RemoteTileFetchers want a RemoteTileInfoNew object.
+ */
+- (id __nullable)fetchInfoForTile:(MaplyTileID)tileID flipY:(bool)flipY;
+
+@end
+
+/**
+ A tile source that just returns nil. You can use this like a tile source where you need one that doesn't do anything.
+ */
+@interface MaplyTileInfoNone : NSObject<MaplyTileInfoNew>
+@end
+
+
+
+/**
+ Generic Tile fetcher request.
+
+ A single request for a single tile of data from a single source.
+ The tile fetcher will... fetch this and call the success or failure callback.
+ */
+@interface MaplyTileFetchRequest : NSObject
+
+/// Priority before importance. Less is more important.
+@property (nonatomic) int priority;
+/// How important this is to us. Probably screen space.
+@property (nonatomic) float importance;
+/// If all other values are equal, sort by this.
+/// It keeps requests we're waiting for grouped together
+@property (nonatomic) int group;
+
+/// Tile ID for this tile
+@property (nonatomic,assign) MaplyTileID tileID;
+
+/// An object representing the tile source. Used for sorting. Not accessed by the fetcher.
+@property (nonatomic,weak,nullable) id tileSource;
+
+/** This is requested from a TileInfo object by a loader and then passed
+ along to the TileFetcher. TileFetchers expect certain objects.
+ The RemoteTileFetcher wants a RemoteFetchInfo object and will check.
+ Other fetchers will want other things.
+ */
+@property (nonatomic,nonnull,strong) id fetchInfo;
+
+/**
+ Tile Fetcher success callback.
+
+ Called on a new dispatch queue and won't be marked as loaded until it returns.
+ This is a good way to limit how many things are loading/parsing at the same time.
+ */
+@property (nonatomic,nullable) void (^success)(MaplyTileFetchRequest * __nonnull,id __nonnull);
+
+/**
+ Tile Fetcher failure callback.
+ */
+@property (nonatomic,nullable) void (^failure)(MaplyTileFetchRequest * __nonnull,NSError * __nonnull);
+
+@end
+
+/**
+ Tile Fetcher protocol.
+
+ The tile fetcher interacts with loaders that want tiles, as demanded by samplers.
+ A given data source (e.g. remote URL, MBTiles) needs one of these to fetch and return data.
+ */
+@protocol MaplyTileFetcher<NSObject>
+
+/// Add a whole group of requests at once.
+/// This is useful if we want to avoid low priority tiles grabbing the slots first
+- (void)startTileFetches:(NSArray<MaplyTileFetchRequest *> *__nonnull)requests;
+
+/// Update an active request with a new priority and importance
+- (id __nullable)updateTileFetch:(id __nonnull)fetchID priority:(int)priority importance:(double)importance;
+
+/// Name of this tile fetcher. Used for coordinating tile sources.
+- (NSString * __nonnull)name;
+
+/// Cancel a group of requests at once
+/// Use the object returned by the startTileFetch call (which is just a Request object)
+- (void)cancelTileFetches:(NSArray * __nonnull)requestRets;
+
+/// Kill all outstanding connections and clean up
+- (void)shutdown;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTouchCancelAnimationDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTouchCancelAnimationDelegate.h
new file mode 100644
index 0000000..74c1391
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTouchCancelAnimationDelegate.h
@@ -0,0 +1,26 @@
+/* MaplyTouchCancelAnimationDelegate.h
+ * WhirlyGlobeLib
+ *
+ * Created by Jesse Crocker on 7/15/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+
+@interface MaplyTouchCancelAnimationDelegate : NSObject <UIGestureRecognizerDelegate>
+
+/// The gesture recognizer
+@property (nonatomic,strong) UIGestureRecognizer *gestureRecognizer;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTwoFingerTapDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTwoFingerTapDelegate.h
new file mode 100644
index 0000000..0e8fe6e
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyTwoFingerTapDelegate.h
@@ -0,0 +1,25 @@
+/* MaplyTwoFingerTapDelegate.h
+ *
+ * Created by Jesse Crocker on 2/4/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyZoomGestureDelegate.h>
+
+@interface MaplyTwoFingerTapDelegate : MaplyZoomGestureDelegate
+
+// How long we animate from one place to the next
+@property (nonatomic) float animTime;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyUpdateLayer.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyUpdateLayer.h
new file mode 100644
index 0000000..772cea1
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyUpdateLayer.h
@@ -0,0 +1,100 @@
+/*
+ * MaplyUpdateLayer.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 4/13/15.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyComponentObject.h>
+#import <WhirlyGlobe/MaplyControllerLayer.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+
+@class MaplyUpdateLayer;
+
+/**
+ An encapsulation of where the viewer is and what they're looking at.
+
+ This wraps information about where the viewer is currently looking from and at.
+ */
+@interface MaplyViewerState : NSObject
+
+/// Position of the viewer
+- (MaplyCoordinate3d) eyePos;
+
+@end
+
+
+/**
+ The update delegate is called if the viewer moves, but not too often.
+
+ Use this delegate to generate features around the viewer when they move. You can control how far they have to move (in display coordinates) and how often you'll receive updates.
+ */
+@protocol MaplyUpdateDelegate
+
+/**
+ Called when the MaplyUpdateLayer is initialized.
+
+ This is called after things are set up. You'll be on the layer thread here.
+ */
+- (void)start:(MaplyUpdateLayer *__nonnull)layer;
+
+/**
+ Called when the viewer moves.
+
+ You'll be called on the layer thread when the viewer moves more than your moveDist, subject to calls no more frequent than the minTime.
+ */
+- (void)viewerMovedTo:(MaplyViewerState *__nonnull)viewState layer:(MaplyUpdateLayer *__nonnull)layer;
+
+/**
+ Called when the update layer is shutting down.
+
+ Clean up your own data here.
+ */
+- (void)teardown:(MaplyUpdateLayer *__nonnull)layer;
+
+@end
+
+/**
+ This layer will call a delegate as the user moves around, but constrained to distance and time.
+
+ This layer is responsible for calling a delegate you provide as the user moves their viewpoint around. You'll be called if they move from than a certain amount, but not more often than the minimum time.
+ */
+@interface MaplyUpdateLayer : MaplyControllerLayer
+
+/// The minimum distance that will trigger a delegate call. Distance is in display units (radius of the earth = 1.0).
+@property (nonatomic,readonly) double moveDist;
+
+/// The delegate will be called no more often than this amount (in seconds).
+@property (nonatomic,readonly) double minTime;
+
+/// Maximum time to go without getting an update (if things are moving)
+@property (nonatomic) double maxLag;
+
+/**
+ Initalize the update layer with a delegate and parameters.
+
+ @param delegate The delegate that will be called every time the user moves, subject to the values.
+
+ @param moveDist The minimum distance that will trigger a delegate call. Distance is in display units (radius of the earth = 1.0).
+
+ @param minTime The delegate will be called no more often than this amount (in seconds).
+ */
+- (nonnull instancetype)initWithDelegate:(NSObject<MaplyUpdateDelegate> *__nullable)delegate moveDist:(double)moveDist minTime:(double)minTime;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVariableTarget.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVariableTarget.h
new file mode 100644
index 0000000..9259826
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVariableTarget.h
@@ -0,0 +1,88 @@
+/*
+ * MaplyVariableTarget.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 9/18/18.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyTexture.h>
+#import <WhirlyGlobe/MaplyRenderTarget.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+
+/**
+ A variable target manages two pass rendering for one type of variable.
+
+ Set up the variable target
+ */
+@interface MaplyVariableTarget : NSObject
+
+/// Initialize with the variable type and view controller
+- (nonnull instancetype)initWithType:(MaplyQuadImageFormat)type viewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+/// Render target created for this variable target
+@property (nonatomic,readonly,strong,nonnull) MaplyRenderTarget *renderTarget;
+
+/// Scale the screen by this amount for the render target
+- (void)setScale:(double)scale;
+
+/// Color of the rectangle used to draw the render target
+@property (nonatomic,strong,nonnull) UIColor *color;
+
+/// Draw priority of the rectangle we'll use to draw the render target to the screen
+@property (nonatomic,assign) int drawPriority;
+
+/// If set (by default), then we clear out the render target every frame
+@property (nonatomic,assign) bool clearEveryFrame;
+
+/// When we're clearing, use this value. 0 by default
+@property (nonatomic,assign) float clearVal;
+
+/// Shader used to draw the render target to the screen.
+/// Leave this empty and we'll provide our own
+@property (nonatomic,strong,nullable) MaplyShader *shader;
+
+/// By default we'll build a rectangle to display the target
+@property (nonatomic,assign) bool buildRectangle;
+
+/// If set, the rectangle rendered to the screen will read from the z Buffer
+/// Useful, when doing depth comparisons
+@property (nonatomic,assign) bool zBuffer;
+
+/// Rectangle created to show the variable target (if that's set)
+@property (nonatomic,readonly,nullable) MaplyComponentObject *rectObj;
+
+/// Size of the texture in pixels for the render target
+@property (nonatomic,readonly) CGSize texSize;
+
+/// The texture we're rendering to (as part of the render target)
+@property (nonatomic,readonly,strong,nullable) MaplyTexture *renderTex;
+
+/// Passing in another variable target will let us assign that target to the
+/// rectangle used to render this variable target's data. This is used if
+/// you need the contents of more than one target in a shader.
+- (void)addVariableTarget:(MaplyVariableTarget * __nonnull)target;
+
+// Pass this uniform block to the geometry we create for rendering (if it was created)
+- (void)setUniformBlock:(NSData *__nonnull)uniBlock buffer:(int)bufferID;
+
+/// Clear the target for the next frame
+- (void)clear;
+
+/// Stop rendering to the target and release everything
+- (void)shutdown;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorObject.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorObject.h
new file mode 100644
index 0000000..80b2ca4
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorObject.h
@@ -0,0 +1,562 @@
+/* MaplyVectorObject.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 8/2/12.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+
+@class MaplyBaseViewController;
+
+/// Data type for the vector. Multi means it contains multiple types
+typedef NS_ENUM(NSInteger, MaplyVectorObjectType) {
+ MaplyVectorNoneType,
+ MaplyVectorPointType,
+ MaplyVectorLinearType,
+ MaplyVectorLinear3dType,
+ MaplyVectorArealType,
+ MaplyVectorMultiType,
+};
+
+
+/**
+ Maply Vector Object represents zero or more vector features.
+
+ The Vector Object can hold several vector features of the same or different types. It's meant to be a fairly opaque structure, often read from GeoJSON or Shapefiles. It's less opaque than originally planned, however, and sports a number of specific methods.
+
+ If you're doing real vector manipulation, it's best to do it somewhere else and then create one of these as needed for display.
+
+ Vector Objects can be created directly or read from a MaplyVectorDatabase. They are typically then displayed on top of a MaplyViewController or WhirlyGlobeViewController as vectors.
+
+ Vector Objects vertices are always in geographic, with longitude = x and latitude = y.
+ */
+@interface MaplyVectorObject : NSObject
+
+/// Turn this off to make this vector invisible to selection.
+/// On by default.
+@property (nonatomic,assign) bool selectable;
+
+/**
+ Return the attributes for the vector object.
+
+ All vectors should have some set of attribution. If there's more than one vector feature here, we'll return the attributes on the first one.
+
+ The attribution is returned as an NSDictionary and, though you can modify it, you probably shouldn't.
+ */
+@property (nonatomic,readonly) NSMutableDictionary *__nullable attributes;
+
+/**
+ Parse vector data from geoJSON.
+
+ Returns one object to represent the whole thing, which might include multiple different vectors. This version uses the faster JSON parser.
+
+ We assume the geoJSON is all in decimal degrees in WGS84.
+ */
++ (MaplyVectorObject *__nullable)VectorObjectFromGeoJSON:(NSData *__nonnull)geoJSON;
+
+/**
+ Parse vector data from geoJSON.
+
+ Returns one object to represent the whole thing, which might include multiple different vectors. This version uses slower JSON parser.
+
+ We assume the geoJSON is all in decimal degrees in WGS84.
+*/
++ (MaplyVectorObject *__nullable)VectorObjectFromGeoJSONApple:(NSData *__nonnull)geoJSON;
+
+/**
+ Parse vector data from geoJSON.
+
+ Returns one object to represent the whole thing, which might include multiple different vectors. This version parses its data from an NSDictionary, which had to be parsed from JSON at some point. Probably the slower path.
+
+ We assume the geoJSON is all in decimal degrees in WGS84.
+ */
++ (MaplyVectorObject *__nullable)VectorObjectFromGeoJSONDictionary:(NSDictionary *__nonnull)geoJSON;
+
+// Note: Reader turned off
+#if 0
+/**
+ Read vector objects from the given cache file.
+
+ MaplyVectorObject's can be written and read from a binary file. We use this for caching data locally on the device.
+
+ @param fileName Name of the binary vector file.
+
+ @return The vector object(s) read from the file or nil on failure.
+ */
++ (MaplyVectorObject *__nullable)VectorObjectFromFile:(NSString *__nonnull)fileName;
+#endif
+
+/**
+ Read vector objects from the given shapefile.
+
+ This will read all the shapes in the given shapefile into memory and return them as one MaplyVectorObject.
+
+ @param fileName The basename of the shape file. Don't include the extension.
+
+ @return The vector object(s) read from the file or nil on failure.
+ */
++ (MaplyVectorObject *__nullable)VectorObjectFromShapeFile:(NSString *__nonnull)fileName;
+
+/**
+ Parse vector objects from a JSON assembly.
+
+ This version can deal with non-compliant assemblies returned by the experimental OSM server
+ */
++ (NSDictionary *__nullable)VectorObjectsFromGeoJSONAssembly:(NSData *__nonnull)geoJSON;
+
+/**
+ Initialize with a single data point and attribution.
+
+ This version takes a single coordinate and the attributes to go with it.
+ */
+- (nonnull instancetype)initWithPoint:(MaplyCoordinate)coord attributes:(NSDictionary *__nullable)attr;
+
+/**
+ Initialize with a single data point and attribution.
+
+ This version takes a single coordinate and the attributes to go with it.
+ */
+- (nonnull instancetype)initWithPointRef:(const MaplyCoordinate *__nonnull)coord attributes:(NSDictionary *__nullable)attr;
+
+/**
+ Initialize with a linear feature.
+
+ This version takes an array of coordinates (2 `NSNumber`s per coordinate, in degrees) and the attribution.
+ With this it will make a linear feature.
+ Prefer the `inDegrees:` overload to reduce ambiguity.
+ Returns nil if the coordinate array contains an odd number of values.
+ */
+- (nullable instancetype)initWithLineString:(const NSArray<NSNumber*> *__nonnull)coords
+ attributes:(NSDictionary *__nullable)attr;
+
+/**
+ Initialize with a linear feature.
+
+ This version takes an array of coordinate pairs (as NSNumber) and the attribution. With this it will make a linear feature.
+ Returns nil if the coordinate array contains an odd number of values.
+ */
+- (nullable instancetype)initWithLineString:(const NSArray<NSNumber*> *__nonnull)coords
+ attributes:(NSDictionary *__nullable)attr
+ inDegrees:(bool)inDegrees;
+
+/**
+ Initialize with a linear feature.
+
+ This version takes an array of coordinates, the size of that array and the attribution. With this it will make a linear feature.
+ */
+- (nonnull instancetype)initWithLineString:(const MaplyCoordinate *__nonnull)coords
+ numCoords:(int)numCoords
+ attributes:(NSDictionary *__nullable)attr;
+
+/**
+ Inintialize as an areal feature.
+
+ This version takes an array of coordinates, the size of that array and the attribution.
+ With this it will make a single area feature with one (exterior) loop. To add loops, call `addHole:numCoords:`
+ */
+- (nonnull instancetype)initWithAreal:(const MaplyCoordinate *__nonnull)coords
+ numCoords:(int)numCoords
+ attributes:(NSDictionary *__nullable)attr;
+
+/**
+ Inintialize as an areal feature.
+
+ This version takes an array of coordinates (2 `NSNumber`s per coordinate, in radians).
+ With this it will make a single area feature with one (exterior) loop. To add loops, call addHole:numCoords:
+ Prefer the `inDegrees:` overload to reduce ambiguity.
+ Returns nil if the coordinate array contains an odd number of values.
+*/
+- (nullable instancetype)initWithArealArray:(const NSArray<NSNumber *> *__nonnull)coords
+ attributes:(NSDictionary *__nullable)attr;
+
+/**
+ Inintialize as an areal feature.
+
+ This version takes an array of coordinates (2 `NSNumber`s per coordinate, in radians).
+ With this it will make a single area feature with one (exterior) loop. To add loops, call `addHole:numCoords:`
+ Returns nil if the coordinate array contains an odd number of values.
+*/
+- (nullable instancetype)initWithArealArray:(const NSArray<NSNumber *> *__nonnull)coords
+ attributes:(NSDictionary *__nullable)attr
+ inDegrees:(bool)inDegrees;
+
+/**
+ Initializes with vectors parsed from geoJSON.
+
+ Returns one object to represent the whole thing, which might include multiple different vectors. This version uses the faster JSON parser.
+
+ We assume the geoJSON is all in decimal degrees in WGS84.
+ */
+- (nullable instancetype)initWithGeoJSON:(NSData *__nonnull)geoJSON;
+
+/**
+ Initializes with vector parsed from geoJSON.
+
+ Returns one object to represent the whole thing, which might include multiple different vectors. This version uses slower JSON parser.
+
+ We assume the geoJSON is all in decimal degrees in WGS84.
+ */
+- (nullable instancetype)initWithGeoJSONApple:(NSData *__nonnull)geoJSON;
+
+/**
+ Initializes with vector parsed from geoJSON.
+
+ Returns one object to represent the whole thing, which might include multiple different vectors. This version parses its data from an NSDictionary, which had to be parsed from JSON at some point. Probably the slower path.
+
+ We assume the geoJSON is all in decimal degrees in WGS84.
+ */
+- (nullable instancetype)initWithGeoJSONDictionary:(NSDictionary *__nonnull)geoJSON;
+
+// Note: Turned off with reading
+#if 0
+/**
+ Initializes with vectors read from the given cache file.
+
+ MaplyVectorObject's can be written and read from a binary file. We use this for caching data locally on the device.
+
+ @param fileName Name of the binary vector file.
+
+ @return The vector object(s) read from the file or nil on failure.
+ */
+- (nullable instancetype)initWithFile:(NSString *__nonnull)fileName;
+#endif
+
+/**
+ Initializes with vectors read from the given shapefile.
+
+ This will read all the shapes in the given shapefile into memory and return them as one MaplyVectorObject.
+
+ @param fileName The basename of the shape file. Don't include the extension.
+
+ @return The vector object(s) read from the file or nil on failure.
+ */
+- (nullable instancetype)initWithShapeFile:(NSString *__nonnull)fileName;
+
+
+// Note: Vector writing turned off
+#if 0
+/**
+ Write the vector object to the given file on the device.
+
+ We support a binary format for caching vector data. Typically you write these files on the device or in the simulator and then put them in a place you can easily find them when needed.
+
+ @param fileName The file to read the vector data from.
+
+ @return Returns true on succes, false on failure.
+ */
+- (bool)writeToFile:(NSString *__nonnull)fileName;
+#endif
+
+/**
+ Make a deep copy of the vector object and return it.
+
+ This makes a complete copy of the vector object, with all features and nothing shared.
+
+ Had to rename this because Apple's private method scanner is dumb.
+ */
+- (MaplyVectorObject *__nonnull)deepCopy2;
+
+/**
+ Reproject from one coordinate system to another.
+
+ This reprojects every single point in the points, linears, and areals (and mesh) from the source coordinate system to the destionation.
+
+ Typically, you'll want Plate Carree for display, the destSystem is probably that.
+
+ For various reasons (e.g. scale), this will probably not work right for you.
+
+ @param srcSystem The source coordinate system. The data is already in this sytem.
+
+ @param destSystem The destination coordinate system. The data will be in this system on return.
+ */
+- (void)reprojectFrom:(MaplyCoordinateSystem *__nonnull)srcSystem to:(MaplyCoordinateSystem *__nonnull)destSystem;
+
+/**
+ Dump the feature(s) out as text
+
+ This will write each feature out as text for debugging.
+ */
+- (NSString *__nonnull)log;
+
+/**
+ Add a hole to an existing feature.
+
+ This method is expecting to find exactly one areal feature. If it finds one, it will add the given hole as a loop on the end of the list of loops.
+ */
+- (void)addHole:(const MaplyCoordinate *__nonnull)coords numCoords:(int)numCoords;
+
+/**
+ Returns the type of the vector feature.
+
+ This method returns the type of the vector. Since vector objects can contain multiple types of vectors at once, this is somewhat complicated.
+
+|Type | Description |
+|:----|:-----------:|
+|MaplyVectorNoneType | There are no features in this object. |
+|MaplyVectorPointType | There are only points (and multi-points) in the object. |
+|MaplyVectorLinearType | There are only linear features in the object. |
+|MaplyVectorLinear3dType | There are only linear features with Z values in the object. |
+|MaplyVectorArealType | There are only areal features in the object. |
+|MaplyVectorMultiType | There are multiple features of different types in the object. |
+ */
+- (MaplyVectorObjectType)vectorType;
+
+/**
+ Run a point in polygon test on all the areal features within the object.
+
+ We'll run a point in polygon test on all the areal features within the vector object. If the point is within one of them, we return true, otherwise false.
+ */
+- (bool)pointInAreal:(MaplyCoordinate)coord;
+
+/**
+ Test if any linear feature is within distance of coord
+ */
+- (bool)pointNearLinear:(MaplyCoordinate)coord distance:(float)maxDistance inViewController:(MaplyBaseViewController *__nonnull)vc;
+
+/**
+ Calculate the center of the entire set of vectors in this object.
+ */
+- (MaplyCoordinate)center;
+
+/**
+ Copy the vectors in the given vector object into this one.
+ */
+- (void)mergeVectorsFrom:(MaplyVectorObject *__nonnull)otherVec;
+
+/**
+ For a linear feature, calculate the mid oint and rotation at that point.
+
+ The vector object contains a number of half baked geometric queries, this being one of them.
+
+ This finds the middle (as measured by distance) of a linear feature and then calculations an angle corresponding to the line segment that middle sits in.
+
+ Why? Think label road placement.
+ */
+- (bool)linearMiddle:(MaplyCoordinate *__nonnull)middle rot:(double *__nonnull)rot;
+
+- (bool)linearMiddle:(MaplyCoordinate *__nullable)middle rot:(double *__nullable)rot displayCoordSys:(MaplyCoordinateSystem *__nonnull)coordSys;
+
+/**
+ For a linear feature, calculate the mid point.
+
+ This is a convenience method to be called without pointers (Swift)
+
+ If you need both the mid point and the rotation, this method is less efficient than the method with pointers.
+
+ @return kMaplyNullCoordinate in case of error
+
+ */
+- (MaplyCoordinate)linearMiddle:(MaplyCoordinateSystem *__nonnull)coordSys;
+
+/**
+ For a linear feature, calculate the mid point and returns the rotation at that point.
+
+ This is a convenience method to be called without pointers (Swift)
+
+ If you need both the mid point and the rotation, this method is less efficient than the method with pointers.
+
+ @return DBL_MIN in case of error
+ */
+- (double)linearMiddleRotation:(MaplyCoordinateSystem *__nonnull)coordSys;
+
+/**
+ return the middle coordinate in a line feature
+
+ @return kMaplyNullCoordinate in case of error
+ */
+- (MaplyCoordinate)middleCoordinate;
+
+/**
+ return the middle coordinate in a line feature.
+ */
+- (bool)middleCoordinate:(MaplyCoordinate *__nonnull)middle;
+
+/**
+ Calculate the center and extents of the largest loop in an areal feature.
+
+ The vector object contains a number of half baked geometric queries, this being one of them.
+
+ If this vector contains at least one areal feature, we'll determine which loop is the largest and return the center of that loop, as well as its bounding box.
+
+ Why? Think label placement on an areal feature.
+
+ @return Returns false if there was no loop (i.e. probably isn't an areal)
+ */
+- (bool)largestLoopCenter:(MaplyCoordinate *__nullable)center mbrLL:(MaplyCoordinate *__nullable)ll mbrUR:(MaplyCoordinate *__nullable)ur;
+
+/**
+ Calculate the centroid of the largest loop in the areal feature.
+
+ The centroid is a better center for label placement than the middle of the largest loop as calculated by largestLoopCenter:mbrLL:mbrUR:
+
+ @return Returns the centroid structure. If there was no loop (i.e. probably isn't an areal), the result will be kMaplyNullCoordinate
+ */
+- (MaplyCoordinate)centroid;
+
+/**
+ Calculate the centroid of the largest loop in the areal feature.
+
+ The centroid is a better center for label placement than the middle of the largest loop as calculated by largestLoopCenter:mbrLL:mbrUR:
+
+ @return Returns false if there was no loop (probably wasn't an areal).
+ */
+- (bool)centroid:(MaplyCoordinate *__nonnull)centroid;
+
+/**
+ Calculate the bounding box of all the features in this vector object.
+
+ @return kMaplyNullBoundingBox in case of error
+ */
+- (MaplyBoundingBox)boundingBox;
+
+/**
+ Calculate the bounding box of all the features in this vector object.
+ */
+- (bool)boundingBoxLL:(MaplyCoordinate *__nonnull)ll ur:(MaplyCoordinate *__nonnull)ur;
+
+/**
+ Calculate the area of the outer loops.
+
+ This returns the area of the outer loops of any areal features in the VectorObject.
+ */
+- (double)areaOfOuterLoops;
+
+/**
+ Convert any linear features into areal features.
+
+ Convert linear features to areal features by closing each one individually.
+ */
+- (MaplyVectorObject * _Nonnull )linearsToAreals;
+
+/**
+ Convert any areal features into outlines.
+ */
+- (MaplyVectorObject * __nonnull)arealsToLinears;
+
+/**
+ Reverse the direction of areal loops in-place
+ */
+- (void)reverseAreals;
+
+/**
+ Return a copy with the areal loops reversed
+ */
+- (MaplyVectorObject * __nonnull)reversedAreals;
+
+/**
+ Filter out edges created from clipping areal features on the server.
+
+ In some very specific cases (OSM water) we get polygons that are obviously clipped
+ along internal boundaries. We can clear this up with some very, very specific logic.
+
+ Input must be closed areals and output is linears.
+ */
+- (MaplyVectorObject *__nonnull)filterClippedEdges;
+
+/**
+ Convert a feature to an NSArray of NSArrays of CLLocation points.
+
+ This is intended for areal features. It will convert those coordinates to CLLocation values and return them. Obviously this is intended for things that need CLLocation values.
+
+ @return Returns an NSArray of NSArray's which then contain CLLocation points.
+ */
+- (NSArray *__nullable)asCLLocationArrays;
+
+/**
+ Return the data as an NSArray of NSNumbers.
+
+ If this is a linear, we'll return the points as an NSArray of NSNumbers.
+ */
+- (NSArray *__nullable)asNumbers;
+
+/**
+ Split up this feature into individual features and return an array of them.
+
+ A vector object can represent multiple features with no real rhyme or reason to it. This method will make one vector object per feature, allowing you to operate on those individually.
+
+ @return An NSArray of MaplyVectorObject.
+ */
+- (NSArray<MaplyVectorObject *> *__nonnull)splitVectors;
+
+/**
+ Subdivide the edges in this feature to a given tolerance.
+
+ This will break up long edges in a vector until they lie flat on a globe to a given epsilon. The epislon is in display coordinates (radius = 1.0). This routine breaks this up along geographic boundaries.
+ */
+- (void)subdivideToGlobe:(float)epsilon;
+
+/**
+ Subdivide the edges in this feature to a given tolerance, using great circle math.
+
+ This will break up long edges in a vector until they lie flat on a globe to a given epsilon using a great circle route. The epsilon is in display coordinates (radius = 1.0).
+ */
+- (void)subdivideToGlobeGreatCircle:(float)epsilon;
+
+/**
+ Subdivide the edges in this feature to a given tolerance, using great circle math.
+
+ This version samples a great circle to display on a flat map.
+ */
+- (void)subdivideToFlatGreatCircle:(float)epsilon;
+
+
+/**
+ Subdivide the edges in this feature to a given tolerance, using ellipsoidal great circle math.
+
+ This will break up long edges in a vector until they lie flat on a globe to a given epsilon using a great circle route. The epsilon is in display coordinates (radius = 1.0).
+ */
+- (void)subdivideToGlobeGreatCirclePrecise:(float)epsilon;
+
+/**
+ Subdivide the edges in this feature to a given tolerance, using ellipsoidal great circle math.
+
+ This version samples a great circle to display on a flat map.
+ */
+- (void)subdivideToFlatGreatCirclePrecise:(float)epsilon;
+
+/**
+ Tesselate the areal geometry in this vector object and return triangles.
+
+ This will attempt to tesselate the areals (with holes) and turn them into triangles. No attribution will be assigned to the new triangles, so be aware. The tesselator is the GLU based one and does a decent job. Odds are if there's something wrong it's in the input data.
+ */
+- (MaplyVectorObject *__nonnull)tesselate;
+
+/**
+ Clip the given (presumably areal) feature(s) to a grid in radians of the given size.
+
+ This will run through the loops in the input vectors and clip them against a grid. The grid size is given in radians.
+
+ @return New areal features broken up along the grid.
+ */
+- (MaplyVectorObject *__nullable)clipToGrid:(CGSize)gridSize;
+
+/**
+
+ Clip the given (probably areal) features to the given bounding box.
+
+ This will run through the loops of the areal features and clip them against a bounding box.
+
+ The bounding box should be in the same coordinate system as the grid, probably radians.
+
+ @return The new areal features will be clipped along the bounding box.
+ */
+- (MaplyVectorObject *__nullable)clipToMbr:(MaplyCoordinate)ll upperRight:(MaplyCoordinate)ur;
+
+@end
+
+typedef MaplyVectorObject WGVectorObject;
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorStyle.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorStyle.h
new file mode 100644
index 0000000..2d30fab
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorStyle.h
@@ -0,0 +1,214 @@
+/* MaplyVectorStyle.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 1/3/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplyBaseViewController.h>
+
+@class MaplyVectorTileData;
+
+/**
+ Settings that control how vector tiles look in relation to their styles.
+
+ These are set based on the sort of device we're on, particularly retina vs. non-retina. They can be manipulated directly as well for your needs.
+ */
+@interface MaplyVectorStyleSettings : NSObject
+
+/// Initialize with the (presumably) retina scale
+- (instancetype __nonnull)initWithScale:(CGFloat)scale;
+
+/// Line widths will be scaled by this amount before display.
+@property (nonatomic) float lineScale;
+/// Text sizes will be scaled by this amount before display.
+@property (nonatomic) float textScale;
+/// Markers (symbols+circles) will be scaled by this amount before display.
+@property (nonatomic) float markerScale;
+/// Symbols will be scaled by this amount before display.
+@property (nonatomic) float symbolScale;
+/// Circles will be scaled by this amount before display.
+@property (nonatomic) float circleScale;
+/// Importance for markers in the layout engine
+@property (nonatomic) float markerImportance;
+/// Default marker size when none is specified
+@property (nonatomic) float markerSize;
+/// Importance for labels in the layout engine
+@property (nonatomic) float labelImportance;
+/// If set we'll use the zoom levels defined in the style
+@property (nonatomic) bool useZoomLevels;
+
+/// For symbols we'll try to pull a UUID out of this field to stick in the marker and label uniqueID
+@property (nonatomic,nullable) NSString *uuidField;
+
+/// Draw priority calculated as offset from here
+@property (nonatomic) int baseDrawPriority;
+
+/// Offset between levels
+@property (nonatomic) int drawPriorityPerLevel;
+
+/**
+ The overall map scale calculations will be scaled by this amount.
+
+ We use the map scale calculations to figure out what is dispalyed and when. Not what to load in, mind you, that's a separate, but related calculation. This controls the scaling of those calculations. Scale it down to load things in later, up to load them in sooner.
+ */
+@property (nonatomic) float mapScaleScale;
+
+/// Dashed lines will be scaled by this amount before display.
+@property (nonatomic) float dashPatternScale;
+
+/// Use widened vectors (which do anti-aliasing and such)
+@property (nonatomic) bool useWideVectors;
+
+/// Where we're using old vectors (e.g. not wide) scale them by this amount
+@property (nonatomic) float oldVecWidthScale;
+
+/// If we're using widened vectors, only activate them for strokes wider than this. Defaults to zero.
+@property (nonatomic) float wideVecCuttoff;
+
+/// If set, this is the shader we'll use on the areal features.
+@property (nonatomic,strong) NSString * _Nullable arealShaderName;
+
+/// If set, we'll make all the features selectable. If not, we won't.
+@property (nonatomic) bool selectable;
+
+/// If set, icons will be loaded from this directory
+@property (nonatomic, strong) NSString * _Nullable iconDirectory;
+
+/// The default font family for all text
+@property (nonatomic,strong) NSString * _Nullable fontName;
+
+@end
+
+@protocol MaplyVectorStyle;
+
+/**
+ Protocol for styling the vectors.
+
+ You pass in an object which adheres to this protocol and will style
+ the vectors read by a MaplyMapnikVectorTiles object. In general, this will be
+ a parsed Mapnik vector file, but you can substitute your own logic as well.
+ */
+@protocol MaplyVectorStyleDelegate <NSObject>
+
+/**
+ Return the styles that apply to the given feature (attributes).
+ */
+- (nullable NSArray *)stylesForFeatureWithAttributes:(NSDictionary *__nonnull)attributes
+ onTile:(MaplyTileID)tileID
+ inLayer:(NSString *__nonnull)layer
+ viewC:(NSObject<MaplyRenderControllerProtocol> *__nonnull)viewC;
+
+/// Return true if the given layer is meant to display for the given tile (zoom level)
+- (BOOL)layerShouldDisplay:(NSString *__nonnull)layer tile:(MaplyTileID)tileID;
+
+/// Return the style associated with the given UUID.
+- (nullable NSObject<MaplyVectorStyle> *)styleForUUID:(long long)uiid viewC:(NSObject<MaplyRenderControllerProtocol> *__nonnull)viewC;
+
+/// Return the style for the background
+- (nullable NSObject<MaplyVectorStyle> *)backgroundStyleViewC:(NSObject<MaplyRenderControllerProtocol> *__nonnull)viewC;
+
+// Return a list of all the styles in no particular order. Needed for categories and indexing
+- (NSArray * __nonnull)allStyles;
+
+@end
+
+/**
+ Base protocol for the vector styles.
+
+ Maply Vector Style is the protocol the your vector style needs to
+ implement for the vector tile parsers to recognize it.
+ */
+@protocol MaplyVectorStyle<NSObject>
+
+/// Unique Identifier for this style
+- (long long) uuid;
+
+/// Category used for sorting
+- (NSString * _Nullable) getCategory;
+
+/// Set if this geometry is additive (e.g. sticks around) rather than replacement
+- (bool) geomAdditive;
+
+/// Construct objects related to this style based on the input data.
+- (void)buildObjects:(NSArray * _Nonnull)vecObjs
+ forTile:(MaplyVectorTileData * __nonnull)tileData
+ viewC:(NSObject<MaplyRenderControllerProtocol> * _Nonnull)viewC
+ desc:(NSDictionary * _Nullable)desc;
+
+/// Construct objects related to this style based on the input data.
+- (void)buildObjects:(NSArray * _Nonnull)vecObjs
+ forTile:(MaplyVectorTileData * __nonnull)tileData
+ viewC:(NSObject<MaplyRenderControllerProtocol> * _Nonnull)viewC
+ desc:(NSDictionary * _Nullable)desc
+ cancelFn:(bool(^__nullable)(void))cancelFn;
+
+@end
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**
+ Use a style delegate to interpret vector data.
+
+ Run the style delegate against the given vectors. The resulting features are added to the
+ given view controller using the thread mode specified.
+
+ @param vecObjs An array of MaplyVectorObject.
+
+ @param styleDelegate The style delegate that controls how the vectors will look.
+
+ @param viewC View controller to add the geometry to.
+
+ @param threadMode MaplyThreadCurrent will block until all the features are added. MaplyThreadAny will do some of the work on another thread.
+ */
+NSArray<MaplyComponentObject*> * _Nonnull AddMaplyVectorsUsingStyle(NSArray<MaplyVectorObject*> * _Nonnull vecObjs,
+ NSObject<MaplyVectorStyleDelegate> * _Nonnull styleDelegate,
+ NSObject<MaplyRenderControllerProtocol> * _Nonnull viewC,
+ MaplyThreadMode threadMode);
+
+/**
+ Use a style delegate to interpret vector data.
+
+ Run the style delegate against the given vectors. The resulting features are added to the
+ given view controller using the thread mode specified.
+
+ @param vecObjs An array of MaplyVectorObject.
+
+ @param styleDelegate The style delegate that controls how the vectors will look.
+
+ @param viewC View controller to add the geometry to.
+
+ @param tileId The tile where the feature originates.
+
+ @param enable Automatically enable the generated objects
+
+ @param threadMode MaplyThreadCurrent will block until all the features are added. MaplyThreadAny will do some of the work on another thread.
+
+ @param desc Additional attributes to include with the generated component objects
+ */
+NSArray<MaplyComponentObject*> * _Nonnull AddMaplyVectorsUsingStyleAndAttributes(
+ NSArray<MaplyVectorObject*> * _Nonnull vecObjs,
+ NSObject<MaplyVectorStyleDelegate> * _Nonnull styleDelegate,
+ NSObject<MaplyRenderControllerProtocol> * _Nonnull viewC,
+ MaplyTileID tileId,
+ bool enable,
+ MaplyThreadMode threadMode,
+ NSDictionary * _Nullable desc);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorStyleSimple.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorStyleSimple.h
new file mode 100644
index 0000000..ccb309e
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorStyleSimple.h
@@ -0,0 +1,85 @@
+/* MaplyVectorStyleSimple.m
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 3/15/16.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <WhirlyGlobe/MapboxVectorTiles.h>
+
+/**
+ Simple default style to see something in vector tile data.
+
+ A simple vector style that displays each layer in a random color.
+ Use this as a starting point for your own style.
+ */
+@interface MaplyVectorStyleSimpleGenerator : NSObject<MaplyVectorStyleDelegate>
+
+@property (nonatomic,weak) NSObject<MaplyRenderControllerProtocol> *viewC;
+
+/// Initialize with a map view controller
+- (id)initWithViewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+/// uuid for the styles
+- (long long)generateID;
+
+@end
+
+/**
+ Base class for the simple vector style.
+ */
+@interface MaplyVectorStyleSimple : NSObject<MaplyVectorStyle>
+
+/// Unique Identifier for this style
+@property (nonatomic) long long uuid;
+
+/// Set if this geometry is additive (e.g. sticks around) rather than replacement
+@property (nonatomic) bool geomAdditive;
+
+/// Priority for sorting among layers
+@property (nonatomic) int drawPriority;
+
+@property (nonatomic,weak) NSObject<MaplyRenderControllerProtocol> *viewC;
+
+- (id)initWithGen:(MaplyVectorStyleSimpleGenerator *)gen viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+@end
+
+/**
+ Simple filled polygon with a random color.
+ */
+@interface MaplyVectorStyleSimplePolygon : MaplyVectorStyleSimple
+
+@property (nonatomic,strong) UIColor *color;
+
+@end
+
+/**
+ Simple point we'll convert to a label.
+ */
+@interface MaplyVectorStyleSimplePoint : MaplyVectorStyleSimple
+
+@property (nonatomic,strong) UIFont *font;
+
+@end
+
+/**
+ Simple linear with a random color.
+ */
+@interface MaplyVectorStyleSimpleLinear : MaplyVectorStyleSimple
+
+@property (nonatomic,strong) UIColor *color;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorTileLineStyle.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorTileLineStyle.h
new file mode 100644
index 0000000..f56dd07
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorTileLineStyle.h
@@ -0,0 +1,29 @@
+/* MaplyVectorLineStyle.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 1/3/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyVectorStyle.h>
+#import <WhirlyGlobe/MaplyVectorTileStyle.h>
+
+/**
+ Implementation of the line style symbolizer for Maply Vector Tiles.
+ */
+@interface MaplyVectorTileStyleLine : MaplyVectorTileStyle
+
+- (instancetype)initWithStyleEntry:(NSDictionary *)styleEntry settings:(MaplyVectorStyleSettings *)settings viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorTileMarkerStyle.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorTileMarkerStyle.h
new file mode 100644
index 0000000..994307e
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorTileMarkerStyle.h
@@ -0,0 +1,29 @@
+/* MaplyVectorMarkerStyle.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 1/3/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyVectorStyle.h>
+#import <WhirlyGlobe/MaplyVectorTileStyle.h>
+
+/**
+ Implementation of the marker style symbolizer for Maply Vector Tiles.
+ */
+@interface MaplyVectorTileStyleMarker : MaplyVectorTileStyle
+
+- (instancetype)initWithStyleEntry:(NSDictionary *)styleEntry settings:(MaplyVectorStyleSettings *)settings viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorTilePolygonStyle.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorTilePolygonStyle.h
new file mode 100644
index 0000000..4d9d81f
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorTilePolygonStyle.h
@@ -0,0 +1,29 @@
+/* MaplyVectorPolygonStyle.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 1/3/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyVectorStyle.h>
+#import <WhirlyGlobe/MaplyVectorTileStyle.h>
+
+/**
+ Implementation of the polygon style symbolizer for Maply Vector Tiles.
+ */
+@interface MaplyVectorTileStylePolygon : MaplyVectorTileStyle
+
+- (instancetype)initWithStyleEntry:(NSDictionary *)styleEntry settings:(MaplyVectorStyleSettings *)settings viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorTileStyle.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorTileStyle.h
new file mode 100644
index 0000000..5f4eed2
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorTileStyle.h
@@ -0,0 +1,60 @@
+/* MaplyVectorTileStyle.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 1/3/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyVectorStyle.h>
+
+/** The Maply Vector Tile Style is an internal representation of the style JSON coming out
+ of a Maply Vector Tile database.
+ */
+@interface MaplyVectorTileStyle : NSObject<MaplyVectorStyle>
+
+/**
+ Construct a style entry from an NSDictionary.
+ */
++ (id)styleFromStyleEntry:(NSDictionary *)styleEntry settings:(MaplyVectorStyleSettings *)settings viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+/// Unique Identifier for this style
+@property (nonatomic) long long uuid;
+
+/// Set if this geometry is additive (e.g. sticks around) rather than replacement
+@property (nonatomic) bool geomAdditive;
+
+/// Construct a style entry from an NSDictionary
+- (instancetype)initWithStyleEntry:(NSDictionary *)styleEntry viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+/// Turn the min/maxscaledenom into height ranges for minVis/maxVis
+- (void)resolveVisibility:(NSDictionary *)styleEntry settings:(MaplyVectorStyleSettings *)settings desc:(NSMutableDictionary *)desc;
+
+/// parse a mapnik style template string
+- (NSString*)formatText:(NSString*)formatString forObject:(MaplyVectorObject*)vec;
+
+/// The view controller we're constructing objects in
+@property (nonatomic,weak) NSObject<MaplyRenderControllerProtocol> *viewC;
+
+/// If set, we create selectable objects
+/// This controls whether the objects we create are selectable. Off by default.
+@property (nonatomic) bool selectable;
+
+/// Parse the various types of color strings
++ (UIColor *) ParseColor:(NSString *)colorStr;
+
+/// Parse an RGB color and fill in the alpha
++ (UIColor *) ParseColor:(NSString *)colorStr alpha:(CGFloat)alpha;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorTileTextStyle.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorTileTextStyle.h
new file mode 100644
index 0000000..59b53c3
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVectorTileTextStyle.h
@@ -0,0 +1,29 @@
+/* MaplyVectorTextStyle.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 1/3/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyVectorStyle.h>
+#import <WhirlyGlobe/MaplyVectorTileStyle.h>
+
+/**
+ Implementation of the text style symbolizer for Maply Vector Tiles.
+ */
+@interface MaplyVectorTileStyleText : MaplyVectorTileStyle
+
+- (instancetype _Nullable)initWithStyleEntry:(NSDictionary * _Nonnull)styleEntry settings:(MaplyVectorStyleSettings * _Nonnull)settings viewC:(NSObject<MaplyRenderControllerProtocol> * _Nonnull)viewC;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVertexAttribute.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVertexAttribute.h
new file mode 100644
index 0000000..07e220a
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyVertexAttribute.h
@@ -0,0 +1,49 @@
+/*
+ * MaplyVertexAttribute.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 11/29/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+
+/**
+ Vertex Attributes are passed all the way though on objects to shaders.
+
+ If you have your own custom shader, you often need a way to feed it data. The toolkit will set up the standard data, like vertices, texture coordinates and normals, but sometimes you need something custom.
+
+ Vertex attributes are the mechanism you use to pass that custom data all the way down to the shader.
+
+ How the vertex attributes are used depends on the data type, so consult the appropriate object.
+ */
+@interface MaplyVertexAttribute : NSObject
+
+/// Construct a vertex attribute as a single float
+- (nonnull instancetype)initWithName:(NSString * __nonnull)name slot:(int)slot float:(float)val;
+
+/// Construct a vertex attribute as two floats
+- (nonnull instancetype)initWithName:(NSString * __nonnull)name slot:(int)slot floatX:(float)x y:(float)y;
+
+/// Construct a vertex attribute as three flaots
+- (nonnull instancetype)initWithName:(NSString * __nonnull)name slot:(int)slot floatX:(float)x y:(float)y z:(float)z;
+
+/// Construct a vertex attribute as an RGBA value
+- (nonnull instancetype)initWithName:(NSString * __nonnull)name slot:(int)slot color:(UIColor * __nonnull)color;
+
+/// Construct a vertex attribute as an int
+- (nonnull instancetype)initWithName:(NSString * __nonnull)name slot:(int)slot int:(int)val;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyViewController.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyViewController.h
new file mode 100644
index 0000000..c49ae41
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyViewController.h
@@ -0,0 +1,651 @@
+/* MaplyViewController.h
+ * MaplyComponent
+ *
+ * Created by Steve Gifford on 9/6/12.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyScreenMarker.h>
+#import <WhirlyGlobe/MaplyVectorObject.h>
+#import <WhirlyGlobe/MaplyViewTracker.h>
+#import <WhirlyGlobe/MaplyComponentObject.h>
+#import <WhirlyGlobe/MaplySharedAttributes.h>
+#import <WhirlyGlobe/MaplyBaseViewController.h>
+
+@class MaplyControllerLayer;
+@class MaplyViewController;
+
+
+/**
+ Animation State used by the MaplyViewControllerAnimationDelegate.
+
+ You fill out one of these when you're implementing the animation delegate. Return it and the view controller will set the respective values to match.
+ */
+@interface MaplyViewControllerAnimationState : NSObject
+
+/// Heading is calculated from due north
+/// If not set or set to MAXFLOAT, this is ignored
+@property (nonatomic) double heading;
+
+/// Height above the map
+@property (nonatomic) double height;
+
+/// Position to move to on the map
+@property (nonatomic) MaplyCoordinateD pos;
+
+/// If set, this is a point on the screen where pos should be.
+/// By default this is (-1,-1) meaning the screen position is just the middle. Otherwise, this is where the position should wind up on the screen, if it can.
+@property (nonatomic) CGPoint screenPos;
+
+/**
+ Interpolate a new state between the given states A and B.
+
+ This does a simple interpolation (lat/lon, not great circle) between the two animation states.
+ */
++ (nonnull MaplyViewControllerAnimationState *)Interpolate:(double)t from:(MaplyViewControllerAnimationState *__nonnull)stateA to:(MaplyViewControllerAnimationState *__nonnull)stateB;
+
+@end
+
+/**
+ An animation delegate that can be set on a MaplyViewController to control the view over time.
+
+ Filling out these methods will get you animation callbacks at the proper time to control position, heading and height on a frame basis.
+
+ You pass the resulting object in to
+ */
+@protocol MaplyViewControllerAnimationDelegate <NSObject>
+
+/**
+ This method is called when the animation starts.
+
+ At the animation start we collect up the various parameters of the current visual view state and pas them in via the startState. You probably want to keep track of this for later.
+
+ @param viewC The view controller doing the animation.
+
+ @param startState The starting point for the visual view animation. Cache this somewhere for your own interpolation.
+
+ @param startTime When the animation starts (e.g. now)
+
+ @param endTime When the animation ends. This is an absolute value.
+ */
+- (void)mapViewController:(MaplyViewController *__nonnull)viewC startState:(MaplyViewControllerAnimationState *__nonnull)startState startTime:(NSTimeInterval)startTime endTime:(NSTimeInterval)endTime;
+
+/**
+ This method is called at the beginning of every frame draw to position the viewer.
+
+ This is the method that does all the work. You need to fill out the returned MaplyViewControllerAnimationState according to whatever interpolation your'e doing based on the currentTime.
+
+ @param viewC The view controller doing the animation.
+
+ @param currentTime The time for this frame. Use this rather than calculating the time yourself.
+
+ @return The MaplyViewControllerAnimationState expressing where you want the viewer to be and where they are looking.
+ */
+- (nonnull MaplyViewControllerAnimationState *)mapViewController:(MaplyViewController *__nonnull)viewC stateForTime:(NSTimeInterval)currentTime;
+
+@optional
+
+/**
+ This method is called at the end of the animation.
+
+ The map view controller calls this method when the animation is finished. Do your cleanup here if need be.
+
+ @param viewC The map view controller.
+ */
+- (void)mapViewControllerDidFinishAnimation:(MaplyViewController *__nonnull)viewC;
+
+@end
+
+/**
+ A simple animation delegate for moving the map around.
+
+ The animation delegate support provides a lot of flexibility. This version just provides all the standard fields and interpolates from beginning to end.
+ */
+@interface MaplyViewControllerSimpleAnimationDelegate : NSObject <MaplyViewControllerAnimationDelegate>
+
+/// Initialize with an animation state to copy
+- (nonnull instancetype)initWithState:(MaplyViewControllerAnimationState *__nonnull)endState;
+
+/// Location at the end of the animation
+@property (nonatomic) MaplyCoordinateD loc;
+
+/// Heading at the end of the animation
+@property (nonatomic) double heading;
+
+/// Height at the end of the animation
+@property (nonatomic) double height;
+
+/// Custom easing
+@property (readwrite,copy) ZoomEasingBlock _Nullable zoomEasing;
+
+@end
+
+/**
+ A protocol to fill out for selection and tap messages from the MaplyViewController.
+
+ Fill out the protocol when you want to get back selection and tap messages. All the methods are optional.
+ */
+@protocol MaplyViewControllerDelegate <NSObject>
+
+@optional
+
+/**
+ Called when the user taps on or near an object.
+
+ You're given the object you passed in originally, such as a MaplyScreenMarker. You can set a userObject on most of these to put your own data in there for tracking.
+ */
+- (void)maplyViewController:(MaplyViewController *__nonnull)viewC didSelect:(NSObject *__nonnull)selectedObj;
+
+/**
+ User selected a given object and tapped at a given location.
+
+ This is called when the user selects an object. It differs from maplyViewController:didSelect: in that it passes on the location (in the local coordinate system) and the position on screen.
+
+ @param viewC View Controller that saw the selection.
+
+ @param selectedObj The object selected. Probably one of MaplyVectorObject or MaplyScreenLabel or so on.
+
+ @param coord Location in the local coordinate system where the user tapped.
+
+ @param screenPt Location on screen where the user tapped.
+ */
+- (void)maplyViewController:(MaplyViewController *__nonnull)viewC didSelect:(NSObject *__nonnull)selectedObj atLoc:(MaplyCoordinate)coord onScreen:(CGPoint)screenPt;
+
+/**
+ User selected one or more objects at a given location.
+
+ @param viewC View Controller that saw the selection(s).
+
+ @param selectedObjs The object(s) selected. Probably one of MaplyVectorObject or MaplyScreenLabel or so on.
+
+ @param coord Location in the local coordinate system where the user tapped.
+
+ @param screenPt Location on screen where the user tapped.
+ */
+- (void)maplyViewController:(MaplyViewController *__nonnull)viewC allSelect:(NSArray *__nonnull)selectedObjs atLoc:(MaplyCoordinate)coord onScreen:(CGPoint)screenPt;
+
+/**
+ User tapped at a given location.
+
+ This is a tap at a specific location on the map. This won't be called if they tapped and selected, just for taps.
+ */
+- (void)maplyViewController:(MaplyViewController *__nonnull)viewC didTapAt:(MaplyCoordinate)coord;
+
+/**
+ Called when the map starts moving.
+
+ @param viewC The map view controller.
+
+ @param userMotion Set if this is motion being caused by the user, rather than a call to set location.
+
+ This is called when something (probably the user) starts moving the map.
+ */
+- (void)maplyViewControllerDidStartMoving:(MaplyViewController *__nonnull)viewC userMotion:(bool)userMotion;
+
+/**
+ Called when the map stops moving.
+
+ This is called when the map stops moving. It passes in the corners of the current viewspace.
+
+ @param viewC The globe view controller.
+
+ @param userMotion Set if this is motion being caused by the user, rather than a call to set location.
+
+ @param corners An array of length 4 containing the corners of the view space (lower left, lower right, upper right, upper left). If any of those corners does not intersect the map (think zoomed out), its values are set to MAXFLOAT.
+ */
+- (void)maplyViewController:(MaplyViewController *__nonnull)viewC didStopMoving:(MaplyCoordinate *__nonnull)corners userMotion:(bool)userMotion;
+
+/**
+ Called whenever the viewpoint moves.
+
+ This is called whenever the viewpoint moves. That includes user motion as well as animations.
+
+ It may be triggered as often as every frame. If that's a problem, use one of the other variants.
+
+ @param viewC The map view controller.
+
+ @param corners An array of length 4 containing the corners of the view space (lower left, lower right, upper right, upper left). If any of those corners does not intersect the globe (think zoomed out), its values are set to MAXFLOAT.
+ */
+- (void)maplyViewController:(MaplyViewController *__nonnull)viewC didMove:(MaplyCoordinate *__nonnull)corners;
+
+
+/**
+ Called when the user taps on one of your annotations.
+
+ This is called when the user taps on an annotation.
+
+ @param annotation Which annotation they tapped on.
+ */
+- (void)maplyViewController:(MaplyViewController *__nonnull)viewC didTapAnnotation:(MaplyAnnotation*__nonnull)annotation;
+
+/// Old version for compatibility. Use tap instead.
+- (void)maplyViewController:(MaplyViewController *__nonnull)viewC didClickAnnotation:(MaplyAnnotation*__nonnull)annotation __deprecated;
+
+@end
+
+
+typedef NS_ENUM(NSInteger, MaplyMapType) {
+ MaplyMapType3D,
+ MaplyMapTypeFlat,
+};
+
+/**
+ This view controller implements a map.
+
+ This is the main entry point for displaying a 2D or 3D map. Create one of these, fill it with data and let your users mess around with it.
+
+ You can display a variety of features on the map, including tile base maps (MaplyQuadImageTilesLayer), vectors (MaplyVectorObject), shapes (MaplyShape), and others. Check out the add calls in the MaplyBaseViewController for details.
+
+ The Maply View Controller can be initialized in 3D map, 2D map mode. The 2D mode can be tethered to a UIScrollView if you want to handle gestures that way. That mode is very specific at the moment.
+
+ To get selection and tap callbacks, fill out the MaplyViewControllerDelegate and assign the delegate.
+
+ Most of the functionality is shared with MaplyBaseViewController. Be sure to look in there first.
+ */
+@interface MaplyViewController : MaplyBaseViewController
+
+/// Initialize as a flat or 3D map.
+- (nonnull instancetype)initWithMapType:(MaplyMapType)mapType;
+
+/// Initialize as a 2D map.
+- (nonnull instancetype)init;
+
+/// Set the coordinate system to use in display.
+/// The coordinate system needs to be valid in flat mode. The extents, if present, will be used to define the coordinate system origin.
+/// nil is the default and will result in a full web style Spherical Mercator.
+@property(nonatomic,strong) MaplyCoordinateSystem *__nullable coordSys;
+
+/**
+ Set the center of the display coordinate system.
+
+ This is (0,0,0) by default. If you set it to something else all display coordinates will be offset from that origin.
+
+ The option is useful when displaying small maps (of a city, say) at very high resolution.
+ */
+@property(nonatomic) MaplyCoordinate3d displayCenter;
+
+/**
+ Turn the pinch (zoom) gesture recognizer on and off
+
+ On by default.
+ */
+@property(nonatomic,assign) bool pinchGesture;
+
+/**
+ Turn the rotate gesture recognizer on and off
+
+ On by default.
+ */
+@property(nonatomic,assign) bool rotateGesture;
+
+/**
+ Turn the pan gesture on and off
+
+ Pan gesture is on by default
+ */
+@property(nonatomic,assign) bool panGesture;
+
+/**
+ Turn the double tap to zoom gesture recognizer on and off
+
+ On by default.
+ */
+@property(nonatomic,assign) bool doubleTapZoomGesture;
+
+/**
+ Turn the 2 finger tap to zoom out gesture recognizer on and off
+
+ On by default.
+ */
+@property(nonatomic,assign) bool twoFingerTapGesture;
+
+/**
+ Turn on the double tap and drag gesture to zoom in and out.
+
+ On by default.
+ */
+@property(nonatomic,assign) bool doubleTapDragGesture;
+
+/**
+ If set, we use a modified pan gesture recognizer to play nice
+ with the scroll view. For the UIScrollView object, set clipsToBounds,
+ pagingEnabled, and delaysContentTouches to YES, and set scrollEnabled
+ and canCancelContentTouches to NO. Add swipe gesture recognizers
+ to the scroll view to control paging, and call
+ requirePanGestureRecognizerToFailForGesture: for each.
+
+ Off by default.
+ */
+@property(nonatomic,assign) bool inScrollView;
+
+/**
+ turn the touch to cancel animation gesture on and off
+
+ off by default
+ */
+@property(nonatomic,assign) bool cancelAnimationOnTouch;
+
+/**
+ The current rotation away from north.
+ */
+@property(nonatomic,assign) float heading;
+
+/**
+ The minimum angle, in degrees, which a rotate gesture must subtend before rotation begins.
+ i.e., larger values are "stickier"
+ default is zero, causing rotation to begin immediately
+ */
+@property(nonatomic,assign) float rotateGestureThreshold;
+
+/**
+ If set, we'll automatically move to wherever the user tapped.
+
+ When on we'll move the current location to wherever the user tapped if they tapped the globe. That's true for selection as well. On by default.
+ */
+@property(nonatomic,assign) bool autoMoveToTap;
+
+/**
+ Delegate for selection and location tapping.
+
+ Fill in the MaplyViewControllerDelegate and assign it here to get callbacks for object selection and tapping.
+ */
+@property(nonatomic,weak) NSObject<MaplyViewControllerDelegate> *__nullable delegate;
+
+/**
+ Current height above terrain.
+
+ In 3D map mode this is the height from which the user is viewing the map. Maps are usually -PI to +PI along their horizontal edges.
+ */
+@property (nonatomic,assign) float height;
+
+/**
+ 2D visual views can do some simple wrapping. This turns that on and off (off by default).
+
+ On some 2D visual views we're allowed to wrap across the edge of the world. This will attempt to do that.
+ */
+@property (nonatomic,assign) bool viewWrap;
+
+/**
+ The box the view point can be in.
+
+ This is the box the view point is allowed to be within. The view controller will constrain it to be within that box. Coordinates are in geographic (radians).
+ */
+- (MaplyBoundingBox)getViewExtents;
+
+/**
+ The box the view point can be in.
+
+ This is the box the view point is allowed to be within. The view controller will constrain it to be within that box. Coordinates are in geographic (radians).
+ */
+- (void)getViewExtentsLL:(MaplyCoordinate *__nonnull)ll ur:(MaplyCoordinate *__nonnull)ur;
+
+/**
+ The box the view point can be in.
+
+ This is the box the view point is allowed to be within. The view controller will constrain it to be within that box. Coordinates are in geographic (radians).
+ */
+- (void)setViewExtents:(MaplyBoundingBox)box;
+
+/**
+ The box the view point can be in.
+
+ This is the box the view point is allowed to be within. The view controller will constrain it to be within that box. Coordinates are in geographic (radians).
+ */
+- (void)setViewExtentsLL:(MaplyCoordinate)ll ur:(MaplyCoordinate)ur;
+
+/**
+ Animate to the given position over time.
+
+ @param newPos A coordinate in geographic (lon/lat radians)
+
+ @param howLong A time in seconds.
+ */
+- (void)animateToPosition:(MaplyCoordinate)newPos time:(NSTimeInterval)howLong;
+
+/**
+ Animate the given position to the screen position over time.
+
+ This is similar to animateToPosition:time: except that it will attempt to match up the screen position and the geographic position. This is how you offset the location you're looking at.
+
+ If it's impossible to move newPos to loc, then nothing happens.
+
+ @param newPos The geographic position (lon/lat in radians) to move to.
+
+ @param loc The location on the screen where we'd like it to go.
+
+ @param howLong How long in seconds to take getting there.
+ */
+- (bool)animateToPosition:(MaplyCoordinate)newPos onScreen:(CGPoint)loc time:(NSTimeInterval)howLong;
+
+/**
+ Animate the given position and height to the screen position over time.
+
+ This is similar to animateToPosition:time: but it also takes a height paramater
+
+ @param newPos The geographic position (lon/lat in radians) to move to.
+
+ @param newHeight the view point height above the map.
+
+ @param howLong How long in seconds to take getting there.
+ */
+- (void)animateToPosition:(MaplyCoordinate)newPos height:(float)newHeight time:(NSTimeInterval)howLong;
+
+/**
+ Animate to the given position, heading and height over time.
+
+ @param newPos A coordinate in geographic (lon/lat radians)
+
+ @param newHeight New height to animate to.
+
+ @param newHeading New heading to finish on.
+
+ @param howLong A time interval in seconds.
+ */
+- (bool)animateToPosition:(MaplyCoordinate)newPos height:(float)newHeight heading:(float)newHeading time:(NSTimeInterval)howLong;
+
+/**
+ Animate to the given position, heading and height over time.
+
+ @param newPos A coordinate in geographic (lon/lat radians) (double precision)
+
+ @param newHeight New height to animate to. (double)
+
+ @param newHeading New heading to finish on. (double)
+
+ @param howLong A time interval in seconds.
+ */
+- (bool)animateToPositionD:(MaplyCoordinateD)newPos height:(double)newHeight heading:(double)newHeading time:(NSTimeInterval)howLong;
+
+/**
+ Animate to the given position, screen position, heading and height over time.
+
+ If it's impossible to move newPos to loc, then nothing happens.
+
+ @param newPos A coordinate in geographic (lon/lat radians)
+
+ @param loc The location on the screen where we'd like it to go.
+
+ @param newHeight New height to animate to.
+
+ @param newHeading New heading to finish on.
+
+ @param howLong A time interval in seconds.
+ */
+- (bool)animateToPosition:(MaplyCoordinate)newPos onScreen:(CGPoint)loc height:(float)newHeight heading:(float)newHeading time:(NSTimeInterval)howLong;
+
+/**
+ Set the center of the screen to the given position immediately.
+
+ @param newPos The geographic position (lon/lat in radians) to move to.
+ */
+- (void)setPosition:(MaplyCoordinate)newPos;
+
+/**
+ Set the center of the screen and the height offset immediately.
+
+ @param newPos The geographic position (lon/lat in radians) to move to.
+
+ @param height Height the view point above the map.
+ */
+- (void)setPosition:(MaplyCoordinate)newPos height:(float)height;
+
+/**
+ Return the current center position
+ */
+- (MaplyCoordinate)getPosition;
+
+/**
+ Return the current view point's height above the map.
+ */
+- (float)getHeight;
+
+/**
+ Return the current center position and height.
+
+ @param pos The center of the screen in geographic (lon/lat in radians).
+
+ @param height The current view point's height above the map.
+ */
+- (void)getPosition:(MaplyCoordinate *__nonnull)pos height:(float *__nonnull)height;
+
+
+/**
+ Set the viewing state all at once
+
+ This sets the position, height, screen position and heading all at once.
+ */
+- (void)setViewState:(MaplyViewControllerAnimationState *__nonnull)viewState;
+
+/**
+ Make a MaplyViewControllerAnimationState object from the current view state.
+
+ This returns the current view parameters in a single MaplyViewControllerAnimationState.
+ */
+- (nullable MaplyViewControllerAnimationState *)getViewState;
+
+/**
+ Return the closest a viewer is allowed to get to the map surface.
+
+ @return FLT_MIN if there's no pitchDelegate set
+ */
+- (float)getMinZoom;
+
+/**
+ Return the farthest away a viewer is allowed to get from the map surface
+
+ @return FLT_MIN if there's no pitchDelegate set
+ */
+- (float)getMaxZoom;
+
+/**
+ Return the zoom limits for 3D map mode.
+
+ @param minHeight The closest a viewer is allowed to get to the map surface.
+
+ @param maxHeight The farthest away a viewer is allowed to get from the map surface.
+ */
+- (void)getZoomLimitsMin:(float *__nonnull)minHeight max:(float *__nonnull)maxHeight;
+
+/**
+ Set the zoom limits for 3D map mode.
+
+ @param minHeight The closest a viewer is allowed to get to the map surface.
+
+ @param maxHeight The farthest away a viewer is allowed to get from the map surface.
+ */
+- (void)setZoomLimitsMin:(float)minHeight max:(float)maxHeight;
+
+/**
+ Return the geographic (lon/lat radians) coordinate in radians for a given screen point.
+
+ @return Returns the geo coordinate corresponding to a given screen point in radians.
+ */
+- (MaplyCoordinate)geoFromScreenPoint:(CGPoint)point;
+
+/**
+ Find a height that shows the given bounding box.
+
+ This method will search for a height that shows the given bounding box within the view. The search is inefficient, so don't call this a lot.
+
+ @param bbox The bounding box (in radians) we're trying to view.
+
+ @param pos Where the view will be looking.
+ */
+- (float)findHeightToViewBounds:(MaplyBoundingBox)bbox
+ pos:(MaplyCoordinate)pos;
+
+/**
+ Find a height that shows the given bounding box.
+ This method will search for a height that shows the given bounding box within the view. The search is inefficient, so don't call this a lot.
+
+ This version takes a margin to add around the outside of the area. Positive margins increase the screen area considered, making the
+ given area larger. Negative margins make the specified area smaller.
+
+ @param bbox The bounding box (in radians) we're trying to view.
+ @param pos Where the view will be looking.
+ @param marginX Horizontal boundary around the area
+ @param marginY Vertical boundary around the area
+ */
+- (float)findHeightToViewBounds:(MaplyBoundingBox)bbox
+ pos:(MaplyCoordinate)pos
+ marginX:(double)marginX
+ marginY:(double)marginY;
+
+/**
+ Find a height that shows the given bounding box.
+ This method will search for a height that shows the given bounding box within the view. The search is inefficient, so don't call this a lot.
+
+ This version takes a margin to add around the outside of the area. Positive margins increase the screen area considered, making the
+ given area larger. Negative margins make the specified area smaller.
+
+ This version attempts to place the given bounds within a rectangle other than the whole view frame.
+
+ @param bbox The bounding box (in radians) we're trying to view.
+ @param pos Where the view will be looking.
+ @param frame The screen area to consider.
+ @param newPos (out,optional) The center location needed to place \c pos at the center of \c frame
+ @param marginX Horizontal boundary around the area
+ @param marginY Vertical boundary around the area
+ */
+- (float)findHeightToViewBounds:(MaplyBoundingBox)bbox
+ pos:(MaplyCoordinate)pos
+ frame:(CGRect)frame
+ newPos:(MaplyCoordinate *_Nullable)newPos
+ marginX:(double)marginX
+ marginY:(double)marginY;
+
+/**
+
+ Return the extents of the current view
+
+ @return Returns the Bounding Box (in radians) corresponding to the current view
+ */
+- (MaplyBoundingBox)getCurrentExtents;
+
+/**
+
+ Make a gesture recognizer's success depend on the pan gesture
+ recognizer's failure.
+
+ When using the map view within a scroll view, add swipe gesture
+ recognizers to the scroll view to control paging, and call this method
+ for each. See also the inScrollView property and its comment.
+
+ @param other The other, subordinate gesture recognizer.
+ */
+- (void)requirePanGestureRecognizerToFailForGesture:(UIGestureRecognizer *__nullable)other;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyViewTracker.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyViewTracker.h
new file mode 100644
index 0000000..9317c00
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyViewTracker.h
@@ -0,0 +1,68 @@
+/*
+ * WGViewTracker.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 7/26/12.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+/**
+ The View Tracker associates a view with a geographic location.
+
+ The Maply View Tracker will move a UIView around to keep track of a geographic location. This is basically used for popups. The system will move the view around at the end of the frame render. It will hide the UIView if needed or make it reappear. The UIView should be a child of view controller's view.
+ */
+@interface MaplyViewTracker : NSObject
+
+/**
+ The UIView we want moved around.
+
+ This is the UIView we'll tie to the geographic location. If you want to center it, use offsets within the UIView.
+ */
+@property (nonatomic,strong) UIView *__nullable view;
+
+/**
+ The geographic location where we want to place the UIView.
+
+ This is the location (lon/lat in radians) where we want to stick the UIView. The location on screen will be updated as the user manipulates the map or globe.
+ */
+@property (nonatomic,assign) MaplyCoordinate loc;
+
+/**
+ An offset in screen space for the view tracker.
+
+ This offset is added to the location after it's projected into screen space.
+ */
+@property (nonatomic, assign) CGPoint offset;
+
+/**
+ The lowest height at which we'll see the view tracker.
+
+ This value is in display coordinates.
+ */
+@property (nonatomic,assign) float minVis;
+
+/**
+ the maximum height at which we'll see the view being tracked.
+
+ This value is in display coordinates.
+ */
+@property (nonatomic,assign) float maxVis;
+
+@end
+
+typedef MaplyViewTracker WGViewTracker;
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyWMSTileSource.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyWMSTileSource.h
new file mode 100644
index 0000000..4b9d317
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyWMSTileSource.h
@@ -0,0 +1,183 @@
+/* MaplyWMSTileSource.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 7/25/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+
+/** A bounding box for a specific CRS in that coordinate
+ system. This is part of the Web Map Server parser.
+ */
+@interface MaplyWMSLayerBoundingBox : NSObject
+
+/// Coordinate Reference System
+@property (nonatomic,strong,nullable) NSString *crs;
+
+/// Left side of the bounding box
+@property (nonatomic) double minx;
+/// Bottom of the bounding box
+@property (nonatomic) double miny;
+/// Right side of the bounding box
+@property (nonatomic) double maxx;
+/// Top of the bounding box
+@property (nonatomic) double maxy;
+
+/// Generate the coordinate system, if we can
+- (nullable MaplyCoordinateSystem *)buildCoordinateSystem;
+
+@end
+
+/** Style of a WMS layer as returned by GetCapabilities.
+ This is part of the Web Map Service parser.
+ */
+@interface MaplyWMSStyle : NSObject
+
+/// The name as returned by the service
+@property (nonatomic,strong,nullable) NSString *name;
+/// The title as returned by the service
+@property (nonatomic,strong,nullable) NSString *title;
+
+@end
+
+/** Description of a WMS layer as returned by a GetCapabilities call.
+ This is part of the Web Map Service parser.
+ */
+@interface MaplyWMSLayer : NSObject
+
+/// The name as returned by the service
+@property (nonatomic,strong,nullable) NSString *name;
+/// The title as returned by the service
+@property (nonatomic,strong,nullable) NSString *title;
+/// The abstract as returned by the service
+@property (nonatomic,strong,nullable) NSString *abstract;
+
+/// Coordinate reference systems supported by the layer
+@property (nonatomic,strong,nullable) NSArray *coordRefSystems;
+
+/// Styles we can choose
+@property (nonatomic,strong,nullable) NSArray *styles;
+
+/// Bounding boxes for zero or more of the CRS'
+@property (nonatomic,strong,nullable) NSArray *boundingBoxes;
+
+/// Lower left corner in longitude/latitude
+@property (nonatomic) MaplyCoordinate ll;
+/// Upper right corner in longitude/latitude
+@property (nonatomic) MaplyCoordinate ur;
+
+/// Try to build a coordinate system we understand
+- (nullable MaplyCoordinateSystem *)buildCoordSystem;
+
+/// Find the style with the given name
+- (nullable MaplyWMSStyle *)findStyle:(NSString *__nonnull)styleName;
+
+@end
+
+@class DDXMLDocument;
+
+/** Encapsulates the capabilities coming back from a WMS server.
+ We can query this to see what layers and coordinate systems are available.
+ Part of the Web Map Service parser.
+ */
+@interface MaplyWMSCapabilities : NSObject
+
+/// We can fetch the capabilities from this URL
++ (nonnull NSString *)CapabilitiesURLFor:(NSString *__nonnull)baseURL;
+
+/// The name as returned by the service
+@property (nonatomic,strong,nullable) NSString *name;
+/// The title as returned by the service
+@property (nonatomic,strong,nullable) NSString *title;
+
+/// Available formats (strings)
+@property (nonatomic,strong,nullable) NSArray *formats;
+
+/// Layers we can fetch from
+@property (nonatomic,strong,nullable) NSArray *layers;
+
+/// This constructor will initialize with an XML document that
+/// we've fetched from the server, presumably.
+- (nullable instancetype)initWithXML:(DDXMLDocument *__nonnull)xmlDoc;
+
+/// Look for a layer with the given name.
+- (nullable MaplyWMSLayer *)findLayer:(NSString *__nonnull)name;
+
+@end
+
+/** This is a MaplyTileSource that works with a remote
+ Web Map Service implementation. WMS is not the most
+ efficient way to access remote image data, but there
+ are still a few places that use it.
+ */
+@interface MaplyWMSTileSource : NSObject<MaplyTileInfoNew>
+
+/// Base URL for the Map Service
+@property (nonatomic,strong,nullable) NSString *baseURL;
+
+/// Capabilities describing the service
+@property (nonatomic,strong,nullable) MaplyWMSCapabilities *capabilities;
+
+/// Image type to request
+@property (nonatomic,strong,nullable) NSString *imageType;
+
+/// Layer we're grabbing
+@property (nonatomic,strong,nonnull) MaplyWMSLayer *layer;
+
+/// Optional style we're using
+@property (nonatomic,strong,nonnull) MaplyWMSStyle *style;
+
+/// Minimum zoom level we'll expect
+@property (nonatomic,readonly) int minZoom;
+/// Maximum zoom level we'll expect
+@property (nonatomic,readonly) int maxZoom;
+
+/// Tile size provided to caller
+@property (nonatomic,readonly) int tileSize;
+
+/// If set we'll ask for a transparent background from the server
+@property (nonatomic) bool transparent;
+
+/// Coordinate system (used to build URLs)
+@property (nonatomic,readonly,nonnull) MaplyCoordinateSystem *coordSys;
+
+/// If set, we'll cache the images locally (a good idea with WMS)
+@property (nonatomic,strong,nullable) NSString *cacheDir;
+
+/** Initialize with the parameters the WMS server is going to want.
+
+ @param baseURL The main URL we'll use to construct queries.
+
+ @param cap The capabilities as parsed from the service.
+
+ @param layer The layer we'll access. There can be multiple and it's
+ up to you to pick one.
+
+ @param style The style variant of the layer we want. Again there can
+ be multiple and it's up to you to pick.
+
+ @param coordSys The coordinate system we're expecting to work in.
+
+ @param minZoom The min zoom level we want. Note that WMS doesn't handle
+ this directly. Our tile source just controls what areas it
+ asks for based on the overall extents and the zoom levels.
+
+ @param maxZoom The max zoom level we'll query.
+ */
+- (nullable instancetype)initWithBaseURL:(NSString *__nonnull)baseURL capabilities:(MaplyWMSCapabilities *__nullable)cap layer:(MaplyWMSLayer *__nonnull)layer style:(MaplyWMSStyle *__nonnull)style coordSys:(MaplyCoordinateSystem *__nonnull)coordSys minZoom:(int)minZoom maxZoom:(int)maxZoom tileSize:(int)tileSize;
+
+@end
+
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyZoomGestureDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyZoomGestureDelegate.h
new file mode 100644
index 0000000..442a976
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MaplyZoomGestureDelegate.h
@@ -0,0 +1,31 @@
+/* MaplyZoomGestureDelegate.h
+ *
+ * Created by Jesse Crocker on 2/4/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+
+@interface MaplyZoomGestureDelegate : NSObject <UIGestureRecognizerDelegate>
+
+/// Minimum allowable zoom level
+@property (nonatomic,assign) float minZoom;
+/// Maximum allowable zoom level
+
+@property (nonatomic,assign) float maxZoom;
+
+//The gesture recognizer
+@property (nonatomic,strong) UIGestureRecognizer *gestureRecognizer;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapnikStyle.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapnikStyle.h
new file mode 100644
index 0000000..22e4cf0
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapnikStyle.h
@@ -0,0 +1,33 @@
+/*
+ * MapnikStyle.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Jesse Crocker, Trailbehind inc. on 3/31/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+#import <WhirlyGlobe/MapnikStyleRule.h>
+
+@interface MapnikStyle : NSObject
+
+@property (nonatomic, readonly) NSMutableArray *rules;
+@property (nonatomic, strong) NSString *name;
+@property (nonatomic, assign) BOOL filterModeFirst;
+@property (nonatomic, assign) float opacity;
+
+- (void)addRule:(MapnikStyleRule*)rule;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapnikStyleRule.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapnikStyleRule.h
new file mode 100644
index 0000000..f462857
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapnikStyleRule.h
@@ -0,0 +1,36 @@
+/*
+ * MapnikStyleRule.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Jesse Crocker, Trailbehind inc. on 3/31/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+@interface MapnikStyleRule : NSObject
+
+@property (nonatomic, strong) NSPredicate *filterPredicate;
+
+@property (nonatomic, assign) NSUInteger minScaleDenominator;
+@property (nonatomic, assign) NSUInteger maxScaleDenomitator;
+@property (nonatomic, assign) NSUInteger minZoom;
+@property (nonatomic, assign) NSUInteger maxZoom;
+
+@property (nonatomic, readonly) NSMutableArray *symbolizers;
+
+- (void)setFilter:(NSString*)filterExpression;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapnikStyleSet.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapnikStyleSet.h
new file mode 100644
index 0000000..86c54e7
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/MapnikStyleSet.h
@@ -0,0 +1,47 @@
+/*
+ * MapnikXmlStyle.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Jesse Crocker, Trailbehind inc. on 3/31/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#import <Foundation/Foundation.h>
+#import <WhirlyGlobe/MapboxVectorTiles.h>
+
+@class MaplyVectorStyleSettings;
+
+@interface MapnikStyleSet : NSObject <NSXMLParserDelegate, MaplyVectorStyleDelegate>
+
+@property (nonatomic, strong, nullable) MaplyVectorStyleSettings *tileStyleSettings;
+@property (nonatomic, strong, nullable) NSMutableDictionary *styleDictionary;
+@property (nonatomic, weak, nullable) NSObject<MaplyRenderControllerProtocol> *viewC;
+@property (nonatomic, readonly) BOOL parsing;
+@property (nonatomic, strong, nullable) UIColor *backgroundColor;
+@property (nonatomic, assign) NSInteger tileMaxZoom;
+@property (nonatomic, assign) NSInteger drawPriorityOffset;
+@property (nonatomic, assign) CGFloat alpha;
+
+- (nonnull instancetype)initForViewC:(NSObject<MaplyRenderControllerProtocol> *__nonnull)viewC;
+
+- (void)loadXmlFile:(NSString *__nonnull)filePath;
+- (void)loadXmlData:(NSData *__nonnull)docData;
+- (void)loadJsonData:(NSData *__nonnull)jsonData;
+- (void)loadJsonFile:(NSString*__nonnull)filePath;
+- (void)saveAsJSON:(NSString *__nonnull)filePath;
+- (void)generateStyles;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/NSData+Zlib.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/NSData+Zlib.h
new file mode 100644
index 0000000..4a28f18
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/NSData+Zlib.h
@@ -0,0 +1,37 @@
+/*
+ * NSData+Zlib.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 9/7/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+/** The NSData zlib category adds compress and uncompress methods to
+ NSData.
+ */
+@interface NSData(zlib)
+
+/// Return a compressed version of the data.
+- (NSData *) compressData;
+
+/// Return an uncompressed verison of the given data
+- (NSData *) uncompressGZip;
+
+/// Returns true if the data is zlib compressed
+- (BOOL)isCompressed;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/NSDictionary+StyleRules.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/NSDictionary+StyleRules.h
new file mode 100644
index 0000000..9c4ab96
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/NSDictionary+StyleRules.h
@@ -0,0 +1,33 @@
+//
+// NSDictionary+StyleRules.h
+// WhirlyGlobe-MaplyComponent
+//
+// Created by Jesse Crocker on 4/9/14.
+//
+//
+
+#import <Foundation/Foundation.h>
+
+@interface NSMutableDictionary (StyleRules)
+
+- (NSMutableArray*)styles;
+- (NSMutableArray*)rules;
+- (NSMutableArray*)symbolizers;
+- (NSMutableArray*)layers;
+- (NSString*)filter;
+- (void)setFilter:(NSString*)filter;
+- (NSString*)name;
+
+- (NSNumber*)minScaleDenom;
+- (void)setMinScaleDenom:(NSNumber*)num;
+- (NSNumber*)maxScaleDenom;
+- (void)setMaxScaleDenom:(NSNumber*)num;
+- (NSMutableDictionary*)parameters;
+
+@end
+
+// A function we can call to force the linker to bring in categories
+#ifdef __cplusplus
+extern "C"
+#endif
+void NSDictionaryStyleDummyFunc(void);
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/SLDExpressions.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/SLDExpressions.h
new file mode 100644
index 0000000..43a042d
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/SLDExpressions.h
@@ -0,0 +1,55 @@
+//
+// SLDExpressions.h
+// SLDTest
+//
+// Created by Ranen Ghosh on 2016-08-12.
+// Copyright 2016-2019 mousebird consulting.
+//
+
+#import <Foundation/Foundation.h>
+@class DDXMLNode;
+@class DDXMLElement;
+
+/** @brief Base class for elements derived from the ogc:expression abstract element.
+ @see http://schemas.opengis.net/filter/1.1.0/expr.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/filter/1.0.0/expr.xsd for SLD v1.0.0
+ */
+@interface SLDExpression : NSObject
+@property (nonatomic, strong) NSExpression * _Nonnull expression;
++ (BOOL)matchesElementNamed:(NSString * _Nonnull)elementName;
++ (SLDExpression * _Nullable)expressionForNode:(DDXMLNode * _Nonnull )node;
+@end
+
+
+/** @brief Class corresponding to the ogc:PropertyName element
+ @see http://schemas.opengis.net/filter/1.1.0/expr.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/filter/1.0.0/expr.xsd for SLD v1.0.0
+ */
+@interface SLDPropertyNameExpression : SLDExpression
+@property (nonatomic, strong) NSString * _Nonnull propertyName;
+- (_Nullable id)initWithElement:(DDXMLElement * _Nonnull)element;
+@end
+
+/** @brief Class corresponding to the ogc:Literal element
+ @see http://schemas.opengis.net/filter/1.1.0/expr.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/filter/1.0.0/expr.xsd for SLD v1.0.0
+ */
+@interface SLDLiteralExpression : SLDExpression
+@property (nonatomic, strong) id _Nonnull literal;
+- (_Nullable id)initWithElement:(DDXMLElement * _Nonnull)element;
+@end
+
+/** @brief Class corresponding to the ogc:BinaryOperatorType elements
+ @see http://schemas.opengis.net/filter/1.1.0/expr.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/filter/1.0.0/expr.xsd for SLD v1.0.0
+ */
+@interface SLDBinaryOperatorExpression : SLDExpression
+
+@property (nonatomic, strong) NSString * _Nonnull elementName;
+
+@property (nonatomic, strong) SLDExpression * _Nonnull leftExpression;
+@property (nonatomic, strong) SLDExpression * _Nonnull rightExpression;
+
+- (_Nullable id)initWithElement:(DDXMLElement * _Nonnull)element;
+@end
+
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/SLDOperators.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/SLDOperators.h
new file mode 100644
index 0000000..746695e
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/SLDOperators.h
@@ -0,0 +1,101 @@
+//
+// SLDOperators.h
+// SLDTest
+//
+// Created by Ranen Ghosh on 2016-08-12.
+// Copyright 2016-2019 mousebird consulting.
+//
+
+#import <Foundation/Foundation.h>
+#import <WhirlyGlobe/SLDExpressions.h>
+
+/** @brief Base class for elements of ogc:comparisonOps or ogc:logicOps.
+
+ Elements of ogc:spatialOps are not supported.
+ @see http://schemas.opengis.net/filter/1.1.0/filter.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/filter/1.0.0/filter.xsd for SLD v1.0.0
+ */
+@interface SLDOperator : NSObject
+@property (nonatomic, strong) NSPredicate * _Nonnull predicate;
++ (BOOL)matchesElementNamed:(NSString * _Nonnull)elementName;
++ (SLDOperator * _Nullable)operatorForNode:(DDXMLNode * _Nonnull )node;
+@end
+
+
+/** @brief Class corresponding to the ogc:BinaryComparisonOpType elements
+ @see http://schemas.opengis.net/filter/1.1.0/expr.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/filter/1.0.0/expr.xsd for SLD v1.0.0
+ */
+@interface SLDBinaryComparisonOperator : SLDOperator
+
+@property (nonatomic, assign) BOOL matchCase;
+@property (nonatomic, strong) NSString * _Nonnull elementName;
+
+@property (nonatomic, strong) SLDExpression * _Nonnull leftExpression;
+@property (nonatomic, strong) SLDExpression * _Nonnull rightExpression;
+
+
+- (_Nullable id)initWithElement:(DDXMLElement * _Nonnull)element;
+
+@end
+
+
+@interface SLDIsNullOperator : SLDOperator
+
+@property (nonatomic, strong) SLDExpression * _Nonnull subExpression;
+
+- (_Nullable id)initWithElement:(DDXMLElement * _Nonnull)element;
+
+@end
+
+
+@interface SLDIsLikeOperator : SLDOperator
+
+@property (nonatomic, strong, nullable) NSString *wildCardStr;
+@property (nonatomic, strong, nullable) NSString *singleCharStr;
+@property (nonatomic, strong, nullable) NSString *escapeCharStr;
+@property (nonatomic, assign) BOOL matchCase;
+@property (nonatomic, strong) SLDPropertyNameExpression * _Nonnull propertyExpression;
+@property (nonatomic, strong) SLDLiteralExpression * _Nonnull literalExpression;
+
+- (_Nullable id)initWithElement:(DDXMLElement * _Nonnull)element;
+
+@end
+
+@interface SLDIsBetweenOperator : SLDOperator
+
+@property (nonatomic, strong) SLDExpression * _Nonnull subExpression;
+@property (nonatomic, strong) SLDExpression * _Nonnull lowerBoundaryExpression;
+@property (nonatomic, strong) SLDExpression * _Nonnull upperBoundaryExpression;
+
+- (_Nullable id)initWithElement:(DDXMLElement * _Nonnull)element;
+
+@end
+
+
+
+/** @brief Class corresponding to the ogc:Not element
+ @see http://schemas.opengis.net/filter/1.1.0/expr.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/filter/1.0.0/expr.xsd for SLD v1.0.0
+ */
+@interface SLDNotOperator : SLDOperator
+
+@property (nonatomic, strong) SLDOperator * _Nonnull subOperator;
+
+- (_Nullable id)initWithElement:(DDXMLElement * _Nonnull)element;
+
+@end
+
+/** @brief Class corresponding to the ogc:BinaryLogicOpType elements
+ @see http://schemas.opengis.net/filter/1.1.0/expr.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/filter/1.0.0/expr.xsd for SLD v1.0.0
+ */
+@interface SLDLogicalOperator : SLDOperator
+
+@property (nonatomic, strong) NSString * _Nonnull elementName;
+@property (nonatomic, strong) NSArray<SLDOperator *> * _Nonnull subOperators;
+
+- (_Nullable id)initWithElement:(DDXMLElement * _Nonnull)element;
+
+@end
+
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/SLDStyleSet.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/SLDStyleSet.h
new file mode 100644
index 0000000..4e705cf
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/SLDStyleSet.h
@@ -0,0 +1,119 @@
+//
+// SLDStyleSet.h
+// SLDTest
+//
+// Created by Ranen Ghosh on 2016-08-12.
+// Copyright 2016-2019 mousebird consulting.
+//
+
+#import <Foundation/Foundation.h>
+#import <WhirlyGlobe/MapboxVectorTiles.h>
+
+/** @brief Class corresponding to the sld:NamedLayer element
+ @see http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+ */
+@interface SLDNamedLayer : NSObject
+
+@property (nonatomic, strong) NSString * _Nullable name;
+@property (nonatomic, strong) NSArray * _Nullable userStyles;
+
+@end
+
+/** @brief Class corresponding to the sld:UserStyle element
+ @see http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+ */
+@interface SLDUserStyle : NSObject
+
+@property (nonatomic, strong) NSString * _Nullable name;
+@property (nonatomic, strong) NSArray * _Nullable featureTypeStyles;
+
+@end
+
+/** @brief Class corresponding to the se:FeatureTypeStyle element
+ @see http://schemas.opengis.net/se/1.1.0/FeatureStyle.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+ */
+@interface SLDFeatureTypeStyle : NSObject
+
+@property (nonatomic, strong) NSArray * _Nullable rules;
+
+@end
+
+/** @brief Class corresponding to the se:Rule element
+ @see http://schemas.opengis.net/se/1.1.0/FeatureStyle.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+ */
+@interface SLDRule : NSObject
+
+@property (nonatomic, strong) NSArray * _Nullable filters;
+@property (nonatomic, strong) NSArray * _Nullable elseFilters;
+
+@property (nonatomic, strong) NSNumber * _Nullable minScaleDenominator;
+@property (nonatomic, strong) NSNumber * _Nullable maxScaleDenominator;
+@property (nonatomic, strong) NSNumber * _Nullable relativeDrawPriority;
+
+@property (nonatomic, strong) NSMutableArray * _Nullable symbolizers;
+
+@end
+
+
+
+@class SLDOperator;
+@class SLDExpression;
+
+/** @brief Class corresponding to the ogc:Filter element
+ @see http://schemas.opengis.net/filter/1.1.0/filter.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/filter/1.0.0/filter.xsd for SLD v1.0.0
+ */
+@interface SLDFilter : NSObject
+
+@property (nonatomic, strong) SLDOperator * _Nonnull sldOperator;
+
+@end
+
+/** @brief Class corresponding to the sld:StyledLayerDescriptor element
+
+ The sld:StyledLayerDescriptor element is the root element of the Styled Layer Descriptor document.
+
+ Implements the MaplyVectorStyleDelegate protocol for matching and applying styles to vector objects.
+ @see http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+ @see MaplyVectorStyleDelegate
+ */
+@interface SLDStyleSet : NSObject <MaplyVectorStyleDelegate>
+
+@property (nonatomic, assign) BOOL useLayerNames;
+@property (nonatomic, weak, nullable) NSObject<MaplyRenderControllerProtocol> *viewC;
+@property (nonatomic, strong, nullable) MaplyVectorStyleSettings *tileStyleSettings;
+
+/**
+ Constructs a SLDStyleSet object.
+
+ After constructing the SLDStyleSet object, call loadSldURL: or loadSldData:baseURL: to parse the desired SLD document tree and create the corresponding symbolizers.
+
+ @param viewC The map or globe view controller.
+
+ @param useLayerNames Whether to use names of NamedLayer elements as a criteria in matching styles.
+
+ @param relativeDrawPriority The z-order relative to other vector features. This will be incremented internally for each style rule, so if you have multiple SLDStyleSets, leave some space between the relativeDrawPriority of each.
+ */
+- (id _Nullable)initWithViewC:(NSObject<MaplyRenderControllerProtocol> * _Nonnull)viewC useLayerNames:(BOOL)useLayerNames relativeDrawPriority:(int)relativeDrawPriority;
+
+- (void)loadSldURL:(NSURL *__nullable)url;
+- (void)loadSldData:(NSData *__nonnull)sldData baseURL:(NSURL *__nonnull)baseURL;
+
+@end
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/SLDSymbolizers.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/SLDSymbolizers.h
new file mode 100644
index 0000000..78e2acb
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/SLDSymbolizers.h
@@ -0,0 +1,82 @@
+//
+// SLDSymbolizers.h
+// SLDTest
+//
+// Created by Ranen Ghosh on 2016-08-12.
+// Copyright 2016-2019 mousebird consulting.
+//
+
+#import <Foundation/Foundation.h>
+@class DDXMLNode;
+@class DDXMLElement;
+#import <WhirlyGlobe/MaplyVectorTileStyle.h>
+
+/** @brief Base class for Symbolizer elements
+ @see http://schemas.opengis.net/se/1.1.0/Symbolizer.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+ */
+@interface SLDSymbolizer : NSObject
+
+/**
+ Returns whether this class can parse the symbolizer corresponding to the provided element name.
+
+ Each subclass matches different symbolizer elements.
+ */
++ (BOOL)matchesSymbolizerNamed:(NSString * _Nonnull)symbolizerName;
+
+/**
+ Produces MaplyVectorTileStyle objects for an SLD Symbolizer element
+
+ Parses the XML subtree and returns an array of corresponding MaplyVectorTileStyle objects.
+
+ @param element The XML element corresponding to a symbolizer
+
+ @param tileStyleSettings The base MaplyVectorStyleSettings settings to apply.
+
+ @param viewC The map or globe view controller.
+
+ @param minScaleDenom If non-null, the minimum map scale at which to apply any constructed symbolizer.
+
+ @param maxScaleDenom If non-null, the maximum map scale at which to apply any constructed symbolizer.
+
+ @param relativeDrawPriority The z-order relative to other vector features.
+
+ @param baseURL The base URL from which external resources (e.g. images) will be located.
+
+ @return An array of MaplyVectorTileStyle objects corresponding to the particular XML element.
+ @see MaplyVectorTileStyle
+ @see MaplyVectorStyleSettings
+ */
++ (NSArray<MaplyVectorTileStyle *> * _Nullable) maplyVectorTileStyleWithElement:(DDXMLElement * _Nonnull)element tileStyleSettings:(MaplyVectorStyleSettings * _Nonnull)tileStyleSettings viewC:(NSObject<MaplyRenderControllerProtocol> * _Nonnull)viewC minScaleDenom:(NSNumber * _Nonnull)minScaleDenom maxScaleDenom:(NSNumber * _Nonnull)maxScaleDenom relativeDrawPriority:(int)relativeDrawPriority crossSymbolizerParams:(NSMutableDictionary * _Nonnull)crossSymbolizerParams baseURL:(NSURL * _Nonnull)baseURL;
+@end
+
+/** @brief Class corresponding to the LineSymbolizer element
+ @see http://schemas.opengis.net/se/1.1.0/Symbolizer.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+ */
+@interface SLDLineSymbolizer : SLDSymbolizer
+@end
+
+/** @brief Class corresponding to the PolygonSymbolizer element
+ @see http://schemas.opengis.net/se/1.1.0/Symbolizer.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+ */
+@interface SLDPolygonSymbolizer : SLDSymbolizer
+@end
+
+/** @brief Class corresponding to the PointSymbolizer element
+ @see http://schemas.opengis.net/se/1.1.0/Symbolizer.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+ */
+@interface SLDPointSymbolizer : SLDSymbolizer
+@end
+
+/** @brief Class corresponding to the TextSymbolizer element
+ @see http://schemas.opengis.net/se/1.1.0/Symbolizer.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+ */
+@interface SLDTextSymbolizer : SLDSymbolizer
+@end
+
+
+
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/SLDWellKnownMarkers.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/SLDWellKnownMarkers.h
new file mode 100644
index 0000000..cdb4cc8
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/SLDWellKnownMarkers.h
@@ -0,0 +1,23 @@
+//
+// SLDWellKnownMarkers.h
+// SLDTest
+//
+// Created by Ranen Ghosh on 2016-08-23.
+// Copyright 2016-2019 mousebird consulting.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+/**
+ Class for generating images corresponding to WellKnownName elements.
+
+ Each static method uses low-level Core Graphics calls to generate an appropriate UIImage object.
+ @see http://schemas.opengis.net/se/1.1.0/Symbolizer.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+*/
+@interface SLDWellKnownMarkers : NSObject
+
++ (UIImage *)imageWithName:(NSString *)wellKnownName strokeColor:(UIColor *)strokeColor fillColor:(UIColor *)fillColor size:(int)size;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/WGCoordinate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/WGCoordinate.h
new file mode 100644
index 0000000..8b79f7b
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/WGCoordinate.h
@@ -0,0 +1,34 @@
+/*
+ * WGCoordinate.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 9/17/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+/// WhirlyGlobe just takes geo coordinates.
+/// This contains lon and lat values in the x and y fields.
+typedef MaplyCoordinate WGCoordinate;
+
+/// Construct a WGCoordinate with longitude and latitude values in degrees
+#if __cplusplus
+extern "C" {
+#endif
+ WGCoordinate WGCoordinateMakeWithDegrees(float degLon,float degLat);
+#if __cplusplus
+}
+#endif
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/WhirlyGlobe.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/WhirlyGlobe.h
new file mode 100644
index 0000000..4fc8123
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/WhirlyGlobe.h
@@ -0,0 +1,121 @@
+//
+// WhirlyGlobeMaplyComponent.h
+// WhirlyGlobeMaplyComponent
+//
+// Created by Steve Gifford on 6/29/16.
+// Copyright © 2016-2019 mousebird consulting.
+//
+
+#import <UIKit/UIKit.h>
+
+//! Project version number for WhirlyGlobeMaplyComponent.
+FOUNDATION_EXPORT double WhirlyGlobeMaplyComponentVersionNumber;
+
+//! Project version string for WhirlyGlobeMaplyComponent.
+FOUNDATION_EXPORT const unsigned char WhirlyGlobeMaplyComponentVersionString[];
+
+// In this header, you should import all the public headers of your framework using statements like #import <WhirlyGlobeMaplyComponent/PublicHeader.h>
+
+#import <WhirlyGlobe/GeographicLib_ObjC.h>
+#import <WhirlyGlobe/GeoJSONSource.h>
+#import <WhirlyGlobe/GlobeDoubleTapDelegate.h>
+#import <WhirlyGlobe/GlobeDoubleTapDragDelegate.h>
+#import <WhirlyGlobe/GlobePanDelegate.h>
+#import <WhirlyGlobe/GlobePinchDelegate.h>
+#import <WhirlyGlobe/GlobeRotateDelegate.h>
+#import <WhirlyGlobe/GlobeTapDelegate.h>
+#import <WhirlyGlobe/GlobeTiltDelegate.h>
+#import <WhirlyGlobe/GlobeTwoFingerTapDelegate.h>
+#import <WhirlyGlobe/MapboxVectorInterpreter.h>
+#import <WhirlyGlobe/MapboxVectorStyleSet.h>
+#import <WhirlyGlobe/MapboxVectorTiles.h>
+#import <WhirlyGlobe/Maply3DTouchPreviewDatasource.h>
+#import <WhirlyGlobe/Maply3dTouchPreviewDelegate.h>
+#import <WhirlyGlobe/MaplyActiveObject.h>
+#import <WhirlyGlobe/MaplyAnnotation.h>
+#import <WhirlyGlobe/MaplyAtmosphere.h>
+#import <WhirlyGlobe/MaplyBaseViewController.h>
+#import <WhirlyGlobe/MaplyBillboard.h>
+#import <WhirlyGlobe/MaplyBridge.h>
+#import <WhirlyGlobe/MaplyBridge.h>
+#import <WhirlyGlobe/MaplyCluster.h>
+#import <WhirlyGlobe/MaplyColorRampGenerator.h>
+#import <WhirlyGlobe/MaplyComponent.h>
+#import <WhirlyGlobe/MaplyComponent.h>
+#import <WhirlyGlobe/MaplyComponentObject.h>
+#import <WhirlyGlobe/MaplyControllerLayer.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+#import <WhirlyGlobe/MaplyDoubleTapDelegate.h>
+#import <WhirlyGlobe/MaplyDoubleTapDragDelegate.h>
+#import <WhirlyGlobe/MaplyGeomBuilder.h>
+#import <WhirlyGlobe/MaplyGeomModel.h>
+#import <WhirlyGlobe/MaplyGlobeRenderController.h>
+#import <WhirlyGlobe/MaplyIconManager.h>
+#import <WhirlyGlobe/MaplyImageTile.h>
+#import <WhirlyGlobe/MaplyLabel.h>
+#import <WhirlyGlobe/MaplyLight.h>
+#import <WhirlyGlobe/MaplyLocationTracker.h>
+#import <WhirlyGlobe/MaplyMarker.h>
+#import <WhirlyGlobe/MaplyMatrix.h>
+#import <WhirlyGlobe/MaplyMBTileFetcher.h>
+#import <WhirlyGlobe/MaplyMoon.h>
+#import <WhirlyGlobe/MaplyPanDelegate.h>
+#import <WhirlyGlobe/MaplyParticleSystem.h>
+#import <WhirlyGlobe/MaplyPinchDelegate.h>
+#import <WhirlyGlobe/MaplyPoints.h>
+#import <WhirlyGlobe/MaplyQuadImageFrameLoader.h>
+#import <WhirlyGlobe/MaplyQuadImageLoader.h>
+#import <WhirlyGlobe/MaplyQuadLoader.h>
+#import <WhirlyGlobe/MaplyQuadPagingLoader.h>
+#import <WhirlyGlobe/MaplyQuadSampler.h>
+#import <WhirlyGlobe/MaplyRemoteTileFetcher.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+#import <WhirlyGlobe/MaplyRenderTarget.h>
+#import <WhirlyGlobe/MaplyRotateDelegate.h>
+#import <WhirlyGlobe/MaplyScreenLabel.h>
+#import <WhirlyGlobe/MaplyScreenMarker.h>
+#import <WhirlyGlobe/MaplyScreenObject.h>
+#import <WhirlyGlobe/MaplyShader.h>
+#import <WhirlyGlobe/MaplyShape.h>
+#import <WhirlyGlobe/MaplySharedAttributes.h>
+#import <WhirlyGlobe/MaplySimpleTileFetcher.h>
+#import <WhirlyGlobe/MaplyStarsModel.h>
+#import <WhirlyGlobe/MaplySticker.h>
+#import <WhirlyGlobe/MaplySun.h>
+#import <WhirlyGlobe/MaplyTapDelegate.h>
+#import <WhirlyGlobe/MaplyTapMessage.h>
+#import <WhirlyGlobe/MaplyTexture.h>
+#import <WhirlyGlobe/MaplyTextureBuilder.h>
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplyTouchCancelAnimationDelegate.h>
+#import <WhirlyGlobe/MaplyTwoFingerTapDelegate.h>
+#import <WhirlyGlobe/MaplyUpdateLayer.h>
+#import <WhirlyGlobe/MaplyVariableTarget.h>
+#import <WhirlyGlobe/MaplyVectorObject.h>
+#import <WhirlyGlobe/MaplyVectorStyle.h>
+#import <WhirlyGlobe/MaplyVectorStyleSimple.h>
+#import <WhirlyGlobe/MaplyVectorTileLineStyle.h>
+#import <WhirlyGlobe/MaplyVectorTileMarkerStyle.h>
+#import <WhirlyGlobe/MaplyVectorTilePolygonStyle.h>
+#import <WhirlyGlobe/MaplyVectorTileStyle.h>
+#import <WhirlyGlobe/MaplyVectorTileTextStyle.h>
+#import <WhirlyGlobe/MaplyVertexAttribute.h>
+#import <WhirlyGlobe/MaplyViewController.h>
+#import <WhirlyGlobe/MaplyViewTracker.h>
+#import <WhirlyGlobe/MaplyWMSTileSource.h>
+#import <WhirlyGlobe/MaplyZoomGestureDelegate.h>
+#import <WhirlyGlobe/MapnikStyle.h>
+#import <WhirlyGlobe/MapnikStyleRule.h>
+#import <WhirlyGlobe/MapnikStyleSet.h>
+#import <WhirlyGlobe/NSData+Zlib.h>
+#import <WhirlyGlobe/NSDictionary+StyleRules.h>
+#import <WhirlyGlobe/SLDExpressions.h>
+#import <WhirlyGlobe/SLDOperators.h>
+#import <WhirlyGlobe/SLDStyleSet.h>
+#import <WhirlyGlobe/SLDSymbolizers.h>
+#import <WhirlyGlobe/SLDWellKnownMarkers.h>
+#import <WhirlyGlobe/WGCoordinate.h>
+#import <WhirlyGlobe/WhirlyGlobeComponent.h>
+#import <WhirlyGlobe/WhirlyGlobeComponent.h>
+#import <WhirlyGlobe/WhirlyGlobeViewController.h>
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/WhirlyGlobeComponent.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/WhirlyGlobeComponent.h
new file mode 100644
index 0000000..babfdf7
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/WhirlyGlobeComponent.h
@@ -0,0 +1,23 @@
+/*
+ * WhirlyGlobeComponent.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 7/21/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyComponent.h>
+#import <WhirlyGlobe/MaplyGlobeRenderController.h>
+#import <WhirlyGlobe/WhirlyGlobeViewController.h>
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/WhirlyGlobeViewController.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/WhirlyGlobeViewController.h
new file mode 100644
index 0000000..f2e3b82
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Headers/WhirlyGlobeViewController.h
@@ -0,0 +1,809 @@
+/*
+ * WhirlyGlobeViewController.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 7/21/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyGlobeRenderController.h>
+#import <WhirlyGlobe/MaplyBaseViewController.h>
+
+@class WGViewControllerLayer;
+@class WhirlyGlobeViewController;
+
+/**
+ An animation delegate that can be set on a WhirlyGlobeViewController to control the view over time.
+
+ Filling out these methods will get you animation callbacks at the proper time to control position, heading, tilt, and height on a frame basis.
+
+ You pass the resulting object in to
+ */
+@protocol WhirlyGlobeViewControllerAnimationDelegate <NSObject>
+
+/**
+ This method is called when the animation starts.
+
+ At the animation start we collect up the various parameters of the current visual view state and pas them in via the startState. You probably want to keep track of this for later.
+
+ @param viewC The view controller doing the animation.
+
+ @param startState The starting point for the visual view animation. Cache this somewhere for your own interpolation.
+
+ @param startTime When the animation starts (e.g. now)
+
+ @param endTime When the animation ends. This is an absolute value.
+ */
+- (void)globeViewController:(WhirlyGlobeViewController *__nonnull)viewC startState:(WhirlyGlobeViewControllerAnimationState *__nonnull)startState startTime:(NSTimeInterval)startTime endTime:(NSTimeInterval)endTime;
+
+/**
+ This method is called at the beginning of every frame draw to position the viewer.
+
+ This is the method that does all the work. You need to fill out the returned WhirlyGlobeViewControllerAnimationState according to whatever interpolation your'e doing based on the currentTime.
+
+ @param viewC The view controller doing the animation.
+
+ @param currentTime The time for this frame. Use this rather than calculating the time yourself.
+
+ @return The WhirlyGlobeViewControllerAnimationState expressing where you want the viewer to be and where they are looking.
+ */
+- (nonnull WhirlyGlobeViewControllerAnimationState *)globeViewController:(WhirlyGlobeViewController *__nonnull)viewC stateForTime:(NSTimeInterval)currentTime;
+
+@optional
+
+/**
+ This method is called at the end of the animation.
+
+ The globe view controller calls this method when the animation is finished. Do your cleanup here if need be.
+
+ @param viewC The globe view controller.
+ */
+- (void)globeViewControllerDidFinishAnimation:(WhirlyGlobeViewController *__nonnull)viewC;
+
+@end
+
+/**
+ A simple animation delegate for moving the globe around.
+
+ The animation delegate support provides a lot of flexibility. This version just provides all the standard fields and interpolates from beginning to end.
+ */
+@interface WhirlyGlobeViewControllerSimpleAnimationDelegate : NSObject <WhirlyGlobeViewControllerAnimationDelegate>
+
+/// Initialize with an animation state to copy
+- (nonnull instancetype)initWithState:(WhirlyGlobeViewControllerAnimationState *__nonnull)endState;
+
+/// Location at the end of the animation
+@property (nonatomic) MaplyCoordinateD loc;
+
+/// Heading at the end of the animation
+@property (nonatomic) double heading;
+
+/// Height at the end of the animation
+@property (nonatomic) double height;
+
+/// Tilt at the end of the animation
+@property (nonatomic) double tilt;
+
+/// Roll at the end of the animation
+@property (nonatomic) double roll;
+
+/// Globe center at the end of the animation
+@property (nonatomic) CGPoint globeCenter;
+
+/// Custom easing
+@property (readwrite,copy) ZoomEasingBlock _Nullable zoomEasing;
+
+@end
+
+/**
+ Globe View Controller Delegate protocol for getting back selection and tap events.
+
+ Fill out the methods in this protocol and assign yourself as a delegate in the WhirlyGlobeViewController to get selection and tap events.
+ */
+@protocol WhirlyGlobeViewControllerDelegate <NSObject>
+
+@optional
+/**
+ Called when the user taps on or near an object.
+
+ You're given the object you passed in originally, such as a MaplyScreenMarker. Most of those objects have userObject properties, which is a good place to stash your own data.
+
+ @param viewC The view controller where the user selected something.
+
+ @param selectedObj The Maply object they selected.
+ */
+- (void)globeViewController:(WhirlyGlobeViewController *__nonnull)viewC didSelect:(NSObject *__nonnull)selectedObj;
+
+/**
+ Called when the user taps on or near an object.
+
+ This will call back with the closest object it finds near (or on) where the user tapped.
+
+ You're given the object you passed in originally, such as a MaplyScreenMarker.
+
+ This version is called preferentially if it exists. Otherwise globeViewController:didSelect: is called if it exists.
+
+ @param viewC The view controller where the user selected something.
+
+ @param selectedObj The Maply object they selected.
+
+ @param coord The location (geographic lon/lat in radians) where the user tapped.
+
+ @param screenPt The location on screen where the user tapped.
+ */
+- (void)globeViewController:(WhirlyGlobeViewController *__nonnull)viewC didSelect:(NSObject *__nonnull)selectedObj atLoc:(MaplyCoordinate)coord onScreen:(CGPoint)screenPt;
+
+/**
+ Called when the user taps on or near one or more objects. Returns them all.
+
+ This method is called when the
+
+ @param viewC The view controller where the user selected something.
+
+ @param selectedObjs A list of
+
+ @param coord The location (geographic lon/lat in radians) where the user tapped.
+
+ @param screenPt The location on screen where the user tapped.
+ */
+- (void)globeViewController:(WhirlyGlobeViewController *__nonnull)viewC allSelect:(NSArray *__nonnull)selectedObjs atLoc:(MaplyCoordinate)coord onScreen:(CGPoint)screenPt;
+
+/**
+ Called when the user taps outside the globe.
+ */
+- (void)globeViewControllerDidTapOutside:(WhirlyGlobeViewController *__nonnull)viewC;
+
+/**
+ Called when the user taps the globe but doesn't select anything.
+
+ @param viewC The view controller where the user selected something.
+
+ @param coord The location (geographic lon/lat in radians) where the user tapped.
+ */
+- (void)globeViewController:(WhirlyGlobeViewController *__nonnull)viewC didTapAt:(MaplyCoordinate)coord;
+
+/**
+ This is an older method called when some layers load.
+
+ Certain image layers call this method when they finish loading. More modern layers don't, so don't rely on this.
+ */
+- (void)globeViewController:(WhirlyGlobeViewController *__nonnull)viewC layerDidLoad:(WGViewControllerLayer *__nonnull)layer;
+
+/**
+ Called when the globe starts moving.
+
+ @param viewC The globe view controller.
+
+ @param userMotion Set if this is motion being caused by the user, rather than a call to set location.
+
+ This is called when something (probably the user) starts moving the globe.
+ */
+- (void)globeViewControllerDidStartMoving:(WhirlyGlobeViewController *__nonnull)viewC userMotion:(bool)userMotion;
+
+/**
+ Called when the globe stops moving.
+
+ This is called when the globe stops moving. It passes in the corners of the current viewspace.
+
+ @param viewC The globe view controller.
+
+ @param userMotion Set if this is motion being caused by the user, rather than a call to set location.
+
+ @param corners An array of length 4 containing the corners of the view space (lower left, lower right, upper right, upper left). If any of those corners does not intersect the globe (think zoomed out), its values are set to MAXFLOAT.
+ */
+- (void)globeViewController:(WhirlyGlobeViewController *__nonnull)viewC didStopMoving:(MaplyCoordinate *__nonnull)corners userMotion:(bool)userMotion;
+
+/**
+ Called when an animation that knows where it's going to stop start ups.
+
+ This is called when we know where the globe will stop. It passes in the corners of that future viewspace.
+
+ @param viewC The globe view controller.
+
+ @param corners An array of length 4 containing the corners of the view space (lower left, lower right, upper right, upper left). If any of those corners does not intersect the globe (think zoomed out), its values are set to MAXFLOAT.
+
+ @param userMotion Set if this is motion being caused by the user, rather than a call to set location.
+ */
+- (void)globeViewController:(WhirlyGlobeViewController *__nonnull)viewC willStopMoving:(MaplyCoordinate *__nonnull)corners userMotion:(bool)userMotion;
+
+/**
+ Called whenever the viewpoint moves.
+
+ This is called whenever the viewpoint moves. That includes user motion as well as animations.
+
+ It may be triggered as often as every frame. If that's a problem, use the globeViewController:didStopMoving:userMotion: or globeViewController:willStopMoving:userMotion: calls.
+
+ @param viewC The globe view controller.
+
+ @param corners An array of length 4 containing the corners of the view space (lower left, lower right, upper right, upper left). If any of those corners does not intersect the globe (think zoomed out), its values are set to MAXFLOAT.
+ */
+- (void)globeViewController:(WhirlyGlobeViewController *__nonnull)viewC didMove:(MaplyCoordinate *__nonnull)corners;
+
+@end
+
+/**
+ This view controller implements a 3D interactive globe.
+
+ This is the main entry point for displaying a globe. Create one of these, fill it with data and let your users mess around with it.
+
+ You can display a variety of features on the globe, including tiled base maps (MaplyQuadImageTilesLayer), vectors (MaplyVectorObject), shapes (MaplyShape), and others. Check out the add calls in the MaplyBaseViewController for details.
+
+ To get selection and tap callbacks, fill out the WhirlyGlobeViewControllerDelegate and assign the delegate.
+
+ Most of the functionality is shared with MaplyBaseViewController. Be sure to look in there first.
+ */
+@interface WhirlyGlobeViewController : MaplyBaseViewController
+
+/**
+ If set, keep north facing upward on the screen as the user moves around.
+
+ Off by default.
+ */
+@property(nonatomic,assign) bool keepNorthUp;
+
+/**
+ Turn the pan gesture recognizer on and off
+
+ On by default.
+ */
+@property(nonatomic,assign) bool panGesture;
+
+/**
+ Turn the pinch (zoom) gesture recognizer on and off
+
+ On by default.
+ */
+@property(nonatomic,assign) bool pinchGesture;
+
+/**
+ Turn the rotate globe functionality for pinch gesture gesture recognizer on and off
+
+ On by default.
+ */
+@property(nonatomic,assign) bool zoomAroundPinch;
+
+/**
+ Turn the rotate gesture recognizer on and off
+
+ On by default.
+ */
+@property(nonatomic,assign) bool rotateGesture;
+
+/**
+ Turn the tilt gesture recognizer on and off
+
+ Off by default.
+ */
+@property(nonatomic,assign) bool tiltGesture;
+
+/**
+ Turn the double tap to zoom gesture recognizer on and off
+
+ On by default.
+ */
+@property(nonatomic,assign) bool doubleTapZoomGesture;
+
+/**
+ Turn the 2 finger tap to zoom out gesture recognizer on and off
+
+ On by default.
+ */
+@property(nonatomic,assign) bool twoFingerTapGesture;
+
+/**
+ Turn on the double tap and drag gesture to zoom in and out.
+
+ On by default.
+ */
+@property(nonatomic,assign) bool doubleTapDragGesture;
+
+/**
+ If set, we use a modified pan gesture recognizer to play nice
+ with the scroll view. For the UIScrollView object, set clipsToBounds,
+ pagingEnabled, and delaysContentTouches to YES, and set scrollEnabled
+ and canCancelContentTouches to NO. Add swipe gesture recognizers
+ to the scroll view to control paging, and call
+ requirePanGestureRecognizerToFailForGesture: for each.
+
+ Off by default.
+ */
+@property(nonatomic,assign) bool inScrollView;
+
+
+/**
+ If set, we'll automatically move to wherever the user tapped.
+
+ When on we'll move the current location to wherever the user tapped if they tapped the globe. That's true for selection as well. On by default.
+ */
+@property(nonatomic,assign) bool autoMoveToTap;
+
+/**
+ Delegate for the selection and tap events.
+
+ Fill in the WhirlyGlobeViewControllerDelegate protocol, assign the object here and you'll get selection and tap events.
+ */
+@property(nonatomic,weak,nullable) NSObject<WhirlyGlobeViewControllerDelegate> *delegate;
+
+/**
+ Current viewer height above terrain.
+
+ This is the height from with the viewer is viewing the globe. Values range from minHeight to maxHeight. Smaller is closer. See getZoomLimitsMin:max: for values. The display units are based on a globe with a radius of 1.0.
+ */
+@property (nonatomic,assign) float height;
+
+/**
+ Tilt in radians. 0 is looking straight down (the default). PI/2 is looking toward the horizon.
+ */
+@property(nonatomic,assign) float tilt;
+
+/**
+ If set, the globe will be centered to this point on the screen.
+ */
+@property(nonatomic,assign) CGPoint globeCenter;
+
+/**
+ The current rotation away from north.
+
+ If keepNorthUp is set this is always 0.
+ */
+@property(nonatomic,assign) float heading;
+
+/**
+ The current roll around the axis pointed out of the user's nose.
+ */
+@property (nonatomic,assign) double roll;
+
+/**
+ Returns the closest a viewer is allowed to get to the map surface.
+
+ @return FLT_MIN if there's no pinchDelegate set
+ */
+- (float)getZoomLimitsMin;
+
+/**
+ Returns the farthest away a viewer is allowed to get from the map surface
+
+ @return FLT_MIN if there's no pinchDelegate set
+ */
+- (float)getZoomLimitsMax;
+
+/**
+ Return the zoom limits for the globe.
+
+ @param minHeight The closest a viewer is allowed to get to the globe surface.
+
+ @param maxHeight The farthest away a viewer is allowed to get from the globe surface.
+ */
+- (void)getZoomLimitsMin:(float *__nonnull)minHeight max:(float *__nonnull)maxHeight;
+
+/**
+ Set the zoom limits for the globe.
+
+ @param minHeight The closest a viewer is allowed to get to the globe surface.
+
+ @param maxHeight The farthest away a viewer is allowed to get from the globe surface.
+ */
+- (void)setZoomLimitsMin:(float)minHeight max:(float)maxHeight;
+
+/**
+ How much we zoom in or out by when the user double taps or two finger taps.
+
+ This sets the factor we'll use to zoom in by (e.g. *2.0) when the user double taps. It also sets how much we zoom out by when the user two finger taps. This will only have an effect if those gestures are active.
+ */
+@property (nonatomic) float zoomTapFactor;
+
+/**
+ How long we take to zoom in or out when the user double taps or two finger taps.
+
+ This controls the duration of the zoom animation. You can set it to zero to avoid the animation entirely.
+ */
+@property (nonatomic) float zoomTapAnimationDuration;
+
+/**
+ Reset the far clipping plane.
+
+ This is advanced functionality. Make sure you actually need to do this before you do it.
+
+ The far clipping plane is usually set to something like 4.0.
+ */
+- (void)setFarClipPlane:(double)farClipPlane;
+
+/**
+ Set the simplified tilt mode. We'll tilt toward the horizon as the user gets closer to the ground.
+
+ This implements a simplified mode for tilting. As the user gets closer to the ground we tilt more toward the horizon.
+
+ @param minHeight The minimum height corresponding to minTilt.
+
+ @param maxHeight The height at which to start interoplating tilt.
+
+ @param minTilt The most tilt toward the horizon. Invoked when the user is at minHeight or below.
+
+ @param maxTilt The tilt at the maximum height and over. The tilt will never be less than this, so typically 0.
+ */
+- (void)setTiltMinHeight:(float)minHeight maxHeight:(float)maxHeight minTilt:(float)minTilt maxTilt:(float)maxTilt;
+
+/// Turn off the varying tilt set up by setTiltMinHeight:maxHeight:minTilt:maxTilt:
+- (void)clearTiltHeight;
+
+/**
+ Turn on autorotate to rotate by the given amount every second.
+
+ This turns on an auto-rotate mode. The globe will start rotating after a delay by the given number of degrees per second. Very pleasant.
+
+ @param autoRotateInterval Wait this number of seconds after user interaction to auto rotate.
+
+ @param autoRotateDegrees Rotate this number of degrees (not radians) per second.
+ */
+- (void)setAutoRotateInterval:(float)autoRotateInterval degrees:(float)autoRotateDegrees;
+
+/**
+ Animate to the given position over time.
+
+ @param newPos A coordinate in geographic (lon/lat radians)
+
+ @param howLong A time interval in seconds.
+ */
+- (void)animateToPosition:(MaplyCoordinate)newPos time:(NSTimeInterval)howLong;
+
+/**
+ Animate the given position to the screen position over time.
+
+ This is similar to animateToPosition:time: except that it will attempt to match up the screen position and the geographic position. This is how you offset the location you're looking at.
+
+ If it's impossible to move newPos to loc, then nothing happens.
+
+ @param newPos The geographic position (lon/lat in radians) to move to.
+
+ @param loc The location on the screen where we'd like it to go.
+
+ @param howLong How long in seconds to take getting there.
+ */
+- (bool)animateToPosition:(MaplyCoordinate)newPos onScreen:(CGPoint)loc time:(NSTimeInterval)howLong;
+
+/**
+ Animate to the given position, heading and height over time.
+
+ @param newPos A coordinate in geographic (lon/lat radians)
+
+ @param newHeight New height to animate to.
+
+ @param newHeading New heading to finish on.
+
+ @param howLong A time interval in seconds.
+ */
+- (bool)animateToPosition:(MaplyCoordinate)newPos height:(float)newHeight heading:(float)newHeading time:(NSTimeInterval)howLong;
+
+/**
+ Animate to the given position, heading and height over time.
+
+ @param newPos A coordinate in geographic (lon/lat radians) (double precision)
+
+ @param newHeight New height to animate to. (double)
+
+ @param newHeading New heading to finish on. (double)
+
+ @param howLong A time interval in seconds.
+ */
+- (bool)animateToPositionD:(MaplyCoordinateD)newPos height:(double)newHeight heading:(double)newHeading time:(NSTimeInterval)howLong;
+
+/**
+ Animate to the given position, screen position, heading and height over time.
+
+ If it's impossible to move newPos to loc, then nothing happens.
+
+ @param newPos A coordinate in geographic (lon/lat radians)
+
+ @param loc The location on the screen where we'd like it to go.
+
+ @param newHeight New height to animate to.
+
+ @param newHeading New heading to finish on.
+
+ @param howLong A time interval in seconds.
+ */
+- (bool)animateToPosition:(MaplyCoordinate)newPos onScreen:(CGPoint)loc height:(float)newHeight heading:(float)newHeading time:(NSTimeInterval)howLong;
+
+/**
+ Animate with a delegate over time.
+
+ Fill in the WhirlyGlobeViewControllerAnimationDelegate and you can control the visual view on a frame by frame basis. You'll get called back at the appropriate time on the main thread over the time period.
+
+ You'll also be called one at the end of the animation to establish the final position.
+
+ @param animationDelegate The objects that implements the WhirlyGlobeViewControllerAnimationDelegate protocol.
+
+ @param howLong How long the animation will run from the present time.
+ */
+- (void)animateWithDelegate:(NSObject<WhirlyGlobeViewControllerAnimationDelegate> *__nonnull)animationDelegate time:(NSTimeInterval)howLong;
+
+/**
+ Set the center of the screen to the given position immediately.
+
+ @param newPos The geographic position (lon/lat in radians) to move to.
+ */
+- (void)setPosition:(MaplyCoordinate)newPos;
+
+/**
+ Set the center of the screen and the height offset immediately.
+
+ @param newPos The geographic position (lon/lat in radians) to move to.
+
+ @param height Height the view point above the globe.
+ */
+- (void)setPosition:(MaplyCoordinate)newPos height:(float)height;
+
+/**
+ Returns the center of the screen in geographic (lon/lat in radians).
+ */
+- (MaplyCoordinate)getPosition;
+
+/**
+ Returns the center of the screen in geographic (lon/lat in radians as doubles).
+ */
+- (MaplyCoordinateD)getPositionD;
+
+/**
+ Returns the current view point's height above the globe.
+ */
+- (double)getHeight;
+
+/**
+ Set the center of the screen and the height offset immediately.
+
+ Set the center and height using double.s
+
+ @param newPos The geographic position (lon/lat in radians) to move to.
+
+ @param height Height the view point above the globe.
+ */
+- (void)setPositionD:(MaplyCoordinateD)newPos height:(double)height;
+
+/**
+ Return the current center position and height.
+
+ @param pos The center of the screen in geographic (lon/lat in radians).
+
+ @param height The current view point's height above the globe.
+ */
+- (void)getPosition:(MaplyCoordinate *__nonnull)pos height:(float *__nonnull)height;
+
+/**
+ Return the current center position and height in doubles.
+
+ @param pos The center of the screen in geographic (lon/lat in radians).
+
+ @param height The current view point's height above the globe.
+ */
+- (void)getPositionD:(MaplyCoordinateD *__nonnull)pos height:(double *__nonnull)height;
+
+/**
+ Set the viewing state all at once
+
+ This sets the position, tilt, height, screen position and heading all at once.
+ */
+- (void)setViewState:(WhirlyGlobeViewControllerAnimationState *__nonnull)viewState;
+
+/**
+ Make a WhirlyGlobeViewControllerAnimationState object from the current view state.
+
+ This returns the current view parameters in a single WhirlyGlobeViewControllerAnimationState.
+ */
+- (nullable WhirlyGlobeViewControllerAnimationState *)getViewState;
+
+/**
+ Return a view state looking at the given location.
+
+ Creates a view state that looks at the given location, taking tilt and heading into account.
+
+ @param coord The location the user will be looking at.
+
+ @param tilt Tilt off of vertical.
+
+ @param heading Heading calculated from due north.
+
+ @param alt Altitude of the point the user will be looking at (0, is a good value).
+
+ @param range How far the user will be from the location they're looking at.
+
+ @return The view state encapsulating the user location. Will be nil if the parameters weren't valid.
+ */
+- (nullable WhirlyGlobeViewControllerAnimationState *)viewStateForLookAt:(MaplyCoordinate)coord tilt:(float)tilt heading:(float)heading altitude:(float)alt range:(float)range;
+
+/**
+ Apply viewing constraints to the given view state.
+
+ This applies active viewing constraints, such as min and max height and calculated tilt, if it's on to the given view state. This is particularly useful when controlled tilt is on.
+ */
+- (void)applyConstraintsToViewState:(WhirlyGlobeViewControllerAnimationState *__nonnull)viewState;
+
+/**
+ Find a selectable object at or near the given location.
+
+ This runs immediately and looks for a Maply object at the given location. It differs from the WhirlyGlobeViewControllerDelegate in that it doesn't require user interaction.
+
+ @param screenPt The location on screen where we're looking for an object.
+
+ @return Returns a Maply object such as MaplyScreenLabel or MaplyShape or nil if it failed to find anything.
+ */
+- (nullable id)findObjectAtLocation:(CGPoint)screenPt;
+
+/**
+ Return a location on the screen for a given geographic coordinate or CGPointZero if it's not on the screen.
+
+ @param geoCoord Point on the earth in lat/lon radians you want a screen position for.
+
+ @return the point or CGPointZero
+ */
+- (CGPoint)screenPointFromGeo:(MaplyCoordinate)geoCoord;
+
+/**
+ Return a location on the screen for a given geographic coordinate or false if it's not on the screen.
+
+ @param geoCoord Point on the earth in lat/lon radians you want a screen position for.
+
+ @param screenPt Location on the screen.
+
+ @return True if the geo coord was on the screen, false otherwise.
+ */
+- (bool)screenPointFromGeo:(MaplyCoordinate)geoCoord screenPt:(CGPoint *__nonnull)screenPt;
+
+/**
+ Calculate a geo coordinate from a point on the screen.
+
+ @param screenPt Location on the screen.
+
+ @param geoCoord Point on the earth in lat/lon radians.
+
+ @return True if the point was on the globe, false otherwise.
+ */
+- (bool)geoPointFromScreen:(CGPoint)screenPt geoCoord:(MaplyCoordinate *__nonnull)geoCoord;
+
+/**
+ Calculate a geo coordinate from a point on the screen.
+
+ @param screenPt Location on the screen.
+
+ @return The corresponding MaplyCoordinate wrapped in an NSValue if the point was on the globe, nil otherwise.
+ */
+- (nullable NSValue *)geoPointFromScreen:(CGPoint)screenPt;
+
+/**
+ Calculate a geocentric coordinate from a point on the screen.
+
+ @param screenPt Location on the screen.
+
+ @return An array of 3 NSNumber (with doubles). If the point wasn't on the globe, returns nil
+ */
+- (nullable NSArray *)geocPointFromScreen:(CGPoint)screenPt;
+
+/**
+ Calculate a geocentric coordinate from a point on the screen.
+
+ @param screenPt Location on the screen.
+
+ @param retCoords An array of 3 doubles. The geocentric coordinate will be returned here.
+
+ @return True if the point was on the globe, false otherwise.
+ */
+- (bool)geocPointFromScreen:(CGPoint)screenPt geocCoord:(double *__nonnull)retCoords;
+
+/**
+ Calculate a size in meters by projecting the two screen points onto the globe.
+ Return -1, -1 if the points weren't on the globe.
+ */
+- (CGSize)realWorldSizeFromScreenPt0:(CGPoint)pt0 pt1:(CGPoint)pt1;
+
+/**
+ Find a height that shows the given bounding box.
+
+ This method will search for a height that shows the given bounding box within the view. The search is inefficient, so don't call this a lot.
+
+ @param bbox The bounding box (in radians) we're trying to view.
+
+ @param pos The position the viewer will be at.
+ */
+- (float)findHeightToViewBounds:(MaplyBoundingBox)bbox pos:(MaplyCoordinate)pos;
+
+/**
+ Find a height that shows the given bounding box.
+ This method will search for a height that shows the given bounding box within the view. The search is inefficient, so don't call this a lot.
+
+ This version takes a margin to add around the outside of the area. Positive margins increase the screen area considered, making the
+ given area larger. Negative margins make the specified area smaller.
+
+ @param bbox The bounding box (in radians) we're trying to view.
+ @param pos Where the view will be looking.
+ @param marginX Horizontal boundary around the area
+ @param marginY Vertical boundary around the area
+ */
+- (float)findHeightToViewBounds:(MaplyBoundingBox)bbox
+ pos:(MaplyCoordinate)pos
+ marginX:(double)marginX
+ marginY:(double)marginY;
+
+/**
+ Find a height that shows the given bounding box.
+ This method will search for a height that shows the given bounding box within the view. The search is inefficient, so don't call this a lot.
+
+ This version takes a margin to add around the outside of the area. Positive margins increase the screen area considered, making the
+ given area larger. Negative margins make the specified area smaller.
+
+ This version attempts to place the given bounds within a rectangle other than the whole view frame.
+ Note that this doesn't work well when the bounds are very large.
+
+ @param bbox The bounding box (in radians) we're trying to view.
+ @param pos Where the view will be looking.
+ @param frame The screen area to consider.
+ @param newPos (out,optional) The center location needed to place \c pos at the center of \c frame
+ @param marginX Horizontal boundary around the area
+ @param marginY Vertical boundary around the area
+ */
+- (float)findHeightToViewBounds:(MaplyBoundingBox)bbox
+ pos:(MaplyCoordinate)pos
+ frame:(CGRect)frame
+ newPos:(MaplyCoordinate *_Nullable)newPos
+ marginX:(double)marginX
+ marginY:(double)marginY;
+
+/**
+
+ Return the extents of the current view.
+
+ When we're dealing with a globe the corners could be outside of the globe, in this case kMaplyNullBoundingBox is returned.
+
+ @return Returns the bounding box if exists a bounding bbox for the current view, otherwise returns kMaplyNullBoundingBox.
+ */
+- (MaplyBoundingBox)getCurrentExtents;
+
+/**
+
+ Return the extents of the current view.
+
+ When we're dealing with a globe the corners could be outside of the globe, in this case false is returned.
+
+ @param bbox The bbox will be returned here.
+
+ @return Returns true if exists a bounding bbox for the current view, otherwise returns false
+ */
+- (bool)getCurrentExtents:(MaplyBoundingBox *__nonnull)bbox;
+
+/**
+
+ From the current view figure out a usable geo bounding box.
+
+ This is similar to the WhirlyGlobeViewControllerDelegate methods and getCurrentExtents except that it goes a little deeper. It starts with the four corners of the screen and then tries to take tilt and orientation into account. Ideally it produces a bounding box that covers everything the user is looking at as opposed to where the four corners are.
+
+ @param bboxes The bounding boxes to fill in. Pass in two.
+
+ @param visualBoxes If set, we'll build bounding boxes you can display. If not set, we'll build a single bounding box usable for math.
+ */
+- (int)getUsableGeoBoundsForView:(MaplyBoundingBox *__nonnull)bboxes visual:(bool)visualBoxes;
+
+/**
+
+ Make a gesture recognizer's success depend on the pan gesture
+ recognizer's failure.
+
+ When using the globe view within a scroll view, add swipe gesture
+ recognizers to the scroll view to control paging, and call this method
+ for each. See also the inScrollView property and its comment.
+
+ @param other The other, subordinate gesture recognizer.
+ */
+- (void)requirePanGestureRecognizerToFailForGesture:(UIGestureRecognizer *__nullable)other;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Info.plist b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Info.plist
new file mode 100644
index 0000000..47bf396
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Info.plist
Binary files differ
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Modules/module.modulemap b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Modules/module.modulemap
new file mode 100644
index 0000000..2e32255
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/Modules/module.modulemap
@@ -0,0 +1,6 @@
+framework module WhirlyGlobe {
+ umbrella header "WhirlyGlobe.h"
+
+ export *
+ module * { export * }
+}
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/WhirlyGlobe b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/WhirlyGlobe
new file mode 100755
index 0000000..8625600
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/WhirlyGlobe
Binary files differ
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/default.metallib b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/default.metallib
new file mode 100644
index 0000000..5d85be9
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64/WhirlyGlobe.framework/default.metallib
Binary files differ
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Config-ac.h.in b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Config-ac.h.in
new file mode 100644
index 0000000..ac3ba0b
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Config-ac.h.in
@@ -0,0 +1,91 @@
+/* include/GeographicLib/Config-ac.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* major version number */
+#undef GEOGRAPHICLIB_VERSION_MAJOR
+
+/* minor version number */
+#undef GEOGRAPHICLIB_VERSION_MINOR
+
+/* patch number */
+#undef GEOGRAPHICLIB_VERSION_PATCH
+
+/* define if the compiler supports basic C++11 syntax */
+#undef HAVE_CXX11
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if the system has the type `long double'. */
+#undef HAVE_LONG_DOUBLE
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#undef LT_OBJDIR
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+# undef WORDS_BIGENDIAN
+# endif
+#endif
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GeoJSONSource.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GeoJSONSource.h
new file mode 100644
index 0000000..ff80172
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GeoJSONSource.h
@@ -0,0 +1,40 @@
+/* GeoJSONSource.mm
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Ranen Ghosh on 2016-11-18.
+ * Copyright 2016-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyBaseViewController.h>
+
+#define GEOJSON_MAX_POINTS 4096
+
+/**
+ This class will read GeoJSON via URL with an associated Styled Layer Descriptor via URL. It will then
+ parse both of them and apply the SLD style to the GeoJSON data. This results in visual data in
+ much the same way as loading vector tiles would.
+ */
+@interface GeoJSONSource : NSObject
+
+- (id _Nullable)initWithViewC:(NSObject<MaplyRenderControllerProtocol> * _Nonnull)baseVC GeoJSONURL:(NSURL * _Nonnull)geoJSONURL sldURL:(NSURL * _Nonnull)sldURL relativeDrawPriority:(int)relativeDrawPriority ;
+
+- (void)startParseWithCompletion:(nonnull void (^)(void)) completionBlock;
+
+- (void)startParse;
+
+@property (nonatomic, readonly) bool loaded;
+@property (nonatomic, assign) bool enabled;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GeographicLib_ObjC.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GeographicLib_ObjC.h
new file mode 100644
index 0000000..22bd915
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GeographicLib_ObjC.h
@@ -0,0 +1,100 @@
+//
+// geowrap.h
+// WhirlyGlobeLib
+//
+// Created by Tim Sylvester on 12/14/20.
+// Copyright 2020 mousebird consulting. All rights reserved.
+//
+
+#ifndef GeographicLib_Wrapper_h
+#define GeographicLib_Wrapper_h
+
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+typedef struct GeoLibInv_t {
+ double distance; // meters
+ double azimuth1; // radians
+ double azimuth2; // radians
+} GeoLibInv;
+
+typedef struct GeoLibInt_t {
+ MaplyCoordinateD intersection;
+ bool intersects;
+} GeoLibInt;
+
+typedef struct GeoLibIntPair_t {
+ MaplyCoordinateD intersections[2];
+ double distances[2];
+ unsigned int count;
+} GeoLibIntPair;
+
+typedef struct GeoLibOrthoDist_t {
+ double downtrackDistance;
+ double crosstrackDistance;
+ double segmentLength;
+} GeoLibOrthoDist;
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+/// Solve the direct geodesic problem where the length of the geodesic is specified in terms of distance.
+/// azimuth in radians, distance in meters
+MaplyCoordinate GeoLibCalcDirectF(MaplyCoordinate origin, double azimuth, double distance);
+MaplyCoordinateD GeoLibCalcDirectD(MaplyCoordinateD origin, double azimuth, double distance);
+
+// Solve the inverse geodesic problem
+GeoLibInv GeoLibCalcInverseF(MaplyCoordinate p1, MaplyCoordinate p2);
+GeoLibInv GeoLibCalcInverseD(MaplyCoordinateD p1, MaplyCoordinateD p2);
+
+// Test for a point lying inside the specified polygon
+bool MaplyCoordinateInPolygon(MaplyCoordinate p, const MaplyCoordinate polygon[], unsigned count);
+bool MaplyCoordinateDInPolygon(MaplyCoordinateD p, const MaplyCoordinate polygon[], unsigned count);
+bool MaplyCoordinateInPolygonD(MaplyCoordinate p, const MaplyCoordinateD polygon[], unsigned count);
+bool MaplyCoordinateDInPolygonD(MaplyCoordinateD p, const MaplyCoordinateD polygon[], unsigned count);
+
+double GeoLibDistanceD(MaplyCoordinateD startPt, MaplyCoordinateD endPt);
+
+// Test for a segment intersecting a polygon.
+// Note that if the line is completely within the polygon the result is false.
+bool GeoLibLineDIntersectsPolygonD(MaplyCoordinateD startPt, MaplyCoordinateD endPt, const MaplyCoordinateD[], unsigned count);
+
+// Compute the intersection point of two geodesic segments
+GeoLibInt GeoLibIntersectD(MaplyCoordinateD a, MaplyCoordinateD b, MaplyCoordinateD c, MaplyCoordinateD d);
+
+// Determine where a great circle intersects a small circle
+GeoLibIntPair GeoLibLineDIntersectCircleD(MaplyCoordinateD startPt, MaplyCoordinateD endPt, MaplyCoordinateD center, double radiusMeters);
+
+// Determine whether there's an intersection without bothering to compute its location
+bool GeoLibLineDIntersectsCircleD(MaplyCoordinateD startPt, MaplyCoordinateD endPt, MaplyCoordinateD center, double radiusMeters);
+
+// Compute the orthogonal distances for a point.
+//
+// Given a segment and a point, find the perpendicular intersection point (the closest point along the
+// segment) and compute the distance from that point to the segment starting point (down-track) and
+// to the specified point (cross-track).
+//
+// negative down-track distance C
+// v | <- negative cross-track distance
+// - - - - - A--------B
+// | | <- positive cross-track distance
+// C C
+// ----
+// ^ positive down-track-distance
+//
+// If the point lies "before" the segment start point, the down-track distance will be negative.
+// If the point lies "after" the segment end point, the down-track distance will be greater than the segment length.
+// If the point lies to the right of the segment, the cross-track distance will be positive.
+// If the point lies to the left of the segment, the cross-track distance will be negative.
+GeoLibOrthoDist GeoLibOrthoDistD(MaplyCoordinateD a, MaplyCoordinateD b, MaplyCoordinateD c);
+
+// Generate points along an arc
+double GeoLibSampleArcD(MaplyCoordinateD center, double radiusMeters,
+ double beginAzimuthRad, double endAziumthRad, bool clockwise,
+ MaplyCoordinateD points[], unsigned count);
+
+#if defined __cplusplus
+} // extern "C"
+#endif
+
+#endif /* GeographicLib_Wrapper_h */
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeDoubleTapDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeDoubleTapDelegate.h
new file mode 100644
index 0000000..ea1b934
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeDoubleTapDelegate.h
@@ -0,0 +1,34 @@
+/* GlobeDoubleTapDelegate.h
+ *
+ * Created by Steve Gifford on 2/7/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@interface WhirlyGlobeDoubleTapDelegate : NSObject<UIGestureRecognizerDelegate>
+
+@property (nonatomic,weak) UIGestureRecognizer *gestureRecognizer;
+
+// How much we zoom in by
+@property (nonatomic) float zoomTapFactor;
+
+// How long the zoom animation takes
+@property (nonatomic) float zoomAnimationDuration;
+
+/// Zoom limits
+@property (nonatomic) float minZoom,maxZoom;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeDoubleTapDragDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeDoubleTapDragDelegate.h
new file mode 100644
index 0000000..295fff8
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeDoubleTapDragDelegate.h
@@ -0,0 +1,33 @@
+/* GlobeDoubleTapDragDelegate.h
+ *
+ * Created by Steve Gifford on 2/7/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <WhirlyGlobe/GlobePinchDelegate.h>
+
+// Sent out when the double tap delegate takes control
+#define kGlobeDoubleTapDragDidStart @"WKGlobeDoubleTapDragStarted"
+// Sent out when the double tap delegate finished (but hands off to momentum)
+#define kGlobeDoubleTapDragDidEnd @"WKGlobeDoubleTapDragEnded"
+
+@interface WhirlyGlobeDoubleTapDragDelegate : NSObject<UIGestureRecognizerDelegate>
+
+@property (nonatomic,weak) UIGestureRecognizer *gestureRecognizer;
+
+/// Zoom limits
+@property (nonatomic) float minZoom,maxZoom;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobePanDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobePanDelegate.h
new file mode 100644
index 0000000..02d2249
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobePanDelegate.h
@@ -0,0 +1,48 @@
+/*
+ * GlobePanDelegate.h
+ * WhirlyGlobeApp
+ *
+ * Created by Stephen Gifford on 4/28/11.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+
+// Sent out when the pan delegate takes control
+#define kPanDelegateDidStart @"WKPanDelegateStarted"
+// Sent out when the pan delegate finished (but hands off to momentum)
+#define kPanDelegateDidEnd @"WKPanDelegateEnded"
+
+#define kPanDelegateMinTime 0.1
+
+// Custom pan gesture recognizer that plays well with scroll views.
+@interface MinDelayPanGestureRecognizer : UIPanGestureRecognizer {
+ // time of start of gesture
+ CFTimeInterval startTime;
+}
+
+- (void)forceEnd;
+
+@end
+
+
+// The pan delegate handles panning and rotates the globe accordingly
+@interface WhirlyGlobePanDelegate : NSObject<UIGestureRecognizerDelegate>
+
+@property(nonatomic,assign) bool northUp;
+
+@property (nonatomic,weak) UIGestureRecognizer *gestureRecognizer;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobePinchDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobePinchDelegate.h
new file mode 100644
index 0000000..35d40d8
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobePinchDelegate.h
@@ -0,0 +1,61 @@
+/* GlobePinchDelegate.h
+ * WhirlyGlobeLib
+ *
+ * Created by Steve Gifford on 8/22/12.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+
+@class WhirlyGlobeRotateDelegate;
+
+// Sent out when the pinch delegate takes control
+#define kPinchDelegateDidStart @"WKPinchDelegateStarted"
+// Sent out when the pinch delegate finished (but hands off to momentum)
+#define kPinchDelegateDidEnd @"WKPinchDelegateEnded"
+
+/** WhirlyGlobe Pinch Gesture Delegate
+ Responds to pinches on a UIView and manipulates the globe view
+ accordingly.
+ */
+@interface WhirlyGlobePinchDelegate : NSObject <UIGestureRecognizerDelegate>
+
+/// Min and max height to allow the user to change
+@property (nonatomic,assign) float minHeight,maxHeight;
+
+/// If set we're cooperating with the rotation delegate (HACK!)
+@property (nonatomic,weak) WhirlyGlobeRotateDelegate *rotateDelegate;
+
+/// If set, we'll zoom around the pinch, rather than the center of the view
+@property (nonatomic,assign) bool zoomAroundPinch;
+
+/// If set, we'll rotate around the pinch
+@property (nonatomic,assign) bool doRotation;
+
+/// If set, we'll pan around the center point. If not, we just zoom.
+@property (nonatomic,assign) bool allowPan;
+
+/// If set, we'll maintain north as up
+@property (nonatomic,assign) bool northUp;
+
+@property (nonatomic,weak) UIGestureRecognizer *gestureRecognizer;
+
+// If set, we'll keep track up rather than north up
+- (void)setTrackUp:(double)trackUp;
+
+// Turn track up back off
+- (void)clearTrackUp;
+
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeRotateDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeRotateDelegate.h
new file mode 100644
index 0000000..9e57c3a
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeRotateDelegate.h
@@ -0,0 +1,37 @@
+/* GlobeRotateDelegate.h
+ * WhirlyGlobeLib
+ *
+ * Created by Steve Gifford on 6/10/11.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+
+@protocol WhirlyKitViewWrapper;
+
+/** Rotation delegate
+ is for two fingered rotation around the axis at the middle of the screen
+ */
+@interface WhirlyGlobeRotateDelegate : NSObject <UIGestureRecognizerDelegate>
+
+/// If set, the rotation will occur around the center between the two fingers rather than the current viewpoint
+@property (nonatomic) bool rotateAroundCenter;
+
+/// Gesture recognizer attached to this delegate (or vice versa, actually)
+@property (nonatomic,weak) UIGestureRecognizer *gestureRecognizer;
+
+/// Can be called by a cooperating delegate (which is also messing with rotation) (HACK!)
+- (void)updateWithCenter:(CGPoint)center touch:(CGPoint)touch wrapView:(UIView<WhirlyKitViewWrapper> *)glView;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeTapDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeTapDelegate.h
new file mode 100644
index 0000000..61e3492
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeTapDelegate.h
@@ -0,0 +1,29 @@
+/* GlobeTapDelegate.h
+ * WhirlyGlobeLib
+ *
+ * Created by Steve Gifford on 2/3/11.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+
+/** WhirlyGlobe tap gesture delegate
+ responds to taps by blasting out a notification.
+ */
+@interface WhirlyGlobeTapDelegate : NSObject <UIGestureRecognizerDelegate>
+
+@property (nonatomic,weak) UIGestureRecognizer *gestureRecognizer;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeTiltDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeTiltDelegate.h
new file mode 100644
index 0000000..09cf3eb
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeTiltDelegate.h
@@ -0,0 +1,28 @@
+/* GlobeTiltDelegate.h
+ *
+ * Created by Stephen Gifford on 1/5/15.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/GlobePinchDelegate.h>
+
+// The tilt delegate handle the 3D camera tilt
+@interface WhirlyGlobeTiltDelegate : NSObject<UIGestureRecognizerDelegate>
+
+@property (nonatomic,weak) UIGestureRecognizer *gestureRecognizer;
+
+// Set so we can turn off the pinch delegate when we're working
+@property (nonatomic,weak) WhirlyGlobePinchDelegate *pinchDelegate;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeTwoFingerTapDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeTwoFingerTapDelegate.h
new file mode 100644
index 0000000..93bea5e
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/GlobeTwoFingerTapDelegate.h
@@ -0,0 +1,34 @@
+/* GlobeTwoFingerTapDelegate.h
+ *
+ * Created by Steve Gifford on 2/7/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@interface WhirlyGlobeTwoFingerTapDelegate : NSObject<UIGestureRecognizerDelegate>
+
+@property (nonatomic,weak) UIGestureRecognizer *gestureRecognizer;
+
+// How much we zoom in by
+@property (nonatomic) float zoomTapFactor;
+
+// How long the zoom animation takes
+@property (nonatomic) float zoomAnimationDuration;
+
+/// Zoom limits
+@property (nonatomic) float minZoom,maxZoom;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapboxVectorInterpreter.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapboxVectorInterpreter.h
new file mode 100644
index 0000000..25a3417
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapboxVectorInterpreter.h
@@ -0,0 +1,65 @@
+/*
+ * MapboxVectorTilesImageDelegate.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on January 24 2018
+ * Copyright 2011-2022 Saildrone
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#import <Foundation/Foundation.h>
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyVectorStyle.h>
+#import <WhirlyGlobe/MapboxVectorTiles.h>
+#import <WhirlyGlobe/MaplyQuadImageFrameLoader.h>
+
+@class MapboxVectorStyleSet;
+
+/**
+ An interpreter for Mapbox Vector Tiles.
+
+ This will turn vector tiles into images, visual objects, or a combination of the two. Loader interpreters like
+ this one can be used by Loaders that talk to ondevice objects (such as MBTiles files) or remote tile
+ sources.
+ */
+@interface MapboxVectorInterpreter : NSObject<MaplyLoaderInterpreter>
+
+/** This version of the init takes an image style set, a vector style set,
+ and an offline renderer to build the image tiles.
+
+ Image tiles will be used as a background and vectors put on top of them.
+ This is very nice for the globe, but requires specialized style sheets.
+ */
+- (instancetype _Nullable ) initWithImageStyle:(NSObject<MaplyVectorStyleDelegate> *__nonnull)imageStyle
+ offlineRender:(MaplyRenderController *__nonnull)renderControl
+ vectorStyle:(NSObject<MaplyVectorStyleDelegate> *__nonnull)vectorStyle
+ viewC:(NSObject<MaplyRenderControllerProtocol> *__nonnull)viewC;
+
+/** This version of the init builds visual features for vector tiles.
+
+ This interpreter can be used as overlay data or a full map, depending
+ on how your style is configured.
+ */
+- (instancetype __nullable) initWithVectorStyle:(NSObject<MaplyVectorStyleDelegate> *__nonnull)vectorStyle
+ viewC:(NSObject<MaplyRenderControllerProtocol> *__nonnull)viewC;
+
+/**
+ Set an optional list of unique features we'll filter on.
+ Any feature we want to pass through must have the given attribute name and one of the values.
+ */
+- (void)setUUIDName:(NSString * __nonnull)uuidName uuidValues:(NSArray<NSString *> * __nonnull)uuids;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapboxVectorStyleSet.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapboxVectorStyleSet.h
new file mode 100644
index 0000000..1f5c9ae
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapboxVectorStyleSet.h
@@ -0,0 +1,139 @@
+/*
+ * MapboxVectorStyleSet.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 2/16/15.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+#import <WhirlyGlobe/MaplyVectorStyle.h>
+#import <WhirlyGlobe/MapboxVectorTiles.h>
+
+typedef NS_ENUM(NSUInteger,MapboxLayerType) {
+ MapboxLayerTypeBackground,
+ MapboxLayerTypeCircle,
+ MapboxLayerTypeFill,
+ MapboxLayerTypeLine,
+ MapboxLayerTypeRaster,
+ MapboxLayerTypeSymbol,
+ MapboxLayerTypeUnknown
+};
+
+/**
+ A single entry in the legend array returned by
+ */
+@interface MaplyLegendEntry : NSObject
+
+/// Name of this entry
+@property (nonatomic,nonnull) NSString *name;
+
+/// Image for this entry, if this is a single entry
+@property (nonatomic,nullable) UIImage *image;
+
+/// Array of entries if this is a group
+@property (nonatomic,nullable) NSMutableArray<MaplyLegendEntry *> *entries;
+
+@end
+
+/** @brief The Mapbox Vector Style Set parses Mapbox GL Style sheets and turns them into Maply compatible styles.
+ @details A style delegate is required by the Mapnik parser to build geometry out of Mapnik vector tiles. This style delegate can read a Mapbox GL Style sheet and produce compatible styles.
+ */
+@interface MapboxVectorStyleSet : NSObject<MaplyVectorStyleDelegate>
+
+/// @brief Initialize with the style dictionary alreayd parsed from JSON
+/// @details We'll parse the style JSON passed in and return nil on failure.
+/// @details The optional filter can be used to reject layers we won't use
+- (id __nullable)initWithDict:(NSDictionary * __nonnull)styleDict
+ settings:(MaplyVectorStyleSettings * __nonnull)settings
+ viewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+/// @brief Initialize with the style JSON and the view controller
+/// @details We'll parse the style JSON passed in and return nil on failure.
+/// @details The optional filter can be used to reject layers we won't use
+- (id __nullable)initWithJSON:(NSData * __nonnull)styleJSON
+ settings:(MaplyVectorStyleSettings * __nonnull)settings
+ viewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+/// @brief Where we can fetch the sprites
+@property (nonatomic, strong, nullable) NSString *spriteURL;
+
+/// Tile sources
+@property (nonatomic, strong, nonnull) NSArray *sources;
+
+/// All the layer names
+@property (nonatomic) NSArray<NSString *> * __nonnull layerNames;
+
+/// Type of the given layer
+- (MapboxLayerType) layerType:(NSString * __nonnull)layerName;
+
+/// Add the sprint sheet for use in symbols. Return false on failures.
+- (bool)addSprites:(NSDictionary * __nonnull)spriteDict image:(UIImage * __nonnull)image;
+
+/**
+ This method will poke around in the given layer to determine a distinc color for it.
+ For circle layers, you get the circle color. For fill and line layers, it's the paint color.
+ For symbols, you get the text color.
+ This is useful for visualizing layers, it has nothing to do with rendering them.
+ */
+- (UIColor * __nullable) colorForLayer:(NSString *__nonnull)layerName;
+
+/// If there is a background layer, calculate the color for a given zoom level.
+/// Otherwise return nil
+- (UIColor * __nullable)backgroundColorForZoom:(double)zoom;
+
+/// Make a layer visible/invisible
+- (void)setLayerVisible:(NSString *__nonnull)layerName visible:(bool)visible;
+
+/// Slot for continuous zoom levels. If not set, we won't use those.
+- (void)setZoomSlot:(int)zoomSlot;
+
+/**
+ Returns a dictionary containing a flexible legend for the layers contained in this style.
+ Each layer is rendered as a representative image at the given size.
+ Layer names that start with the same "<name>_" will be grouped together in the hiearchy if
+ the group parameter is set. Otherwise they'll be flat.
+ */
+- (NSArray<MaplyLegendEntry *> * __nonnull)layerLegend:(CGSize)imageSize group:(bool)useGroups;
+
+@property (nonatomic, weak, nullable) NSObject<MaplyRenderControllerProtocol> *viewC;
+
+@end
+
+typedef enum : NSUInteger {
+ MapboxSourceVector,
+ MapboxSourceRaster,
+ // TODO: Support the rest of these eventually
+} MapboxSourceType;
+
+// Sources are called out individually
+@interface MaplyMapboxVectorStyleSource : NSObject
+
+// Name of the source
+@property (nonatomic,nullable) NSString *name;
+
+// Vector and raster sources supported for now
+@property (nonatomic) MapboxSourceType type;
+
+// TileJSON URL, if present
+@property (nonatomic,nullable) NSString *url;
+
+// If the TileJSON spec is inline, this is it
+@property (nonatomic,nullable) NSDictionary *tileSpec;
+
+// Initialize with the entry in the style file
+- (id __nullable)initWithName:(NSString *__nonnull)name styleEntry:(NSDictionary * __nonnull)styleEntry styleSet:(MapboxVectorStyleSet * __nonnull)styleSet viewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapboxVectorTiles.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapboxVectorTiles.h
new file mode 100644
index 0000000..7b4cbef
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapboxVectorTiles.h
@@ -0,0 +1,65 @@
+/*
+ * MapboxVectorTiles.h
+ * WhirlyGlobeLib
+ *
+ * Created by Steve Gifford on 4/10/19.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyVectorTileStyle.h>
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyVectorStyle.h>
+
+typedef NS_ENUM(NSInteger,MapboxGeometryType)
+{
+ GeomTypeUnknown = 0,
+ GeomTypePoint = 1,
+ GeomTypeLineString = 2,
+ GeomTypePolygon = 3
+};
+
+
+/**
+ Container for data parsed out of a Mapbox Vector Tile stream.
+
+ This holds the parsed data as well as post-constructed data. You will likely be handed one of these
+ if you see it at all. There are few cases where you might construct one.
+ */
+@interface MaplyVectorTileData : NSObject
+
+/// Initialize with tile and bounds, both local coordinates and geographic
+- (id)initWithID:(MaplyTileID)tileID bbox:(MaplyBoundingBoxD)bbox geoBBox:(MaplyBoundingBoxD)geoBBox;
+
+/// Tile ID for the tile being built
+@property (readonly) MaplyTileID tileID;
+
+/// Bounding box in local coordinates
+@property (readonly) MaplyBoundingBoxD bounds;
+
+/// Bounding box in geographic
+@property (readonly) MaplyBoundingBoxD geoBounds;
+
+/// Add a single component object for tracking
+- (void)addComponentObject:(MaplyComponentObject *)compObj;
+
+/// When a style builds a component object, it needs to add it here
+/// for tracking. This lets us delete it later.
+- (void)addComponentObjects:(NSArray *)compObjs;
+
+/// Return all the component objects thus collected
+- (NSArray *)componentObjects;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/Maply3DTouchPreviewDatasource.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/Maply3DTouchPreviewDatasource.h
new file mode 100644
index 0000000..ef42bf5
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/Maply3DTouchPreviewDatasource.h
@@ -0,0 +1,38 @@
+//
+// Maply3DTouchPreviewDatasource.h
+// WhirlyGlobe-MaplyComponent
+//
+// Created by Jesse Crocker on 10/4/15.
+//
+//
+
+@class MaplyBaseViewController;
+
+@protocol Maply3dTouchPreviewDatasource <NSObject>
+
+@required
+/**
+ Asks the data source for a view controller to display as a preview for a selected object
+
+ @param viewC the map requesting the view controller;
+
+ @param selectedObj The object a preview is being requested for.
+
+ @return a UIViewController, or nil if no preview should be displayed.
+ */
+- (UIViewController * _Nullable)maplyViewController:(MaplyBaseViewController * _Nonnull)viewC
+ previewViewControllerForSelection:(NSObject * _Nonnull)selectedObj;
+
+/**
+ Asks the data source to present a preview view controller.
+
+ the most likely implementation of this is [self show:previewViewC sender:self];
+
+ @param viewC the map requesting the view controller;
+
+ @param previewViewC the view controller to present.
+ */
+- (void)maplyViewController:(MaplyBaseViewController * _Nonnull)viewC
+ showPreviewViewController:(UIViewController * _Nonnull)previewViewC;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/Maply3dTouchPreviewDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/Maply3dTouchPreviewDelegate.h
new file mode 100644
index 0000000..1957e10
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/Maply3dTouchPreviewDelegate.h
@@ -0,0 +1,26 @@
+//
+// Maply3dTouchDelegate.h
+// WhirlyGlobeLib
+//
+// Created by Jesse Crocker on 10/4/15.
+//
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/Maply3DTouchPreviewDatasource.h>
+
+@class MaplyBaseInteractionLayer;
+@class MaplyBaseViewController;
+
+@interface Maply3dTouchPreviewDelegate : NSObject <UIViewControllerPreviewingDelegate>
+
+@property (nonatomic, strong) NSObject<Maply3dTouchPreviewDatasource> * _Nonnull datasource;
+
+/// Create and configure new Maply3dTouchPreviewDelegate, but it is not activated.
++ (Maply3dTouchPreviewDelegate * _Nonnull)touchDelegate:(MaplyBaseViewController * _Nonnull)maplyViewC
+ interactLayer:( MaplyBaseInteractionLayer* _Nonnull)interactLayer
+ datasource:(NSObject<Maply3dTouchPreviewDatasource>* _Nonnull)datasource;
+
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyActiveObject.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyActiveObject.h
new file mode 100644
index 0000000..864e853
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyActiveObject.h
@@ -0,0 +1,70 @@
+/*
+ * MaplyActiveObject.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 4/3/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+@class MaplyBaseViewController;
+@protocol MaplyRenderControllerProtocol;
+
+/**
+ Active Objects are used implement animation.
+
+ Active Objects work in conjuction with the renderer to make updates on the main thread. The way they work is this. They're called right at the beginning of a frame draw. They can make updates to regular Maply objects via the MaplyBaseViewController add and remove calls with the MaplyThreadMode set to MaplyThreadCurrent. This forces the changes to happen immediately on the current (main) thread.
+
+ Fill in at least the hasUpdate and updateForFrameMethods.
+
+ Active Objects are run on the main thread and you're probably going to be asking the view controller to add and remove objects on the main thread. As such, this can be slow. Be sure to precalculate whatever you might need to make this run faster. Also consider implementing your changes another way. If it can be done on another thread, do it on another thread.
+
+ */
+@interface MaplyActiveObject : NSObject
+
+/**
+ Initialize with a view controller
+
+ The default initializer just takes a view controller. If you replace this with your own, be sure to pass in what you need.
+ */
+- (nonnull instancetype)initWithViewController:(NSObject<MaplyRenderControllerProtocol> *__nonnull)viewC;
+
+/// The view controller this active object is associated with
+@property (nonatomic,weak,readonly) NSObject<MaplyRenderControllerProtocol> *__nullable viewC;
+
+/** Has Update
+
+ This is called every frame to determine if the active model has an update.
+ If it doesn't, we may not need to render. So use this judiciously.
+ */
+- (bool)hasUpdate;
+
+/** Update for the current frame.
+
+ Run the update right now. This should not take too long, as it's holding up
+ the renderer.
+
+ The frameInfo object is undefined at this point.
+ */
+- (void)updateForFrame:(void * __nonnull)frameInfo;
+
+/** Teardown active model.
+
+ The active model will no longer be run. Get rid of your internal state.
+ */
+- (void)teardown;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyAnnotation.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyAnnotation.h
new file mode 100644
index 0000000..1337cc3
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyAnnotation.h
@@ -0,0 +1,71 @@
+/*
+ * MaplyAnnotation.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 12/13/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+/**
+ This object displays an annotation at a particular point and will track that point as the map or globe moves.
+
+ An annotation is used to point out some feature on the globe or map, typically that the user has tapped on. It's a multi-part beast that may contain titles, subtitles, images, background views and such.
+
+ To add one, create the MaplyAnnotation and then call addAnnotation:forPoint:offset: on the MaplyBaseViewController.
+
+ The MaplyAnnotation is a wrapper around the SMCalloutView by Nick Farina. It exposes much of the functionality, but sets things up correctly and deals with moving the annotation around.
+ */
+@interface MaplyAnnotation : NSObject
+
+/// The minimum viewer height this annotation is visible at.
+/// This is viewer height above the globe or map. The annotation will only be visible if the user is above this height.
+@property (nonatomic,assign) float minVis;
+
+/// The maximum viewer height this annotation is visible at.
+/// This is viewer height above the globe or map. The annotation will only be visible if the user is below this height.
+@property (nonatomic,assign) float maxVis;
+
+/// Set the popup's title
+@property (nonatomic,strong) NSString *title;
+
+/// Set the popup's subtitle
+@property (nonatomic,strong) NSString *subTitle;
+
+/// If set, the (optional) accessory view on the left
+@property (nonatomic,strong) UIView *leftAccessoryView;
+
+/// If set, the (optional) accessory view on the right
+@property (nonatomic,strong) UIView *rightAccessoryView;
+
+/// If set, the custom title view containing whatever you like.
+@property (nonatomic,strong) UIView *titleView;
+
+/// If set, the custom subtitle view containing whatever you put in there.
+@property (nonatomic,strong) UIView *subtitleView;
+
+/// If set, a custom content view. Title, subtitle and views are ignored.
+@property (nonatomic,strong) UIView *contentView;
+
+/// The location of the annotation
+@property (nonatomic,readonly) MaplyCoordinate loc;
+
+/// If set, we'll reposition the globe or map to make the annotation visible.
+/// If the annotation would be off screen we would normally reposition the globe or map to make it visible. If this is et to false, we won't.
+@property (nonatomic) bool repositionForVisibility;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyAtmosphere.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyAtmosphere.h
new file mode 100644
index 0000000..f5de72d
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyAtmosphere.h
@@ -0,0 +1,81 @@
+/*
+ * MaplyAtmosphere.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 6/30/15.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyComponentObject.h>
+#import <WhirlyGlobe/WhirlyGlobeViewController.h>
+#import <WhirlyGlobe/MaplyLight.h>
+
+/**
+ Sets up the objects and shaders to implement an atmosphere.
+
+ This object sets up a shader implementation of the simple atmosphere from GPU Gems 2 http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html
+ */
+@interface MaplyAtmosphere : NSObject
+
+/// Initialize the view controller. Will place objects in that view controller.
+- (nullable instancetype)initWithViewC:(WhirlyGlobeViewController *__nonnull)viewC;
+
+/// Rayleigh scattering constant (0.0025 by default)
+@property (nonatomic) float Kr;
+
+/// Mie scattering constant (0.0010 by default)
+@property (nonatomic) float Km;
+
+/// Brightness of the sun (20.0 by default)
+@property (nonatomic) float ESun;
+
+/// Number of samples for the ray through the atmosphere (3 by default)
+@property (nonatomic) int numSamples;
+
+/// Outer radius of the atmosphere (1.05 by default). Earth is radius 1.0.
+@property (nonatomic) float outerRadius;
+
+/// Constant used in the fragment shader. Default is -0.95.
+@property (nonatomic) float g;
+
+/// Exposure constant in fragment shader. Default is 2.0.
+@property (nonatomic) float exposure;
+
+/// The ground shader we set up. You need to apply it yourself.
+@property (nonatomic,nullable,strong) MaplyShader *groundShader;
+
+/// If set we'll lock the sun direction to the camera position. Permanent daylight.
+@property (nonatomic) bool lockToCamera;
+
+/// Wavelengths of the light (RGB). Three floats, defaults are: 0.650, 0.570, 0.475
+- (void)setWavelength:(float *__nonnull)wavelength;
+
+/// Wavelengths of the light (RGB). Defaults are: 0.650, 0.570, 0.475
+- (void)setWavelengthRed:(float) redWavelength green:(float)greenWavelength blue:(float)blueWavelength;
+
+/// Return the current wavelength settings (RGB)
+- (void)getWavelength:(float *__nonnull)wavelength;
+
+/// Return the current wavelength settings (RGB). The component is 0 for red, 1 for green and 2 for blue
+- (float)getWavelengthForComponent:(short)component;
+
+/// Set the sun's position relative to the earth. This is what comes out of MaplySun.
+- (void)setSunPosition:(MaplyCoordinate3d)sunDir;
+
+/// Remove objects from the view controller we set it up in.
+- (void)removeFromViewC;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyBaseViewController.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyBaseViewController.h
new file mode 100644
index 0000000..119b330
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyBaseViewController.h
@@ -0,0 +1,1582 @@
+/* MaplyBaseViewController.h
+ * MaplyComponent
+ *
+ * Created by Steve Gifford on 12/14/12.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <Metal/Metal.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyScreenMarker.h>
+#import <WhirlyGlobe/MaplyVectorObject.h>
+#import <WhirlyGlobe/MaplyViewTracker.h>
+#import <WhirlyGlobe/MaplyComponentObject.h>
+#import <WhirlyGlobe/MaplySharedAttributes.h>
+#import <WhirlyGlobe/MaplyControllerLayer.h>
+#import <WhirlyGlobe/MaplyLight.h>
+#import <WhirlyGlobe/MaplyShader.h>
+#import <WhirlyGlobe/MaplyActiveObject.h>
+#import <WhirlyGlobe/MaplyTexture.h>
+#import <WhirlyGlobe/MaplyAnnotation.h>
+#import <WhirlyGlobe/MaplyParticleSystem.h>
+#import <WhirlyGlobe/MaplyPoints.h>
+#import <WhirlyGlobe/MaplyCluster.h>
+#import <WhirlyGlobe/Maply3DTouchPreviewDatasource.h>
+#import <WhirlyGlobe/MaplyLocationTracker.h>
+#import <WhirlyGlobe/MaplyRenderTarget.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+#import <WhirlyGlobe/MaplyRemoteTileFetcher.h>
+#import <WhirlyGlobe/MaplyVertexAttribute.h>
+
+typedef double (^ZoomEasingBlock)(double z0,double z1,double t);
+typedef void (__strong ^InitCompletionBlock)(void);
+
+/**
+ When selecting multiple objects, one or more of these is returned.
+
+ When you implement one of the selection delegates that takes multiple objects, you'll get an NSArray of these things.
+ */
+@interface MaplySelectedObject : NSObject
+
+/// Object the user selected
+/// This is the original object the user passed in when adding it to the globe or map.
+@property (nonatomic) id __nullable selectedObj;
+
+/// Distance from where the user tapped to the closest part of the object on the screen
+@property double screenDist;
+
+/// Distance from the user's viewpoint to the center of the object in 3-space. Use this for sorting.
+@property double zDist;
+
+/// Set if this was part of a cluster
+@property bool cluster;
+
+@end
+
+/** Snapshot Delegate
+
+ Snapshots can be run as callbacks after the rendering. If you keep your area
+ small enough you can even do it every frame. This is the protocol for
+ snapshot delegates.
+ */
+@protocol MaplySnapshotDelegate
+
+/// Return true if you want a snapshot for this frame
+- (bool)needSnapshot:(NSTimeInterval)now viewC:(MaplyBaseViewController * __nonnull)viewC;
+
+/// If you want the whole thing return CGRectZero, otherwise return the rectangle you want based
+/// on the number of pixels. So multiply by the scale first.
+- (CGRect)snapshotRect;
+
+/// Here's your snapshot data. Do what you will, but do it quickly. You can hold onto the NSData.
+- (void)snapshot:(NSData * __nonnull)snapshotData;
+
+/// If you want a specific render target, return it. Otherwise nil for the screen.
+- (MaplyRenderTarget * __nullable)renderTarget;
+
+@optional
+/// If a render target calculates the min/max values after rendering, this snapshot callback will be called as well
+- (void)snapshotMinMax:(NSData * __nonnull)snapshotData;
+
+@end
+
+
+@protocol MaplyLocationTrackerDelegate;
+
+/**
+ Base class for the Maply and WhirlyGlobe view controllers.
+
+ The Maply Base View Controller is where most of the functionality lives. For the most part Maply and WhirlyGlobe share methods and data structures. This view controller sets up the rendering, the threading, basically everything that makes WhirlyGlobe-Maply work.
+
+ Don't create one of these directly, instead use the MaplyViewController or the WhirlyGlobeViewController.
+ */
+@interface MaplyBaseViewController : UIViewController <MaplyRenderControllerProtocol>
+
+/**
+ Turn selection on or off globally.
+
+ If on we'll forward selected features on to the delegate. When off, we don't do that. On by default.
+ */
+@property(nonatomic,assign) bool selection;
+
+/**
+ Set the globe (not the UIView's) background color.
+
+ This property sets the clear color used by OpenGL. By default it's black.
+ */
+@property (nonatomic,strong) UIColor * __nullable clearColor;
+
+/**
+ Set the frame interval passed to the CADisplayLink.
+
+ This sets the frame rate the renderer will attempt to achieve.
+
+ |value|frames per second|
+ |:----|:----------------|
+ |1|60fps|
+ |2|30fps|
+ |3|20fps|
+ |4|15fps|
+ |5|12fps|
+ |6|Really? No, you can do better.|
+ */
+@property (nonatomic,assign) int frameInterval;
+
+///**
+// The elevation delegate that will provide elevation data per tile.
+//
+// We break the image tiles out from the elevation tiles. The data is often coming from different sources, but in the end this is a probably a hack. It's a hack that's going to be in place for a while.
+//
+// To provide elevation for your compatible MaplyTileSource objects, you fill out the MaplyElevationSourceDelegate protocol and assign the resulting object here. When an image layer needs elevation, it will check for the delegate and then query for the respective file.
+//
+// At present there is no checking for coordinate system compatibility, so be aware.
+// */
+//@property (nonatomic,weak) NSObject<MaplyElevationSourceDelegate> *__nullable elevDelegate;
+
+/**
+ Set the offset for the screen space objects.
+
+ In general you want the screen space objects to appear on top of everything else. There used to be structural reasons for this, but now you can mix and match where everything appears. This controls the offset that's used to push screen space objects behind everything else in the list (and thus, on top).
+
+ If you set this to 0, you can control the ordering of everything more precisely.
+ */
+@property (nonatomic,assign) int screenObjectDrawPriorityOffset;
+
+/**
+ Controls whether objects with unique IDs fade in and out when added or removed from the layout manager
+ */
+@property (nonatomic,assign) bool layoutFade;
+
+/**
+ Controls the way height changes while animating the view
+ For simple, linear zoom use:
+
+ zoomEasing = ^(double z0,double z1,double t) { return z0 + (z1 - z0) * t; };
+ */
+@property (readwrite,copy) ZoomEasingBlock _Nullable animationZoomEasing;
+
+
+/**
+ If in Metal rendering mode, return the Metal device being used.
+ */
+- (id<MTLDevice> __nullable)getMetalDevice;
+
+/**
+ If in Metal rendering mode, return the shader library set up by the toolkit.
+ */
+- (id<MTLLibrary> __nullable)getMetalLibrary;
+
+/**
+ Clear all the currently active lights.
+
+ There are a default set of lights, so you'll want to do this before adding your own.
+ */
+- (void)clearLights;
+
+/**
+ Reset the lighting back to its default state at startup.
+
+ This clears out all the lights and adds in the default starting light source.
+ */
+- (void)resetLights;
+
+/**
+ Add the given light to the list of active lights.
+
+ This method will add the given light to our active lights. Most shaders will recognize these lights and do the calculations. If you have a custom shader in place, it may or may not use these.
+
+ Triangle shaders use the lights, but line shaders do not.
+ */
+- (void)addLight:(MaplyLight *__nonnull)light;
+
+/// Remove the given light (assuming it's active) from the list of lights.
+- (void)removeLight:(MaplyLight *__nonnull)light;
+
+/**
+ Set the rendering hints to control how the renderer is configured.
+
+ This is a bit vestigial, but still has a few important uses. The hints should be set right after the init call. Any later and they'll probably be ignored.
+
+ The rendering hints are as follows.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyRenderHintZBuffer|bool|If set, we'll explicitly turn on the Z buffer. Normally it's off until a drawable requests it, allowing us to play neat tricks with overlays. The only time you should be turning this on is if you're doing 3D elevation. The default is off.|
+ |kMaplyRenderHintCulling|bool|If set, we'll use the internal culling logic. Texture and drawable atlases have largely made this pointless. Leave it off unless you have a compelling reason to turn it on.|
+ |kMaplyRendererLightingMode|NSString|This can be set to @"none", in which case we use optimized shaders that do no lighting or "regular". The latter is the default.|
+ */
+- (void)setHints:(NSDictionary *__nonnull)hintsDict;
+
+/// This calls addScreenMarkers:desc:mode: with mode set to MaplyThreadAny
+- (MaplyComponentObject *__nullable)addScreenMarkers:(NSArray *__nonnull)markers desc:(NSDictionary *__nullable)desc;
+
+/**
+ Add one or more screen markers to the current scene.
+
+ This method will add the given MaplyScreenMaker objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param markers An NSArray of MaplyScreenMarker objects.
+
+ @param desc The desciption dictionary which controls how the markers will be constructed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|The color we'll use for the rectangle that makes up a marker. White by default.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The marker will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The marker will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyDrawPriority|NSNumber|If set, the markers are sorted by this number. Larger numbers will be sorted later.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a marker in when it appears and out when it disappears.|
+ |kMaplyFadeIn|NSNumber|The number of seconds to fade a marker in when it appears. This overrides kMaplyFade.|
+ |kMaplyFadeOut|NSNumber|The number of seconds to fade a marker out when it disappears. This override kMaplyFade.|
+ |kMaplyFadeOutTime|NSNumber|If you want to create an object, just to have it fade out at a specific time, this is what you set.|
+ |kMaplyShader|NSString|If set, this is the name of the MaplyShader to use when rendering the screen markers.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyEnableStart|NSNumber|If set, this controls when the resulting objects will be activated.|
+ |kMaplyEnableEnd|NSNumber|If set, this controls when the resulting objects will be deactivated.|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+ |kMaplyClusterGroup|NSNumber|If set, the screen markers will be clustered together according to the given group ID. Off by default, but 0 is the default cluster.|
+
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addScreenMarkers:(NSArray *__nonnull)markers desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add a cluster generator for making clustered marker images on demand.
+
+ When the layout system clusters a bunch of markers or labels together, it needs new images to represent the cluster.
+
+ You can provide a custom image for each group of markers by filling in one of these generates and passing it in.
+ */
+- (void)addClusterGenerator:(NSObject <MaplyClusterGenerator> *__nonnull)clusterGen;
+
+/// This calls addMarkers:desc:mode: with mode set to MaplyThreadAny
+- (MaplyComponentObject *__nullable)addMarkers:(NSArray *__nonnull)markers desc:(NSDictionary *__nullable)desc;
+
+/**
+ Add one or more 3D markers to the current scene.
+
+ This method will add the given MaplyMarker objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param markers An NSArray of MaplyMarker objects.
+
+ @param desc The desciption dictionary which controls how the markers will be constructed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|The color we'll use for the rectangle that makes up a marker. White by default.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The marker will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The marker will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a marker in when it appears and out when it disappears.|
+ |kMaplyFadeIn|NSNumber|The number of seconds to fade a marker in when it appears. This overrides kMaplyFade.|
+ |kMaplyFadeOut|NSNumber|The number of seconds to fade a marker out when it disappears. This override kMaplyFade.|
+ |kMaplyFadeOutTime|NSNumber|If you want to create an object, just to have it fade out at a specific time, this is what you set.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyMarkerDrawPriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's off by default, meaning that the geometry will draw on top of anything (respecting the kMaplyDrawPriority).|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addMarkers:(NSArray *__nonnull)markers desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/// This calls addScreenLabels:desc:mode: with mode set to MaplyThreadAny
+- (MaplyComponentObject *__nullable)addScreenLabels:(NSArray *__nonnull)labels desc:(NSDictionary *__nullable)desc;
+
+/**
+ Add one or more screen labels to the current scene.
+
+ This method will add the given MaplyScreenLabel objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param labels An NSArray of MaplyScreenLabel objects.
+
+ @param desc The desciption dictionary which controls how the labels will be constructed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyTextColor|UIColor|Color we'll use for the text. Black by default.|
+ |kMaplyBackgroundColor|UIColor|Color we'll use for the rectangle background. Use clearColor to make this invisible.|
+ |kMaplyFont|UIFont|The font we'll use for the text.|
+ |kMaplyLabelHeight|NSNumber|Height of the text in points.|
+ |kMaplyLabelWidth|NSNumber|Width of the text in points. It's best to set Height and leave this out. That way the width will be calculated by the toolkit.|
+ |kMaplyJustify|NSString|This can be set to @"middle", @"left", or @"right" to justify the text around the location.|
+ |kMaplyTextJustify|NSString|This can be kMaplyTextJustifyRight, kMaplyTextJustifyCenter, or kMaplyTextJustifyLeft|
+ |kMaplyShadowSize|NSNumber|If set, we'll draw a shadow with the kMaplyShadowColor offset by this amount. We recommend using an outline instead.|
+ |kMaplyShadowColor|UIColor|If we're drawing a shadow, this is its color.|
+ |kMaplyTextOutlineSize|NSNumber|If set, we'll draw an outline around the text (really draw it twice). The outline will be this large.|
+ |kMaplyTextOutlineColor|UIColor|If we're drawing an outline, it's in this color.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The label will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The label will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyDrawPriority|NSNumber|If set, the labels are sorted by this number. Larger numbers will be sorted later.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a screen label in when it appears and out when it disappears.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyEnableStart|NSNumber|If set, this controls when the resulting objects will be activated.|
+ |kMaplyEnableEnd|NSNumber|If set, this controls when the resulting objects will be deactivated.|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addScreenLabels:(NSArray *__nonnull)labels desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/// This calls addLabels:desc:mode: with mode set to MaplyThreadAny
+- (MaplyComponentObject *__nullable)addLabels:(NSArray *__nonnull)labels desc:(NSDictionary *__nullable)desc;
+
+/**
+ Add one or more 3D labels to the current scene.
+
+ This method will add the given MaplyLabel objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param labels An NSArray of MaplyLabel objects.
+
+ @param desc The desciption dictionary which controls how the labels will be constructed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyTextColor|UIColor|Color we'll use for the text. Black by default.|
+ |kMaplyBackgroundColor|UIColor|Color we'll use for the rectangle background. Use clearColor to make this invisible.|
+ |kMaplyFont|UIFont|The font we'll use for the text.|
+ |kMaplyLabelHeight|NSNumber|Height of the text in display coordinates. For the globe these are based on radius = 1.0.|
+ |kMaplyLabelWidth|NSNumber|Width of the text in display coordinates. It's best to set Height and leave this out. That way the width will be calculated by the toolkit.|
+ |kMaplyJustify|NSString|This can be set to @"middle", @"left", or @"right" to justify the text around the location.|
+ |kMaplyShadowSize|NSNumber|If set, we'll draw a shadow with the kMaplyShadowColor offset by this amount. We recommend using an outline instead.|
+ |kMaplyShadowColor|UIColor|If we're drawing a shadow, this is its color.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The label will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The label will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a label in when it appears and out when it disappears.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyLabelDrawPriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's off by default, meaning that the geometry will draw on top of anything (respecting the kMaplyDrawPriority).|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addLabels:(NSArray *__nonnull)labels desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/// This calls addVectors:desc:mode: with mode set to MaplyThreadAny
+- (MaplyComponentObject *__nullable)addVectors:(NSArray *__nonnull)vectors desc:(NSDictionary *__nullable)desc;
+
+/**
+ Add one or more vectors to the current scene.
+
+ This method will add the given MaplyVectorObject objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param vectors An NSArray of MaplyVectorObject objects.
+
+ @param desc The desciption dictionary which controls how the vectors will look. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the vector features.|
+ |kMaplyVecWidth|NSNumber|If the geometry is not filled, this is the width of the GL lines.|
+ |kMaplyFilled|NSNumber boolean|If set, the areal geometry will be tesselated, taking holes into account. The resulting triangles will be displayed instead of the vectors.|
+ |kMaplySubdivType|NSString|When present, this requests that the geometry be broken up to follow the globe (really only makes sense there). It can be set to kMaplySubdivGreatCircle or kMaplySubdivSimple which do a great circle subdivision and a simple 3-space subdivision respectively. If the key is missing, we do no subdivision at all.|
+ |kMaplySubdivEpsilon|NSNumber|If there's a kMaplySubdivType set this is the epsilon we'll pass into the subdivision routine. The value is in display coordinates. 0.01 is a reasonable value. Smaller results in more subdivision.|
+ |kMaplyVecTexture|UIImage|If set and the kMaplyFilled attribute is set, we will apply the given texture across any areal features. How the texture is applied can be controlled by kMaplyVecTexScaleX, kMaplyVecTexScaleY, kMaplyVecCenterX, kMaplyVecCenterY, and kMaplyVecTextureProjection|
+ |kMaplyVecTexScaleX,kMaplyVecTexScaleY|NSNumber|These control the scale of the texture application. We'll multiply by these numbers before generating texture coordinates from the vertices.|
+ |kMaplyVecCenterX,kMaplyVecCenterY|NSNumber|These control the center of a texture application. If not set we'll use the areal's centroid. If set, we'll use these instead. They should be in local coordinates (probably geographic radians).|
+ |kMaplyVecTextureProjection|NSString|This controls how a texture is projected onto an areal feature. By default we just use the geographic coordinates and stretch them out. This looks odd for very large features. If you set this to kMaplyProjectionTangentPlane then we'll take the center of the feature, make a tangent plane and then project the coordinates onto that tangent plane to get texture coordinates. This looks nice at the poles. If set to kMaplyProjectionScreen the texture is mapped on after screen space projection around the center of the feature.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a vector in when it appears and out when it disappears.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyVectorDrawPriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's off by default, meaning that the geometry will draw on top of anything (respecting the kMaplyDrawPriority).|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplySelectable|NSNumber boolean|Off by default. When enabled, the vector feature will be selectable by a user.|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addVectors:(NSArray *__nonnull)vectors desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Make a copy of the base object and apply the attributes given for the new version.
+
+ This call makes a cheap copy of the vectors in the given MaplyComponentObject and applies the given description to them. You can use this to make a wider or thinner version of a set of vectors, or change their color, while continuing to draw the originals. Or not, as the case may be.
+
+ This is useful for vector maps where we tend to reuse the same geometry at multiple levels and with different colors and line widths.
+
+ Instancing only works with a handful of visual changes. For instance, you can't make a filled and non-filled version.
+
+ @param baseObj The MaplyComponentObject returned by an addVectors: call. This only works for vectors.
+
+ @param desc The description dictionary with controls how vectors will be displayed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the vector features.|
+ |kMaplyVecWidth|NSNumber|If the geometry is not filled, this is the width of the GL lines.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyVectorDrawPriorityDefault.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)instanceVectors:(MaplyComponentObject *__nonnull)baseObj desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more widened vectors to the current scene.
+
+ Build widened vectors
+
+
+ @param desc The description dictionary which controls how vectors will be displayed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the features.|
+ |kMaplyVecWidth|NSNumber|If the geometry is not filled, this is the width of the lines.|
+ |kMaplyWideVecCoordType|NSNumber|Vectors can be widened in real coordinates (kMaplyWideVecCoordTypeReal) or screen coordinates (kMaplyWideVecCoordTypeScreen). In the latter case they stay the same size now matter how you zoom.|
+ |kMaplyWideVecJoinType|NSNumber|When lines meet in a join there are several options for representing them. These include kMaplyWideVecMiterJoin, which is a simple miter join and kMaplyWideVecBevelJoin which is a more complicated bevel. See http://www.w3.org/TR/SVG/painting.html#StrokeLinejoinProperty for how these look.|
+ |kMaplyWideVecMiterLimit|NSNumber|When using miter joins you can trigger them at a certain threshold.|
+ |kMaplyWideVecTexRepeatLen|NSNumber|This is the repeat size for a texture applied along the widened line. For kMaplyWideVecCoordTypeScreen this is pixels.|
+ |kMaplyVecTexture|UIImage or MaplyTexture|This the texture to be applied to the widened vector.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyVectorDrawPriorityDefault.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addWideVectors:(NSArray *__nonnull)vectors desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/// This calls addWideVectors:desc:mode: with mode set to MaplyThreadAny
+- (MaplyComponentObject *__nullable)addWideVectors:(NSArray *__nonnull)vectors desc:(NSDictionary *__nullable)desc;
+
+
+/// This calls addShapes:desc:mode: with mode set to MaplyThreadAny
+- (MaplyComponentObject *__nullable)addShapes:(NSArray *__nonnull)shapes desc:(NSDictionary *__nullable)desc;
+
+/**
+ Add one or more model instances.
+
+ Each MaplyGeomInstance points to a MaplyGeomModel. All those passed in here will be grouped and processed together.
+
+
+ @param desc The description dictionary which controls how the models are displayed, selected, and so forth.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplySelectable|NSNumber boolean|Off by default. When enabled, the vector feature will be selectable by a user.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addModelInstances:(NSArray *__nonnull)modelInstances desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or raw geometry models.
+
+ Each MaplyGeometryModel holds points and triangles in display space. These are relatively "raw" geometry and are passed to the geometry manager as is.
+
+
+ @param desc The description dictionary which controls how the geometry is displayed, selected, and so forth.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplySelectable|NSNumber boolean|Off by default. When enabled, the vector feature will be selectable by a user.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addGeometry:(NSArray *__nonnull)geom desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more MaplyShape children to the current scene.
+
+ This method will add the given MaplyShape derived objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param shapes An NSArray of MaplyShape derived objects.
+
+ @param desc The desciption dictionary which controls how the shapes will look. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the shape features.|
+ |kMaplyShapeSampleX|NSNumber|Number of samples to use in one direction when converting to polygons.|
+ |kMaplyShapeSampleY|NSNumber|Number of samples to use in the other direction when converting to polygons.|
+ |kMaplyShapeInsideOut|NSNumber boolean|If set to YES, we'll make the spheres inside out and such. Set to NO by default.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The shapes will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The shapes will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a shape in when it appears and out when it disappears.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyVectorShapePriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's on by default, meaning that the geometry can be occluded by things drawn first.|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addShapes:(NSArray *__nonnull)shapes desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/// This calls addStickers:desc:mode: with mode set to MaplyThreadAny
+- (MaplyComponentObject *__nullable)addStickers:(NSArray *__nonnull)stickers desc:(NSDictionary *__nullable)desc;
+
+/**
+ Add one or more MaplySticker objects to the current scene.
+
+ This method will add the given MaplySticker objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param stickers An NSArray of MaplySticker derived objects.
+
+ @param desc The desciption dictionary which controls how the stickers will look. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the stickers.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The stickers will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The stickers will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a sticker in when it appears and out when it disappears.|
+ |kMaplySampleX|NSNumber|Stickers are broken up along two dimensions to adhere to the globe. By default this is done adaptively. If you want to override it, this is the X dimension for the sticker.|
+ |kMaplySampleY|NSNumber|If you want to override it, this is the Y dimension for the sticker.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyVectorShapePriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's off by default, meaning that it will draw on top of things before it..|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyShader|NSString|If set, this is the name of the MaplyShader to use when rendering the sticker(s).|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addStickers:(NSArray *__nonnull)stickers desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Modify an existing sticker. This only supports changing the active textures.
+
+ This method will change attributes of a sticker that's currently in use. At present that's just the images it's displaying.
+
+ @param compObj The component object representing one or more existing stickers.
+
+ @param desc The description dictionary for changes we're making to the sticker.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyStickerImages|NSARray|The array of images to apply to the sticker. You can reuse old ones or introduce new ones.|
+ */
+- (void)changeSticker:(MaplyComponentObject *__nonnull)compObj desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more MaplyBillboard objects to the current scene.
+
+ This method will add the given MaplyBillboard objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param billboards An NSArray of MaplyBillboard objects.
+
+ @param desc The description dictionary that controls how the billboards will look. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the billboards.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The billboards will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The billboards will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyBillboardDrawPriorityDefault.|
+ |kMaplyBillboardOrient|NSNumber|Controls the billboard orientation. It's either directly toward the eye with kMaplyBillboardOrientEye or takes the ground into account with kMaplyBillboardOrientGround. Ground is the default.
+
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+ */
+- (MaplyComponentObject *__nullable)addBillboards:(NSArray *__nonnull)billboards desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add a particle system to the scene.
+
+ This adds a particle system to the scene, but does not kick off any particles.
+
+ @param partSys The particle system to start.
+
+ @param desc Any additional standard parameters (none at present).
+
+ @param threadMode MaplyThreadAny will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread. For particles, it's best to make a separate thread and use MaplyThreadCurrent.
+ */
+- (MaplyComponentObject *__nullable)addParticleSystem:(MaplyParticleSystem *__nonnull)partSys desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Change the render target for a particle system.
+
+ This changes the render target for an existing particle system that's already been created.
+ Can pass in nil, which means the particles are rendered to the screen directly.
+ This change takes place immediately, so call it on the main thread.
+ */
+- (void)changeParticleSystem:(MaplyComponentObject *__nonnull)compObj renderTarget:(MaplyRenderTarget *__nullable)target;
+
+/**
+ Add a batch of particles to the current scene.
+
+ Particles are short term objects, typically very small. We create them in large groups for efficience.
+
+ You'll need to fill out the MaplyParticleSystem initially and then the MaplyParticleBatch to create them.
+
+ @param batch The batch of particles to add to an active particle system.
+
+ @param threadMode MaplyThreadAny will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread. For particles, it's best to make a separate thread and use MaplyThreadCurrent.
+ */
+- (void)addParticleBatch:(MaplyParticleBatch *__nonnull)batch mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add vectors that can be used for selections.
+
+ These are MaplyVectorObject's that will show up in user selection, but won't be visible. So if a user taps on one, you get the vector in your delegate. Otherwise, no one will know it's there.
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addSelectionVectors:(NSArray *__nonnull)vectors;
+
+/**
+ Change the representation of the given vector features.
+
+ This will change how any vector features represented by the compObj look.
+
+ You can change kMaplyColor, kMaplyMinVis, kMaplyMaxVis, and kMaplyDrawPriority.
+ */
+- (void)changeVector:(MaplyComponentObject *__nonnull)compObj desc:(NSDictionary *__nullable)desc;
+
+/**
+ Change the representation of the given vector features.
+
+ This will change how any vector features represented by the compObj look.
+
+ You can change kMaplyColor, kMaplyMinVis, kMaplyMaxVis, and kMaplyDrawPriority.
+
+ This version takes a thread mode.
+ */
+- (void)changeVector:(MaplyComponentObject *__nonnull)compObj desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Adds the MaplyVectorObject's passed in as lofted polygons.
+
+ Lofted polygons are filled polygons draped on top of the globe with height. By using a transparent color, these can be used to represent selection or relative values on the globe (or map).
+
+
+ @param polys An NSArray of MaplyVectorObject.
+
+ @param desc The desciption dictionary which controls how the lofted polys will look. It takes the following entries.
+
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the lofted polygons. A bit of alpha looks good.|
+ |kMaplyLoftedPolyHeight|NSNumber|Height of the top of the lofted polygon in display units. For the globe display units are based on a radius of 1.0.|
+ |kMaplyLoftedPolyBase|NSNumber|If present, we'll start the lofted poly at this height. The height is in globe units, based on a radius of 1.0.|
+ |kMaplyLoftedPolyTop|NSNumber boolean|If on we'll create the geometry for the top. On by default.|
+ |kMaplyLoftedPolySide|NSNumber boolean|If on we'll create geometry for the sides. On by default.|
+ |kMaplyLoftedPolyGridSize|NSNumber|The size of the grid (in radians) we'll use to chop up the vector features to make them follow the sphere (for a globe).|
+ |kMaplyLoftedPolyOutline|NSNumber boolean|If set to @(YES) this will draw an outline around the top of the lofted poly in lines.|
+ |kMaplyLoftedPolyOutlineBottom|NSNumber boolean|If set to @(YES) this will draw an outline around the bottom of the lofted poly in lines.|
+ |kMaplyLoftedPolyOutlineColor|UIColor|If the outline is on this is the outline's color.|
+ |kMaplyLoftedPolyOutlineWidth|NSNumber|This is the outline's width if it's turned on.|
+ |kMaplyLoftedPolyOutlineDrawPriority|NSNumber|Draw priority of the lines created for the lofted poly outline.|
+ |kMaplyLoftedPolyOutlineSide|NSNumber boolean|If set and we're drawing an outline, this will create lines up the sides.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The lofted polys will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The lofted polys will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a lofted poly in when it appears and out when it disappears.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyLoftedPolysShapePriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's on by default, meaning that it can be occluded by geometry coming before it.|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addLoftedPolys:(NSArray *__nonnull)polys desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add a group of points to the display.
+
+ Adds a group of points all at once. We're assuming you want to draw a lot of points, so you have to group them together into a MaplyPoints.
+
+
+ @param points The points to add to the scene.
+
+ @param desc The desciption dictionary which controls how the points will look. It takes the following entries.
+
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the lofted polygons. A bit of alpha looks good.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The lofted polys will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The lofted polys will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a lofted poly in when it appears and out when it disappears.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyLoftedPolysShapePriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's on by default, meaning that it can be occluded by geometry coming before it.|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addPoints:(NSArray * __nonnull)points desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/// Add a view tracker to move a UIView around based on a geographic location.
+- (void)addViewTracker:(MaplyViewTracker *__nonnull)viewTrack;
+
+/// Move an existing view tracker to a new location
+- (void)moveViewTracker:(MaplyViewTracker *__nonnull)viewTrack moveTo:(MaplyCoordinate)newPos;
+
+/**
+ Add a single annotation which will track the given point.
+
+ This adds a MaplyAnnotation that will follow the given geo coordinate, applying the screen offset as given.
+
+ @param annotate The annotation we want to track a given point.
+
+ @param coord The location on the map (or globe) we'd like to track.
+
+ @param offset The screen offset for the annotation UIView. You use this to put the annotation above or below objects.
+ */
+- (void)addAnnotation:(MaplyAnnotation *__nonnull)annotate forPoint:(MaplyCoordinate)coord offset:(CGPoint)offset;
+
+/**
+ Remove the given annotation from the UIView.
+
+ This will dismiss the given annotation with its animation.
+ */
+- (void)removeAnnotation:(MaplyAnnotation *__nonnull)annotate;
+
+/**
+ Make the annotation stop moving.
+
+ If you have controls in your annotation you may need to make the annotation stop moving while the user manipulates them. Call this method to freeze the annotation while this happens.
+ */
+- (void)freezeAnnotation:(MaplyAnnotation *__nonnull)annotate;
+
+/**
+ Call this to start an annotation following its location again after being frozen.
+ */
+- (void)unfreezeAnnotation:(MaplyAnnotation *__nonnull)annotate;
+
+/**
+ Calls removeAnnotation: on all outstanding annotations.
+ */
+- (void)clearAnnotations;
+
+/**
+ Return an array of active annotations. Don't modify these.
+ */
+- (NSArray *__nullable)annotations;
+
+/// Remove an existing view tracker.
+- (void)removeViewTrackForView:(UIView *__nonnull)view;
+
+/**
+ Return the location on screen for a given geographic (lon/lat radians) coordinate.
+
+ @return Returns the screen point corresponding to a given geo coordinate.
+ */
+- (CGPoint)screenPointFromGeo:(MaplyCoordinate)geoCoord;
+
+/**
+ Animate the given position to the screen position over time.
+
+ This is similar to animateToPosition:time: except that it will attempt to match up the screen position and the geographic position. This is how you offset the location you're looking at.
+
+ If it's impossible to move newPos to loc, then nothing happens.
+
+ @param newPos The geographic position (lon/lat in radians) to move to.
+
+ @param loc The location on the screen where we'd like it to go.
+
+ @param howLong How long in seconds to take getting there.
+ */
+- (bool)animateToPosition:(MaplyCoordinate)newPos onScreen:(CGPoint)loc time:(NSTimeInterval)howLong;
+
+/**
+ Add an image as a texture and return a MaplyTexture to track it.
+
+ We reference count UIImages attached to Maply objects, but that has a couple of drawbacks. First, it retains the UIImage and if that's large, that's a waste of memory. Second, if you're adding and removing Maply objects you may repeatedly create and delete the same UIImage, which is a waste of CPU.
+
+ This method solves the problem by letting you create the texture associated with the UIImage and use it where you like. You can assign these in any place a UIImage is accepted on Maply objects.
+
+ You don't have call this before using a UIImage in a MaplyScreenMarker or other object. The system takes care of it for you. This is purely for optimization.
+
+ @param image The image we wish to retain the texture for.
+
+ @param imageFormat If we create this image, this is the texture format we want it to use.
+
+ | Image Format | Description |
+ |:-------------|:------------|
+ | MaplyImageIntRGBA | 32 bit RGBA with 8 bits per channel. The default. |
+ | MaplyImageUShort565 | 16 bits with 5/6/5 for RGB and none for A. |
+ | MaplyImageUShort4444 | 16 bits with 4 bits for each channel. |
+ | MaplyImageUShort5551 | 16 bits with 5/5/5 bits for RGB and 1 bit for A. |
+ | MaplyImageUByteRed | 8 bits, where we choose the R and ignore the rest. |
+ | MaplyImageUByteGreen | 8 bits, where we choose the G and ignore the rest. |
+ | MaplyImageUByteBlue | 8 bits, where we choose the B and ignore the rest. |
+ | MaplyImageUByteAlpha | 8 bits, where we choose the A and ignore the rest. |
+ | MaplyImageUByteRGB | 8 bits, where we average RGB for the value. |
+ | MaplyImage4Layer8Bit | 32 bits, four channels of 8 bits each. Just like MaplyImageIntRGBA, but a warning not to do anything too clever in sampling. |
+
+
+ @param wrapFlags These can be MaplyImageWrapX, MaplyImageWrapY, both or none.
+
+
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred.
+
+
+ @return A MaplyTexture you'll want to keep track of. It goes out of scope, the OpenGL ES texture will be deleted.
+ */
+- (MaplyTexture *__nullable)addTexture:(UIImage *__nonnull)image imageFormat:(MaplyQuadImageFormat)imageFormat wrapFlags:(int)wrapFlags mode:(MaplyThreadMode)threadMode;
+
+/**
+ Represent an image as a MaplyTexture.
+
+ This version of addTexture: allows more precise control over how the texture is represented. It replaces the other addTexture: and addTextureToAtlas calls.
+
+ @param image The UIImage to add as a texture.
+
+ @param desc A description dictionary controlling how the image is converted to a texture and represented in the system.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyTexFormat|NSNumber|The texture format to use for the image. Consult addTexture:imageFormat:wrapFlags:mode: for a list. Default is MaplyImageIntRGBA.|
+ |kMaplyTexMinFilter|NSNumber|Filter to use for minification. This can be kMaplyMinFilterNearest or kMaplyMinFilterLinear. Default is kMaplyMinFilterLinear.|
+ |kMaplyTexMagFilter|NSNumber|Filter to use for magnification. This can be kMaplyMinFilterNearest or kMaplyMinFilterLinear. Default is kMaplyMinFilterLinear.|
+ |kMaplyTexWrapX|NSNumber boolean|Texture wraps in x direction. Off by default.|
+ |kMaplyTexWrapY|NSNumber boolean|Texture wraps in y direction. Off by default.|
+ |kMaplyTexAtlas|NSNumber boolean|If set, the texture goes into an appropriate atlas. If not set, it's a standalone texture (default).|
+
+
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred.
+ */
+- (MaplyTexture *__nullable)addTexture:(UIImage *__nonnull)image desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Create an empty texture and return it.
+
+ Empty textures are used for offscreen rendering and other crazy stuff. You probably don't want to do this.
+
+ @param spec The description dictionary controlling the format and other textures goodies.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyTexFormat|NSNumber|The texture format to use for the image. Consult addTexture:imageFormat:wrapFlags:mode: for a list. Default is MaplyImageIntRGBA.|
+ |kMaplyTexMinFilter|NSNumber|Filter to use for minification. This can be kMaplyMinFilterNearest or kMaplyMinFilterLinear. Default is kMaplyMinFilterLinear.|
+ |kMaplyTexMagFilter|NSNumber|Filter to use for magnification. This can be kMaplyMinFilterNearest or kMaplyMinFilterLinear. Default is kMaplyMinFilterLinear.|
+ |kMaplyTexWrapX|NSNumber boolean|Texture wraps in x direction. Off by default.|
+ |kMaplyTexWrapY|NSNumber boolean|Texture wraps in y direction. Off by default.|
+ |kMaplyTexAtlas|NSNumber boolean|If set, the texture goes into an appropriate atlas. If not set, it's a standalone texture (default).|
+
+
+ @param sizeX The horizontal size of the textures (in pixels).
+
+ @param sizeY Vertical size of the texture (in pixels).
+ */
+- (MaplyTexture *__nullable)createTexture:(NSDictionary * _Nullable)spec sizeX:(int)sizeX sizeY:(int)sizeY mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add an image as a texture, but put it in a texture atlas. Return a
+
+ Texture atlases consolidate a number of compatible textures, speeding up rendering of any geometry they're used on. If you know you're going to be using a UIImage with a lot of other images in, say, a group of markers, it's wise to add it here first.
+
+ The entry in a texture atlas will be released when the MaplyTexture is released. So keep a copy of it around if you're going to use it.
+
+ @param image The image we're going to put in the texture.
+
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred if you're on the main thread.
+
+ @return A MaplyTexture you'll want to keep track of. It goes out of scope, the entry in the texture atlas will be cleared.
+ */
+- (MaplyTexture *__nullable)addTextureToAtlas:(UIImage *__nonnull)image mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add an image as a texture, but put it in a texture atlas and return a MaplyTexture to track it.
+
+ Texture atlases consolidate a number of compatible textures, speeding up rendering of any geometry they're used on. If you know you're going to be using a UIImage with a lot of other images in, say, a group of markers, it's wise to add it here first.
+
+ The entry in a texture atlas will be released when the MaplyTexture is released. So keep a copy of it around if you're going to use it.
+
+ @param image The image we're going to put in the texture.
+
+ @param imageFormat If we create this image, this is the texture format we want it to use.
+
+ | Image Format | Description |
+ |:-------------|:------------|
+ | MaplyImageIntRGBA | 32 bit RGBA with 8 bits per channel. The default. |
+ | MaplyImageUShort565 | 16 bits with 5/6/5 for RGB and none for A. |
+ | MaplyImageUShort4444 | 16 bits with 4 bits for each channel. |
+ | MaplyImageUShort5551 | 16 bits with 5/5/5 bits for RGB and 1 bit for A. |
+ | MaplyImageUByteRed | 8 bits, where we choose the R and ignore the rest. |
+ | MaplyImageUByteGreen | 8 bits, where we choose the G and ignore the rest. |
+ | MaplyImageUByteBlue | 8 bits, where we choose the B and ignore the rest. |
+ | MaplyImageUByteAlpha | 8 bits, where we choose the A and ignore the rest. |
+ | MaplyImageUByteRGB | 8 bits, where we average RGB for the value. |
+ | MaplyImage4Layer8Bit | 32 bits, four channels of 8 bits each. Just like MaplyImageIntRGBA, but a warning not to do anything too clever in sampling. |
+
+
+ @param wrapFlags These can be MaplyImageWrapX, MaplyImageWrapY, both or none.
+
+
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred if you're on the main thread.
+
+ @return A MaplyTexture you'll want to keep track of. It goes out of scope, the entry in the texture atlas will be cleared.
+ */
+- (MaplyTexture *__nullable)addTextureToAtlas:(UIImage *__nonnull)image imageFormat:(MaplyQuadImageFormat)imageFormat wrapFlags:(int)wrapFlags mode:(MaplyThreadMode)threadMode;
+
+/**
+ Creates a new texture that references part of an existing texture.
+
+ @param x Horizontal offset within the existing texture.
+ @param y Vertical offset within the existing texture.
+ @param width Width of the chunk to make a new texture.
+ @param height Height of the chunk to make a new texture.
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred if you're on the main thread.
+ */
+- (MaplyTexture *__nullable)addSubTexture:(MaplyTexture *__nonnull)tex xOffset:(int)x yOffset:(int)y width:(int)width height:(int)height mode:(MaplyThreadMode)threadMode;
+
+/**
+ Remove the OpenGL ES texture associated with the given MaplyTexture.
+
+ MaplyTexture's will remove their associated OpenGL textures when they go out of scope. This method does it expicitly and clears out the internals of the MaplyTexture.
+
+ Only call this if you're managing the texture explicitly and know you're finished with them.
+ */
+- (void)removeTexture:(MaplyTexture *__nonnull)image mode:(MaplyThreadMode)threadMode;
+
+/**
+ Remove the OpenGL ES textures associated with the given MaplyTextures.
+
+ MaplyTextures will remove their associated OpenGL textures when they go out of scope. This method does it expicitly and clears out the internals of the MaplyTexture.
+
+ Only call this if you're managing the texture explicitly and know you're finished with them.
+ */
+- (void)removeTextures:(NSArray *__nonnull)texture mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add a render target to the system
+
+ Sets up a render target and will start rendering to it on the next frame.
+
+ Keep the render target around so you can remove it later.
+ */
+- (void)addRenderTarget:(MaplyRenderTarget * _Nonnull)renderTarget;
+
+/**
+ Set the texture a given render target is writing to.
+
+ Render targets start out with one, but you may wish to change it.
+ */
+- (void)changeRenderTarget:(MaplyRenderTarget * __nonnull)renderTarget tex:(MaplyTexture * __nullable)tex;
+
+/**
+ Request a one time clear for the render target.
+
+ Rather than clearing every frame, you may want to specifically request a clear. This will
+ be executed at the next frame and then not again.
+ */
+- (void)clearRenderTarget:(MaplyRenderTarget * __nonnull)renderTarget mode:(MaplyThreadMode)threadMode;
+
+/**
+ Remove the given render target from the system.
+
+ Ask the system to stop drawing to the given render target. It will do this on the next frame.
+ */
+- (void)removeRenderTarget:(MaplyRenderTarget * _Nonnull)renderTarget;
+
+/**
+ Set the max number of objects for the layout engine to display.
+
+ The layout engine works with screen objects, such MaplyScreenLabel and MaplyScreenMaker. If those have layoutImportance set, this will control the maximum number we can display.
+ */
+- (void)setMaxLayoutObjects:(int)maxLayoutObjects;
+
+/**
+ Screen markers and labels can have uniqueIDs. We use these to ensure we're only displaying one version of an object with, say, vector tiles
+ that load multiple levels.
+
+ Now let's say you want to select some objects. This will let you pull them out of the usual layout logic so they'll always be displayed.
+ */
+- (void)setLayoutOverrideIDs:(NSArray *__nullable)uuids;
+
+
+
+/**
+ Normally the layout layer runs periodically if you change something or when you move around.
+ You can ask it to run ASAP right here. Layout runs on its own thread, so there may still be a delay.
+ */
+- (void)runLayout;
+
+/// Calls removeObjects:mode: with MaplyThreadAny.
+- (void)removeObject:(MaplyComponentObject *__nonnull)theObj;
+
+/// Calls removeObjects:mode: with MaplyThreadAny.
+- (void)removeObjects:(NSArray *__nonnull)theObjs;
+
+/**
+ Remove all information associated with the given MaplyComponentObject's.
+
+ Every add call returns a MaplyComponentObject. This will remove any visible features, textures, selection data, or anything else associated with it.
+
+ @param theObjs The MaplyComponentObject's we wish to remove.
+
+ @param threadMode For MaplyThreadAny we'll do the removal on another thread. For MaplyThreadCurrent we'll block the current thread to finish the removal. MaplyThreadAny is preferred.
+ */
+- (void)removeObjects:(NSArray *__nonnull)theObjs mode:(MaplyThreadMode)threadMode;
+
+/**
+ Disable a group of MaplyComponentObject's all at once.
+
+ By default all of the geometry created for a given object will appear. If you set kMaplyEnable to @(NO) then it will exist, but not appear. This has the effect of setting kMaplyEnable to @(NO).
+
+ @param theObjs The objects to disable.
+
+ @param threadMode For MaplyThreadAny we'll do the disable on another thread. For MaplyThreadCurrent we'll block the current thread to finish the disable. MaplyThreadAny is preferred.
+ */
+- (void)disableObjects:(NSArray *__nonnull)theObjs mode:(MaplyThreadMode)threadMode;
+
+/**
+ Enable a group of MaplyComponentObject's all at once.
+
+ By default all of the geometry created for a given object will appear. If you set kMaplyEnable to @(NO) then it will exist, but not appear. This has the effect of setting kMaplyEnable to @(YES).
+
+ @param theObjs The objects to enable.
+
+ @param threadMode For MaplyThreadAny we'll do the enable on another thread. For MaplyThreadCurrent we'll block the current thread to finish the enable. MaplyThreadAny is preferred.
+*/
+- (void)enableObjects:(NSArray *__nonnull)theObjs mode:(MaplyThreadMode)threadMode;
+
+/**
+ Set the representation to use for the matching UUIDs by specifying the UUIDs directly.
+
+ @param uuids Array of NSString, the UUIDs to update
+ @param repName The representation value to apply, nil to return to the default
+*/
+- (void)setRepresentation:(NSString *__nullable)repName
+ ofUUIDs:(NSArray<NSString *> *__nonnull)uuids;
+
+/**
+ Set the representation to use for the matching UUIDs by specifying the UUIDs directly.
+
+ @param repName The representation value to apply, nil to return to the default
+ @param fallbackRepName The representation to use if there are no matches
+ @param uuids Array of NSString, the UUIDs to update
+*/
+- (void)setRepresentation:(NSString *__nullable)repName
+ fallbackRepName:(NSString *__nullable)fallbackRepName
+ ofUUIDs:(NSArray<NSString *> *__nonnull)uuids;
+
+/**
+ Set the representation to use for the matching UUIDs by specifying the UUIDs directly.
+
+ @param uuids Array of NSString, the UUIDs to update
+ @param repName The representation value to apply, nil to return to the default
+ @param threadMode For MaplyThreadAny we'll do the enable on another thread. For MaplyThreadCurrent we'll block the current thread to finish the enable. MaplyThreadAny is preferred.
+*/
+- (void)setRepresentation:(NSString *__nullable)repName
+ ofUUIDs:(NSArray<NSString *> *__nonnull)uuids
+ mode:(MaplyThreadMode)threadMode;
+
+/**
+ Set the representation to use for the matching UUIDs by specifying the UUIDs directly.
+
+ @param uuids Array of NSString, the UUIDs to update
+ @param repName The representation value to apply, nil to return to the default
+ @param fallbackRepName The representation to use if there are no matches
+ @param threadMode For MaplyThreadAny we'll do the enable on another thread. For MaplyThreadCurrent we'll block the current thread to finish the enable. MaplyThreadAny is preferred.
+*/
+- (void)setRepresentation:(NSString *__nullable)repName
+ fallbackRepName:(NSString *__nullable)fallbackRepName
+ ofUUIDs:(NSArray<NSString *> *__nonnull)uuids
+ mode:(MaplyThreadMode)threadMode;
+
+/**
+ Set the representation to use for the UUIDs of the given objects.
+
+ @param objects Array of ComponentObject, the UUIDs to update
+ @param repName The representation value to apply, nil to return to the default
+*/
+- (void)setRepresentation:(NSString *__nullable)repName
+ ofObjects:(NSArray<MaplyComponentObject *> *__nonnull)objects;
+
+/**
+ Set the representation to use for the UUIDs of the given objects.
+
+ @param objects Array of ComponentObject, the UUIDs to update
+ @param repName The representation value to apply, nil to return to the default
+*/
+- (void)setRepresentation:(NSString *__nullable)repName
+ fallbackRepName:(NSString *__nullable)fallbackRepName
+ ofObjects:(NSArray<MaplyComponentObject *> *__nonnull)objects;
+
+/**
+ Set the representation to use for the UUIDs of the given objects.
+
+ @param objects Array of ComponentObject, the UUIDs to update
+ @param repName The representation value to apply, nil to return to the default
+ @param fallbackRepName The representation to use if there are no matches
+ @param threadMode For MaplyThreadAny we'll do the enable on another thread. For MaplyThreadCurrent we'll block the current thread to finish the enable. MaplyThreadAny is preferred.
+*/
+- (void)setRepresentation:(NSString *__nullable)repName
+ fallbackRepName:(NSString *__nullable)fallbackRepName
+ ofObjects:(NSArray<MaplyComponentObject *> *__nonnull)objects
+ mode:(MaplyThreadMode)threadMode;
+
+/**
+ Pass a uniform block through to a shader. Only for Metal.
+
+ Custom Metal shaders may have their own uniform blocks associated with a known bufferID.
+ This is how you pass those through for objects you've already created.
+ Useful for things like custom animation.
+ */
+- (void)setUniformBlock:(NSData *__nonnull)uniBlock buffer:(int)bufferID forObjects:(NSArray<MaplyComponentObject *> *__nonnull)compObjs mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add the given active object to the scene.
+
+ Active objects are used for immediate, frame based updates. They're fairly expensive, so be careful. After you create one, you add it to the scene here.
+ */
+- (void)addActiveObject:(MaplyActiveObject *__nonnull)theObj;
+
+/// Remove an active object from the scene.
+- (void)removeActiveObject:(MaplyActiveObject *__nonnull)theObj;
+
+/// Remove an array of active objects from the scene
+- (void)removeActiveObjects:(NSArray *__nonnull)theObjs;
+
+/**
+ Add a MaplyControllerLayer to the globe or map.
+
+ At present, layers are for paged geometry such as image tiles or vector tiles. You can create someting like a MaplyQuadImageTilesLayer, set it up and then hand it to addLayer: to add to the scene.
+ */
+- (bool)addLayer:(MaplyControllerLayer *__nonnull)layer;
+
+/// Remove a MaplyControllerLayer from the globe or map.
+- (void)removeLayer:(MaplyControllerLayer *__nonnull)layer;
+
+/// Remove zero or more MaplyControllerLayer objects from the globe or map.
+- (void)removeLayers:(NSArray *__nonnull)layers;
+
+/// Remove all the user created MaplyControllerLayer objects from the globe or map.
+- (void)removeAllLayers;
+
+/**
+ Utility routine to convert from a lat/lon (in radians) to display coordinates
+
+ This is a simple routine to get display coordinates from geocoordinates. Display coordinates for the globe are based on a radius of 1.0 and an origin of (0,0,0).
+
+ @return The input coordinate in display coordinates.
+ */
+- (MaplyCoordinate3d)displayPointFromGeo:(MaplyCoordinate)geoCoord;
+
+/**
+ Utility routine to convert from a lat/lon (in radians) to display coordinates
+
+ This is a simple routine to get display coordinates from geocoordinates. Display coordinates for the globe are based on a radius of 1.0 and an origin of (0,0,0).
+
+ @return The input coordinate in display coordinates.
+ */
+- (MaplyCoordinate3dD)displayPointFromGeoD:(MaplyCoordinate)geoCoord;
+
+/**
+ Utility routine to convert from a lat/lon (in radians) to display coordinates
+
+ This is a simple routine to get display coordinates from geocoordinates. Display coordinates for the globe are based on a radius of 1.0 and an origin of (0,0,0).
+
+ @return The input coordinate in display coordinates.
+ */
+- (MaplyCoordinate3dD)displayPointFromGeoDD:(MaplyCoordinateD)geoCoord;
+
+/**
+ If you've paused the animation earlier, this will start it again.
+
+ The renderer relies on a CADisplayLink. If it's paused, this will unpause it.
+ */
+- (void)startAnimation;
+
+/**
+ Pause the animation.
+
+ The renderer relies on a CADisplayLink. This will pause it. You'll want to do this if your app is going into the background or if you generally want the OpenGL ES code to stop doing anything.
+ */
+- (void)stopAnimation;
+
+/**
+ This shuts down the rendering and it cannot be restarted.
+
+ There are times we need to explicitly shut down the rendering rather than wait for an unload or release. This will do that.
+ */
+- (void)teardown;
+
+/**
+ Add a compiled shader. We'll refer to it by the scene name.
+
+ Once you've create a MaplyShader, you'll need to add it to the scene to use it.
+
+ @param shader The working shader (be sure valid is true) to add to the scene.
+
+ |Scene Name|Purpose|
+ |:---------|:------|
+ |kMaplyShaderDefaultTri|The shader used on triangles by default when there is lighting.|
+ |kMaplyShaderDefaultTriNoLighting|The shader used when lighting is explicitly turned off.|
+ |kMaplyShaderDefaultTriMultiTex|The shader used when drawables have more than one texture.|
+ |kMaplyShaderDefaultLine|The shader used for line drawing on the globe. This does a tricky bit of backface culling.|
+ |kMaplyShaderDefaultLineNoBackface|The shader used for line drawing on the map. This does no backface culling.|
+ */
+- (void)addShaderProgram:(MaplyShader *__nonnull)shader;
+
+/**
+ Look for a shader with the given name.
+
+ This is the shader's own name as specified in the init call, not the scene name as might be specified in addShaderProgram:sceneName:
+
+ @return Returns the registered shader if it found one.
+ */
+- (MaplyShader *__nullable)getShaderByName:(NSString *__nonnull)name;
+
+/**
+ Remove a shader that was added earlier.
+ */
+- (void)removeShaderProgram:(MaplyShader *__nonnull)shader;
+
+/**
+ Return the current map scale from the viewpoint.
+
+ Calculate the map scale denominator (ala Mapnik) based on the current screen size and the 3D viewport.
+
+ @return Returns the map scale denominator or MAXFLOAT if the system is not yet initialized.
+ */
+- (float)currentMapScale;
+
+/**
+ Calculate the height that corresponds to a given Mapnik-style map scale.
+
+ Figure out the viewer height that corresponds to a given scale denominator (ala Mapnik).
+
+ This height will probably be use for visibility ranges on geometry. This works as a mechanism for making geometry appear at certain map scales and disappear at others.
+
+ @return Returns the height or 0.0 if the system isn't initialized yet.
+ */
+- (float)heightForMapScale:(float)scale;
+
+/**
+ Takes a snapshot of the current OpenGL view and returns it.
+ */
+- (UIImage *__nullable)snapshot;
+
+/**
+ Return the raw data for a render target.
+
+ Copies the pixels for a render target out after rendering and returns them in an NSData object.
+ This is not fast. Don't call it often.
+ */
+- (NSData * __nullable)shapshotRenderTarget:(MaplyRenderTarget * __nonnull)renderTarget;
+
+/** Add a snapshot delegate.
+
+ If you need more regular snapshots, you can fill this in to get a callback every frame.
+ Don't snapshot the screen or even offscreen render targets every frame. It'll be slow.
+ */
+- (void)addSnapshotDelegate:(NSObject<MaplySnapshotDelegate> *__nonnull)snapshotDelegate;
+
+/** Remove your snapshot delegate.
+
+ Don't getting screenshots/render target snapshots? Get rid of your delegate. They're expensive.
+ */
+- (void)removeSnapshotDelegate:(NSObject<MaplySnapshotDelegate> *__nonnull)snapshotDelegate;
+
+
+/**
+ Return the current map zoom from the viewpoint.
+
+ Calculate the map zoom (TMS) based on the current screen size and the 3D viewport.
+
+ @param coordinate the location to calculate for. This is needed because zoom is dependant on latitude.
+
+ @return Returns the map zoom or MAXFLOAT if the system is not yet initialized.
+ */
+- (float)currentMapZoom:(MaplyCoordinate)coordinate;
+
+/**
+ Return the coordinate system being used for the display.
+
+ This returns the local coordinate system, which is used to unroll the earth (for the globe) or via a scaling factor (for the flat map).
+ */
+- (MaplyCoordinateSystem *__nullable)coordSystem;
+
+/**
+ Convert from a local coordinate (probably spherical mercator) to a display coordinate.
+
+ This converts from a local coordinate (x,y,height) in the view controller's coordinate system (probably spherical mercator) to a coordinate in display space. For the globe display space is based on a radius of 1.0. For the flat map it's just stretched with a similar factor.
+ */
+- (MaplyCoordinate3d)displayCoordFromLocal:(MaplyCoordinate3d)localCoord;
+
+/**
+ Convert from a local coordinate (probably spherical mercator) to a display coordinate.
+
+ This converts from a local coordinate (x,y,height) in the view controller's coordinate system (probably spherical mercator) to a coordinate in display space. For the globe display space is based on a radius of 1.0. For the flat map it's just stretched with a similar factor.
+ */
+- (MaplyCoordinate3dD)displayCoordFromLocalD:(MaplyCoordinate3dD)localCoord;
+
+/**
+ Convert from a coordinate in the given system to display space.
+
+ This converts from a coordinate (3d) in the given coordinate system to the view controller's display space. For the globe, display space is based on a radius of 1.0.
+ */
+- (MaplyCoordinate3d)displayCoord:(MaplyCoordinate3d)localCoord fromSystem:(MaplyCoordinateSystem *__nonnull)coordSys;
+
+/**
+ Convert from a coordinate in the given system to display space.
+
+ This converts from a double coordinate (3d) in the given coordinate system to the view controller's display space. For the globe, display space is based on a radius of 1.0.
+ */
+- (MaplyCoordinate3dD)displayCoordD:(MaplyCoordinate3dD)localCoord fromSystem:(MaplyCoordinateSystem *__nonnull)coordSys;
+
+/**
+ enable 3d touch object selection.
+
+ @param previewDataSource Data source to provide 3d touch preview view controllers.
+
+ @return true if 3d touch could be enabled
+ */
+- (BOOL)enable3dTouchSelection:(NSObject<Maply3dTouchPreviewDatasource> *__nonnull)previewDataSource;
+
+/**
+ Disable 3dtouch object selection
+ */
+- (void)disable3dTouchSelection;
+
+/**
+ Return all the selectable vector objects at the given location.
+
+ Objects can be selected via the delegate or the search can be run directly here.
+
+ This is not thread safe and will block the main thread.
+ */
+- (NSArray * _Nullable)objectsAtCoord:(MaplyCoordinate)coord;
+
+/**
+ Return all the selectable labels and markers at the given location.
+
+ Objects can be selected via the delegate or the search can be run directly here.
+
+ This is not thread safe and will block the main thread.
+ */
+- (NSArray * _Nullable)labelsAndMarkersAtCoord:(MaplyCoordinate)coord;
+
+/// Turn on/off performance output (goes to the log periodically).
+@property (nonatomic,assign) bool performanceOutput;
+
+/// Turn on/off debug outlines for layout objects
+@property (nonatomic,assign) bool showDebugLayoutBoundaries;
+
+/**
+ See derived class method.
+ */
+- (void)requirePanGestureRecognizerToFailForGesture:(UIGestureRecognizer *__nullable)other;
+
+/**
+ Start location tracking
+
+ @param delegate The MaplyLocationTrackerDelegate for receiving location event callbacks
+
+ @param useHeading Use location services heading information (requires physical magnetometer)
+
+ @param useCourse Use location services course information as fallback if heading unavailable
+ */
+- (void)startLocationTrackingWithDelegate:(NSObject<MaplyLocationTrackerDelegate> *__nullable)delegate
+ useHeading:(bool)useHeading
+ useCourse:(bool)useCourse;
+
+/**
+ Start location tracking
+
+ @param delegate The MaplyLocationTrackerDelegate for receiving location event callbacks
+
+ @param simulator The MaplyLocationSimulatorDelegate for producing locations
+
+ @param simInterval The time interval on which to update
+
+ @param useHeading Use location services heading information (requires physical magnetometer)
+
+ @param useCourse Use location services course information as fallback if heading unavailable
+ */
+- (void)startLocationTrackingWithDelegate:(NSObject<MaplyLocationTrackerDelegate> *__nullable)delegate
+ simulator:(NSObject<MaplyLocationSimulatorDelegate> *__nullable)simulator
+ simInterval:(NSTimeInterval)simInterval
+ useHeading:(bool)useHeading
+ useCourse:(bool)useCourse;
+
+/**
+ Return the current location tracker, if there is one.
+ */
+- (MaplyLocationTracker * __nullable)getLocationTracker;
+
+/**
+ Change lock type for location tracking
+
+ @param lockType The MaplyLocationLockType value for lock behavior
+ */
+- (void)changeLocationTrackingLockType:(MaplyLocationLockType)lockType;
+
+/**
+ Change lock type for location tracking
+
+ @param lockType The MaplyLocationLockType value for lock behavior
+
+ @param forwardTrackOffset The vertical offset if using MaplyLocationLockHeadingUpOffset (positive values are below the view center)
+ */
+- (void)changeLocationTrackingLockType:(MaplyLocationLockType)lockType forwardTrackOffset:(int)forwardTrackOffset;
+
+/**
+ Stop location tracking
+ */
+- (void)stopLocationTracking;
+
+/**
+ Get the current location tracker device location
+
+ @return The coordinate if valid, else kMaplyNullCoordinate
+ */
+- (MaplyCoordinate)getDeviceLocation;
+
+/**
+ Exposes MaplyLocationTracker's location manager for use elsewhere
+
+ @return The CLLocationmanager if it exists, else nil
+ */
+- (CLLocationManager * _Nullable )getTrackingLocationManager;
+
+/**
+ Return all layers loaded by user.
+
+ All layers loaded by user than are currently loaded.
+ */
+-(NSArray * _Nonnull)loadedLayers;
+
+/// Return the renderer type being used
+- (MaplyRenderType)getRenderType;
+
+/**
+ Blocks to be called after the view is set up, or immediately if it is already set up.
+ Similar to `addPostSurfaceRunnable` on Android.
+*/
+- (void)addPostInitBlock:(_Nonnull InitCompletionBlock)block;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyBillboard.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyBillboard.h
new file mode 100644
index 0000000..f29eb87
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyBillboard.h
@@ -0,0 +1,74 @@
+/*
+ * MaplyBillboard.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 10/28/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyScreenObject.h>
+
+/**
+ A billboard is tied to a specific point, but rotates to face the user.
+
+ The billboard object represents a rectangle which is rooted at a specific point, but will rotate to face the user. These are typically used in 3D, when the globe or map has a tilt. They make little sense in 2D.
+ */
+@interface MaplyBillboard : NSObject
+
+/**
+ The point this billboard is rooted at.
+
+ The x and y coordinates are radians. The z coordinate is in meters.
+ */
+@property (nonatomic) MaplyCoordinate3d center;
+
+/// Set if you want to select these
+@property (nonatomic) bool selectable;
+
+/// The 2D polygonal description of what the billboard should be
+@property (nonatomic,strong) MaplyScreenObject * __nullable screenObj;
+
+/**
+ Vertex attributes to apply to this billboard.
+
+ MaplyVertexAttribute objects are passed all the way to the shader. Read that page for details on what they do.
+
+ The array of vertex attributes provided here will be copied onto all the vertices we create for the shader. This means you can use these to do things for a single billboard in your shader.
+ */
+@property (nonatomic,strong) NSArray * __nullable vertexAttributes;
+
+/**
+ User data object for selection
+
+ When the user selects a feature and the developer gets it in their delegate, this is an object they can use to figure out what the screen label means to them.
+ */
+@property (nonatomic,strong) id __nullable userObject;
+
+/**
+ Initialize with a single image, a given background and a size.
+
+ This will create a simple billboard with a single image pasted on it.
+
+ @param texture This can either be a UIImage or a MaplyTexture.
+
+ @param color Color for the polygon that makes up the billboard.
+
+ @param size Size of the billboard in display space.
+ */
+- (nullable instancetype)initWithImage:(id __nonnull)texture color:(UIColor * __nonnull)color size:(CGSize)size;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyBridge.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyBridge.h
new file mode 100644
index 0000000..d0e9832
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyBridge.h
@@ -0,0 +1,23 @@
+/* MaplyBridge.h
+ * MaplyBridge
+ *
+ * Created by jmnavarro on 7/19/15.
+ * Copyright 2015-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyComponent.h>
+#import <WhirlyGlobe/MaplyBaseViewController.h>
+#import <WhirlyGlobe/WhirlyGlobeViewController.h>
+#import <WhirlyGlobe/MaplyGlobeRenderController.h>
+#import <WhirlyGlobe/MaplyViewController.h>
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyCluster.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyCluster.h
new file mode 100644
index 0000000..d874bb3
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyCluster.h
@@ -0,0 +1,147 @@
+/*
+ * MaplyCluster.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 9/29/15.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyScreenMarker.h>
+#import <WhirlyGlobe/MaplyShader.h>
+
+@class MaplyBaseViewController;
+
+/**
+ Information about the group of objects to cluster.
+
+ This object is passed in when the developer needs to make an image for a group of objects.
+ */
+@interface MaplyClusterInfo : NSObject
+
+/// Number of objects being clustered
+@property (nonatomic,assign) int numObjects;
+
+/// All the unique IDs from the
+@property (nonatomic,retain) NSArray<NSString *> * __nullable uniqueIDs;
+
+@end
+
+/**
+ Visual representation for a group of markers.
+
+ Fill this in when you're implementing a MaplyClusterGenerator.
+ */
+@interface MaplyClusterGroup : NSObject
+
+/// The image to use for the group
+@property (nonatomic,strong) id __nonnull image;
+
+/// Screen size to use for the resulting marker
+@property (nonatomic,assign) CGSize size;
+
+/// Size used for layout. If it's not set, we use the regular size.
+@property (nonatomic,assign) CGSize layoutSize;
+
+@end
+
+/**
+ Fill in this protocol to provide images when individual markers/labels are clustered.
+
+ This is the protocol for marker/label clustering. You must fill this in and register the cluster
+ */
+@protocol MaplyClusterGenerator <NSObject>
+
+/**
+ Called at the start of clustering.
+
+ Called right before we start generating clusters. Do you setup here if need be.
+ */
+- (void) startClusterGroup;
+
+/**
+ Generate a cluster group for a given collection of markers.
+
+ Generate an image and size to represent the number of marker/labels we're consolidating.
+
+ @note Will not be called if @c -showMarkerWithHighestImportance returns @c true.
+ */
+- (MaplyClusterGroup *__nonnull) makeClusterGroup:(MaplyClusterInfo *__nonnull)clusterInfo;
+
+/**
+ Called at the end of clustering.
+
+ If you were doing optimization (for image reuse, say) clean it up here.
+ */
+- (void) endClusterGroup;
+
+/// Return the cluster number we're covering
+- (int) clusterNumber;
+
+/// The size of the cluster that will be created.
+/// This is the biggest cluster you're likely to create. We use it to figure overlaps between clusters.
+- (CGSize) clusterLayoutSize;
+
+/// Use appearance and coordinate of cluster group marker with highest importance. If not set then an average of coordinates will be used
+- (bool) showMarkerWithHighestImportance;
+
+/// Set this if you want cluster to be user selectable. On by default.
+- (bool) selectable;
+
+/// How long to animate markers the join and leave a cluster
+- (double) markerAnimationTime;
+
+/// The shader to use for moving objects around
+/// If you're doing animation from point to cluster you need to provide a suitable shader.
+- (MaplyShader *__nullable) motionShader;
+
+@end
+
+/**
+ The basic cluster generator installed by default.
+
+ This cluster generator will make images for grouped clusters of markers/labels.
+ */
+@interface MaplyBasicClusterGenerator : NSObject <MaplyClusterGenerator>
+
+/**
+ Initialize with a list of colors.
+
+ Initialize with a list of colors. Each order of magnitude will use another color. Must provide at least 1.
+ */
+- (nonnull instancetype)initWithColors:(NSArray *__nonnull)colors clusterNumber:(int)clusterNumber size:(CGSize)markerSize viewC:(NSObject<MaplyRenderControllerProtocol> *__nonnull)viewC;
+
+/// The ID number corresponding to the cluster. Every marker/label with this cluster ID will be grouped together.
+@property (nonatomic,assign) int clusterNumber;
+
+/// The size of the cluster that will be created.
+/// This is the biggest cluster you're likely to create. We use it to figure overlaps between clusters.
+@property (nonatomic) CGSize clusterLayoutSize;
+
+/// Set to use appearance and coordinate of cluster group marker with highest importance. Off by default.
+@property (nonatomic) bool showMarkerWithHighestImportance;
+
+/// Set this if you want cluster to be user selectable. On by default.
+@property (nonatomic) bool selectable;
+
+/// How long to animate markers the join and leave a cluster
+@property (nonatomic) double markerAnimationTime;
+
+/// The shader to use when moving objects around
+/// When warping objects to their new locations we use a motion shader. Set this if you want to override the default.
+@property (nonatomic,strong) MaplyShader * __nullable motionShader;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyColorRampGenerator.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyColorRampGenerator.h
new file mode 100644
index 0000000..95d2331
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyColorRampGenerator.h
@@ -0,0 +1,42 @@
+//
+// MaplyColorRampGenerator.h
+// WhirlyGlobe-MaplyComponent
+//
+// Created by Steve Gifford on 4/20/16.
+//
+//
+
+#import <UIKit/UIKit.h>
+
+/** The color ramp generator will take a set of color values
+ and generate a linear ramp of those colors in an output
+ image. You typically feed the color ramp image into a shader.
+ */
+@interface MaplyColorRampGenerator : NSObject
+
+// If set we'll stretch the colors out to the whole image
+// On by default.
+@property (nonatomic,assign) bool stretch;
+
+/// Add a color as a hex value.
+- (void)addHexColor:(int)hexColor;
+
+/// This color has an alpha too
+- (void)addHexColorWithAlpha:(int)hexColor;
+
+/// A color that's present in only one entry
+- (void)addSingleEntryColor:(UIColor *)color;
+
+/// Add a color as a UIColor
+- (void)addColor:(UIColor *)color;
+
+/// Add color with values expressed as integers 0-255
+- (void)addByteRed:(int)red green:(int)green blue:(int)blue alpha:(int)alpha;
+
+/// Generate the image with the color ramp in it
+- (UIImage *)makeImage:(CGSize)size;
+
+/// Get a list of colors (rather than generating an image)
+- (NSArray *)getColors;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyComponent.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyComponent.h
new file mode 100644
index 0000000..1d51b1b
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyComponent.h
@@ -0,0 +1,102 @@
+/* MaplyComponent.h
+ * MaplyComponent
+ *
+ * Created by Steve Gifford on 9/6/12.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplySharedAttributes.h>
+
+#import <WhirlyGlobe/NSData+Zlib.h>
+#import <WhirlyGlobe/NSDictionary+StyleRules.h>
+
+#import <WhirlyGlobe/MaplyGeomBuilder.h>
+#import <WhirlyGlobe/MaplyIconManager.h>
+#import <WhirlyGlobe/MaplyLocationTracker.h>
+#import <WhirlyGlobe/MaplyTextureBuilder.h>
+
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+#import <WhirlyGlobe/MaplyMatrix.h>
+
+#import <WhirlyGlobe/MaplyActiveObject.h>
+#import <WhirlyGlobe/MaplyAnnotation.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+#import <WhirlyGlobe/MaplyUpdateLayer.h>
+#import <WhirlyGlobe/MaplyViewTracker.h>
+#import <WhirlyGlobe/MaplyControllerLayer.h>
+#import <WhirlyGlobe/MaplyViewController.h>
+#import <WhirlyGlobe/MaplyBaseViewController.h>
+
+#import <WhirlyGlobe/MaplyComponentObject.h>
+#import <WhirlyGlobe/MaplyBillboard.h>
+#import <WhirlyGlobe/MaplyCluster.h>
+#import <WhirlyGlobe/MaplyLabel.h>
+#import <WhirlyGlobe/MaplyGeomModel.h>
+#import <WhirlyGlobe/MaplyMarker.h>
+#import <WhirlyGlobe/MaplyMoon.h>
+#import <WhirlyGlobe/MaplyParticleSystem.h>
+#import <WhirlyGlobe/MaplyPoints.h>
+#import <WhirlyGlobe/MaplySticker.h>
+#import <WhirlyGlobe/MaplyShape.h>
+#import <WhirlyGlobe/MaplyScreenLabel.h>
+#import <WhirlyGlobe/MaplySun.h>
+#import <WhirlyGlobe/MaplyScreenObject.h>
+#import <WhirlyGlobe/MaplyScreenMarker.h>
+#import <WhirlyGlobe/MaplyStarsModel.h>
+#import <WhirlyGlobe/MaplyTexture.h>
+#import <WhirlyGlobe/MaplyVectorObject.h>
+
+#import <WhirlyGlobe/MapboxVectorTiles.h>
+#import <WhirlyGlobe/MapboxVectorInterpreter.h>
+
+#import <WhirlyGlobe/SLDStyleSet.h>
+#import <WhirlyGlobe/SLDExpressions.h>
+#import <WhirlyGlobe/SLDOperators.h>
+#import <WhirlyGlobe/SLDSymbolizers.h>
+#import <WhirlyGlobe/SLDWellKnownMarkers.h>
+#import <WhirlyGlobe/MaplyVectorStyle.h>
+#import <WhirlyGlobe/MaplyVectorStyleSimple.h>
+#import <WhirlyGlobe/MaplyVectorTileLineStyle.h>
+#import <WhirlyGlobe/MaplyVectorTileMarkerStyle.h>
+#import <WhirlyGlobe/MaplyVectorTilePolygonStyle.h>
+#import <WhirlyGlobe/MaplyVectorTileStyle.h>
+#import <WhirlyGlobe/MaplyVectorTileTextStyle.h>
+#import <WhirlyGlobe/MapboxVectorStyleSet.h>
+#import <WhirlyGlobe/MapnikStyle.h>
+#import <WhirlyGlobe/MapnikStyleRule.h>
+#import <WhirlyGlobe/MapnikStyleSet.h>
+
+#import <WhirlyGlobe/MaplyQuadLoader.h>
+#import <WhirlyGlobe/MaplyImageTile.h>
+#import <WhirlyGlobe/MaplyQuadImageLoader.h>
+#import <WhirlyGlobe/MaplyQuadImageFrameLoader.h>
+#import <WhirlyGlobe/MaplyQuadPagingLoader.h>
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplySimpleTileFetcher.h>
+#import <WhirlyGlobe/MaplyQuadSampler.h>
+#import <WhirlyGlobe/MaplyRemoteTileFetcher.h>
+#import <WhirlyGlobe/GeoJSONSource.h>
+
+#import <WhirlyGlobe/MaplyWMSTileSource.h>
+#import <WhirlyGlobe/MaplyMBTileFetcher.h>
+
+#import <WhirlyGlobe/MaplyVariableTarget.h>
+#import <WhirlyGlobe/MaplyAtmosphere.h>
+#import <WhirlyGlobe/MaplyColorRampGenerator.h>
+#import <WhirlyGlobe/MaplyLight.h>
+#import <WhirlyGlobe/MaplyRenderTarget.h>
+#import <WhirlyGlobe/MaplyShader.h>
+#import <WhirlyGlobe/MaplyVertexAttribute.h>
+
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyComponentObject.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyComponentObject.h
new file mode 100644
index 0000000..59ccde6
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyComponentObject.h
@@ -0,0 +1,37 @@
+/*
+ * MaplyComponentObject.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 9/18/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+/**
+ Used to represent the view controller resources attached to one or more visual objects.
+
+ When you add one or more objects to a view controller, you'll get a component object back. It's an opaque object (seriously, don't look inside) that we use to track various resources within the toolkit.
+
+ You can keep these around to remove the visual objects you added earlier, but that's about all the interaction you'll have with them.
+ */
+@interface MaplyComponentObject : NSObject
+
+/// Construct with a description. Uses the kMaplyEnable.
+- (nonnull instancetype)initWithDesc:(NSDictionary *__nonnull)desc;
+
+@end
+
+typedef MaplyComponentObject WGComponentObject;
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyControllerLayer.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyControllerLayer.h
new file mode 100644
index 0000000..d8775d0
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyControllerLayer.h
@@ -0,0 +1,44 @@
+/*
+ * MaplyControllerLayer.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 10/25/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+/**
+ The View Controller Layer is a base class for other display layers.
+
+ You don't create these directly. This is a base class for other things. Its hooks into the rest of the system are hidden.
+ */
+@interface MaplyControllerLayer : NSObject
+
+/**
+ Set the priority for drawing.
+
+ This is how you control where the geometry produced by this layer shows up with respect to other layers and other geometry. This must be set immediately after creation. It will have undefined behavior after the layer has started.
+ */
+@property (nonatomic,assign) int drawPriority;
+
+/**
+ Set as unique identifier, or group...
+
+ use this property in order to localize this layer in the Globe/Map, you use in a predicate to catch as a load layer in Globe...
+ */
+@property (nonatomic, strong) NSString *identifier;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyCoordinate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyCoordinate.h
new file mode 100644
index 0000000..753b77e
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyCoordinate.h
@@ -0,0 +1,336 @@
+/*
+ * MaplyCoordinate.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 7/21/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+#import <CoreLocation/CoreLocation.h>
+
+/**
+ A 2D coordinate representation.
+
+ The Maply Coordinate is a simple 2 dimensional coordinate
+ passed around to numerous methods. For geo-coordinates x
+ maps to longitude and y to latitude and the values are
+ in radians.
+ */
+typedef struct
+{
+ float x,y;
+} MaplyCoordinate;
+
+
+extern const MaplyCoordinate kMaplyNullCoordinate;
+
+
+/**
+ Double precision version of 2D coordinate.
+
+ This works the same was as the MaplyCoordinate, but has
+ more precision.
+ */
+typedef struct
+{
+ double x,y;
+} MaplyCoordinateD;
+
+extern const MaplyCoordinateD kMaplyNullCoordinateD;
+
+
+/**
+ A 3D coordinate representation.
+
+ The 3D version of the Maply Coordinate adds a z values, often
+ in meters, but not always. Consult the appropriate method to
+ be sure.
+ */
+typedef struct
+{
+ float x,y,z;
+} MaplyCoordinate3d;
+
+/**
+ An NSObject based wrapper for 3D coordinates.
+
+ This wrapper encapsulates a MaplyCoordinate3d so we can pass them around in NSDictionary objects.
+ */
+@interface MaplyCoordinate3dWrapper : NSObject
+
+/// Initialize with a 3D coordinate
+- (instancetype)initWithCoord:(MaplyCoordinate3d)coord;
+
+/// 3D coordinate
+@property (nonatomic,readonly) MaplyCoordinate3d coord;
+
+@end
+
+typedef struct
+{
+ double x,y,z;
+} MaplyCoordinate3dD;
+
+extern const MaplyCoordinate3dD kMaplyNullCoordinate3dD;
+
+/**
+ An NSObject based wrapper for 3D coordinates.
+
+ This wrapper encapsulates a MaplyCoordinate3d so we can pass them around in NSDictionary objects.
+ */
+@interface MaplyCoordinate3dDWrapper : NSObject
+
+/// Initialize with a 3D coordinate
+- (instancetype)initWithCoord:(MaplyCoordinate3dD)coord;
+
+/// 3D coordinate
+@property (nonatomic,readonly) MaplyCoordinate3dD coord;
+
+@end
+
+/**
+ Represents a bounding box in a particular coordinate system.
+
+ ll is the lower left and ur is the upper right.
+ */
+typedef struct
+{
+ MaplyCoordinate ll;
+ MaplyCoordinate ur;
+} MaplyBoundingBox;
+
+extern const MaplyBoundingBox kMaplyNullBoundingBox;
+
+/**
+ A category that uses NSValue to store MaplyCoordinate data
+ */
+@interface NSValue (MaplyCoordinate)
++ (instancetype)valueWithMaplyCoordinate:(MaplyCoordinate)value;
+@property (readonly) MaplyCoordinate maplyCoordinateValue;
+@end
+
+/**
+ A category that uses NSValue to store MaplyCoordinateD data
+ */
+@interface NSValue (MaplyCoordinateD)
++ (instancetype)valueWithMaplyCoordinateD:(MaplyCoordinateD)value;
+@property (readonly) MaplyCoordinateD maplyCoordinateDValue;
+@end
+
+/**
+ A category that uses NSValue to store MaplyBoundingBox data
+ */
+@interface NSValue (MaplyBoundingBox)
++ (instancetype)valueWithMaplyBoundingBox:(MaplyBoundingBox)value;
+@property (readonly) MaplyBoundingBox maplyBoundingBoxValue;
+@end
+
+/**
+ Represents a bounding box in a particular coordinate system.
+
+ ll is the lower left and ur is the upper right.
+ */
+typedef struct
+{
+ MaplyCoordinateD ll;
+ MaplyCoordinateD ur;
+} MaplyBoundingBoxD;
+
+extern const MaplyBoundingBoxD kMaplyNullBoundingBoxD;
+
+#if __cplusplus
+extern "C" {
+#endif
+
+/**
+ Construct a MaplyCoordiante with longitude and latitude values in radians.
+
+ MaplyCoordinate's are in radians when they represent lon/lat values. This constructs one with radians as input.
+
+ @return A 2D MaplyCoordinate in radians (if representing a lon/lat value).
+ */
+MaplyCoordinate MaplyCoordinateMake(float radLon,float radLat);
+
+/**
+ Construct a MaplyCoordianteD with longitude and latitude values in radians.
+
+ MaplyCoordinate's are in radians when they represent lon/lat values. This constructs one with radians as input.
+
+ @return A 2D MaplyCoordinateD in radians (if representing a lon/lat value).
+ */
+MaplyCoordinateD MaplyCoordinateDMake(double radLon,double radLat);
+
+/**
+ Construct a MaplyGeoCoordinate with longitude and latitude values in degrees.
+
+ MaplyCoordinate's are in radians when they represent lon/lat values. This function does that conversion for you.
+
+ @param degLon The longitude value (east to west) in degrees.
+
+ @param degLat The latitude value (north to south) in degrees.
+
+ @return A 2D MaplyCoordinate in radians (if representing a lon/lat value).
+ */
+MaplyCoordinate MaplyCoordinateMakeWithDegrees(float degLon,float degLat);
+
+/**
+ Construct a MaplyGeoCoordinate with longitude and latitude values in degrees.
+
+ MaplyCoordinate's are in radians when they represent lon/lat values. This function does that conversion for you.
+
+ @param degLon The longitude value (east to west) in degrees.
+
+ @param degLat The latitude value (north to south) in degrees.
+
+ @return A 2D MaplyCoordinate in radians (if representing a lon/lat value).
+ */
+MaplyCoordinateD MaplyCoordinateDMakeWithDegrees(double degLon,double degLat);
+
+/**
+ Construct a MaplyCoordinateD with a MaplyCoordinate.
+
+ This function constructs a MaplyCoordinateD with the component values of the input MaplyCoordinate.
+
+ @param c The input MaplyCoordinate value.
+
+ @return A 2D MaplyCoordinateD in radians (if representing a lon/lat value).
+ */
+MaplyCoordinateD MaplyCoordinateDMakeWithMaplyCoordinate(MaplyCoordinate c);
+
+/**
+ Construct a MaplyCoordinate with a MaplyCoordinateD.
+
+ This function constructs a MaplyCoordinate with the component values of the input MaplyCoordinateD.
+
+ @param c The input MaplyCoordinateD value.
+
+ @return A 2D MaplyCoordinate in radians (if representing a lon/lat value).
+ */
+MaplyCoordinate MaplyCoordinateMakeWithMaplyCoordinateD(MaplyCoordinateD c);
+
+/**
+ Construct a MaplyCoordinat3d from the values given.
+
+ @param x The x value, or longitude in radians if we're making geo coordinates.
+
+ @param y The y value, or latitude in radians if we're making geo coordinates.
+
+ @param z The z value, sometimes this is display coordinates (radius == 1.0 for a sphere)
+ and sometimes this is meters. It depends on how you're using it.
+
+ @return A 3D MaplyCoordinate3d in radians + other (if representing a lon/lat value).
+ */
+MaplyCoordinate3d MaplyCoordinate3dMake(float x,float y,float z);
+
+/**
+ Construct a MaplyCoordinat3d from the values given.
+
+ @param x The x value, or longitude in radians if we're making geo coordinates.
+
+ @param y The y value, or latitude in radians if we're making geo coordinates.
+
+ @param z The z value, sometimes this is display coordinates (radius == 1.0 for a sphere)
+ and sometimes this is meters. It depends on how you're using it.
+
+ @return A 3D MaplyCoordinate3d in radians + other (if representing a lon/lat value).
+ */
+MaplyCoordinate3dD MaplyCoordinate3dDMake(double x,double y,double z);
+
+/**
+ Construct a MaplyBoundingBox from the values given.
+
+ The inputs are in degrees and the order is longitude *then* latitude.
+
+ @param degLon0 The left side of the bounding box in degrees.
+
+ @param degLat0 The bottom of the bounding box in degrees.
+
+ @param degLon1 The right side of the bounding box in degrees.
+
+ @param degLat1 The top of the bounding box in degrees.
+
+ @return A MaplyBoundingBox in radians.
+ */
+MaplyBoundingBox MaplyBoundingBoxMakeWithDegrees(float degLon0,float degLat0,float degLon1,float degLat1);
+
+/** Double version of MaplyBoundingBoxMakeWithDegrees
+ */
+MaplyBoundingBoxD MaplyBoundingBoxDMakeWithDegrees(double degLon0,double degLat0,double degLon1,double degLat1);
+
+/**
+ Check if two bounding boxes overlap.
+
+ @return Returns true if they did overlap, false otherwise.
+ */
+bool MaplyBoundingBoxesOverlap(MaplyBoundingBox bbox0,MaplyBoundingBox bbox1);
+
+/**
+ Check if a bounding contains a given coordinate.
+
+ @return Returns true if the bounding box contains the coordinate.
+ */
+bool MaplyBoundingBoxContains(MaplyBoundingBox bbox, MaplyCoordinate c);
+
+/**
+ Set up a bounding box from a list of 2D locations.
+ */
+MaplyBoundingBox MaplyBoundingBoxFromLocations(const CLLocationCoordinate2D locs[], unsigned int numLocs);
+
+/**
+ Set up a bounding box from a list of 2D coordinates
+ */
+MaplyBoundingBox MaplyBoundingBoxFromCoordinates(const MaplyCoordinate coords[], unsigned int numCoords);
+MaplyBoundingBox MaplyBoundingBoxFromCoordinatesD(const MaplyCoordinateD coords[], unsigned int numCoords);
+MaplyBoundingBoxD MaplyBoundingBoxDFromCoordinates(const MaplyCoordinate coords[], unsigned int numCoords);
+MaplyBoundingBoxD MaplyBoundingBoxDFromCoordinatesD(const MaplyCoordinateD coords[], unsigned int numCoords);
+
+/**
+ Expand a bounding box with a list of 2D coordinates
+ */
+MaplyBoundingBox MaplyBoundingBoxAddCoordinates(MaplyBoundingBox box, const MaplyCoordinate coords[], unsigned int numCoords);
+MaplyBoundingBox MaplyBoundingBoxAddCoordinatesD(MaplyBoundingBox box, const MaplyCoordinateD coords[], unsigned int numCoords);
+MaplyBoundingBoxD MaplyBoundingBoxDAddCoordinates(MaplyBoundingBoxD box, const MaplyCoordinate coords[], unsigned int numCoords);
+MaplyBoundingBoxD MaplyBoundingBoxDAddCoordinatesD(MaplyBoundingBoxD box, const MaplyCoordinateD coords[], unsigned int numCoords);
+
+/**
+ Return the intersection of two bounding boxes.
+ */
+MaplyBoundingBox MaplyBoundingBoxIntersection(MaplyBoundingBox bbox0,MaplyBoundingBox bbox1);
+
+/**
+ Expands a bounding box by a given fraction of its size.
+
+ @return Returns the expanded bounding box.
+ */
+MaplyBoundingBox MaplyBoundingBoxExpandByFraction(MaplyBoundingBox bbox, float buffer);
+
+/**
+ Calculate the great circle distance between two geo coordinates.
+
+ This calculates the distance on a sphere between one point and another.
+
+ @param p0 The starting point, lon/lat in radians.
+
+ @param p1 The end point, lon/lat in radians.
+
+ @return The distance between p0 and p1 in meters.
+ */
+double MaplyGreatCircleDistance(MaplyCoordinate p0,MaplyCoordinate p1);
+
+#if __cplusplus
+}
+#endif
+
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyCoordinateSystem.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyCoordinateSystem.h
new file mode 100644
index 0000000..d1ddf69
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyCoordinateSystem.h
@@ -0,0 +1,176 @@
+/* MaplyCoordinateSystem.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 5/13/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+/**
+ Coordinate system for tiling systems and data sources and such.
+
+ This object represents the spatial reference system and bounding box for objects like the MaplyTileSource or vectors or other things. Not all data is in lat/lon geographic (actually MaplyPlateCaree) nor is it always in MaplySphericalMercator. Sometimes it's in one or the other, or a bit of both.
+
+ We use this base class to express the coordinate system and we threw in the bounding box, which we will surely come to regret. Oh well, it's in there.
+
+ This object gets passed around to tell us what coordinate system data is in or how we're displaying things. Right now only MaplySphericalMercator and MaplyPlateCarree are represented. In the future, there will be more.
+ */
+@interface MaplyCoordinateSystem : NSObject
+
+/**
+ Set the bounding box in the local coordinate system.
+
+ This is the bounding box, for things like display coordinates. If the extents would normally be in degrees, use radians. Otherwise, the values are in the local system.
+ */
+- (void)setBounds:(MaplyBoundingBox)bounds;
+
+/**
+ Set the bounding box in the local coordinate system.
+
+ This is the bounding box, for things like display coordinates. If the extents would normally be in degrees, use radians. Otherwise, the values are in the local system.
+ */
+- (void)setBoundsD:(MaplyBoundingBoxD)boundsD;
+
+/**
+ Set the bounding box in the local coordinate system.
+
+ This is the bounding box, for things like display coordinates. If the extents would normally be in degrees, use radians. Otherwise, the values are in the local system.
+ */
+- (void)setBoundsLL:(MaplyCoordinate * __nonnull)ll ur:(MaplyCoordinate * __nonnull)ll;
+
+/**
+ Return the bounding box in local coordinates.
+
+ This is the bounding box in local coordinates, or if the extents would normally be expressed in degrees, it's radians.
+ */
+- (MaplyBoundingBox)getBounds;
+
+/**
+ Return the bounding box in local coordinates.
+
+ This is the bounding box in local coordinates, or if the extents would normally be expressed in degrees, it's radians.
+ */
+- (void)getBoundsLL:(MaplyCoordinate * __nonnull)ret_ll ur:(MaplyCoordinate * __nonnull)ret_ur;
+
+/**
+ Convert a coordinate from geographic to the local coordinate system.
+
+ Take a geo coordinate (lon/lat in radians) and convert to the local space.
+ */
+- (MaplyCoordinate)geoToLocal:(MaplyCoordinate)coord;
+
+/**
+ Convert a coordinate from the local space to geographic.
+
+ This takes a coordinate in this coordinate system and converts it to geographic (lat/lon in radians).
+ */
+- (MaplyCoordinate)localToGeo:(MaplyCoordinate)coord;
+
+/**
+ Convert a 3D coordinate from the local space to geocentric.
+
+ This takes a 3D coordinate (including height) and converts it to geocentric in WGS84.
+ */
+- (MaplyCoordinate3dD)localToGeocentric:(MaplyCoordinate3dD)coord;
+
+/**
+ Convert a 3D coordinate from geocentric to the local space.
+
+ This takes a 3D geocentric coordinate (WGS84) and converts it to the local space, including height;
+ */
+- (MaplyCoordinate3dD)geocentricToLocal:(MaplyCoordinate3dD)coord;
+
+/**
+ Express the coordinate system in an SRS compatible string.
+ */
+- (NSString * __nonnull)getSRS;
+
+/**
+ Can this coordinate system be expressed in degrees?
+
+ This is set for coordinate systems that express their extents in degrees. This is useful for cases where we need to construct some metadata to go along with the system and you'd normally expect it to be in degrees rather than radians.
+ */
+- (bool)canBeDegrees;
+
+@end
+
+/**
+ Plate Carree is lat/lon stretched out to its full extents.
+
+ This coordinate system is used when we're tiling things over the whole earth, from -180 to +180 and from -90 to +90. Use this if you chopped up your data in that way.
+ */
+@interface MaplyPlateCarree : MaplyCoordinateSystem
+
+/// Initialize with Plate Carree covering the whole globe.
+- (nonnull instancetype)init;
+
+/// Initialize with Plate Carree covering the whole globe.
+- (nullable instancetype)initFullCoverage;
+
+/// Initialize with the given bounding box (in radians)
+- (nullable instancetype)initWithBoundingBox:(MaplyBoundingBox)bbox;
+
+/// Initialize with the given bounding box (in radians)
+- (nullable instancetype)initWithBoundingBoxD:(MaplyBoundingBoxD)bbox;
+
+@end
+
+/**
+ Spherical Mercator is what you'll most commonly see on web maps.
+
+ The Spherical Mercator system, with web extents is what MapBox, Google, Bing, etc. use for their maps. If you ever want to annoy a cartographer, suggest that spherical mercator is all you ever really need.
+
+ The drawback with Spherical Mercator is that it doesn't cover the poles and it distorts (and how) its north and south extents. Web Standard refers to the extents you'll find in most online maps. This is probably want you want.
+ */
+@interface MaplySphericalMercator : MaplyCoordinateSystem
+
+/// Initialize with the -85...,+85... extents to match most comm only used online maps
+- (nonnull instancetype)init;
+
+/// Initialize with the -85...,+85... extents to match most commonly used online maps
+- (nonnull instancetype)initWebStandard;
+
+@end
+
+/**
+ A generic coordinate system wrapper around proj4.
+
+ You create one of these with a proj4 string. It'll act like a normal MaplyCoordinateSysterm after that.
+
+ Be sure to check that the system is valid. The proj4 string could be wrong.
+ */
+@interface MaplyProj4CoordSystem : MaplyCoordinateSystem
+
+/**
+ Initialize with a proj4 compatible string
+
+ Since this is just a proj.4 wrapper, we need an initialization string that it can parse.
+ */
+- (nonnull instancetype)initWithString:(NSString * __nonnull)proj4Str;
+
+/// True if the proj.4 string was valid and the coordinate system can work.
+- (bool)valid;
+
+@end
+
+/**
+ Generate the correct coordinate system from a standard EPSG.
+
+ This returns the correct coordinate system from a standard EPSG string.
+
+ The list of available coordinate systems is very short.
+ */
+MaplyCoordinateSystem * __nullable MaplyCoordinateSystemFromEPSG(NSString * __nonnull crs);
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyDoubleTapDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyDoubleTapDelegate.h
new file mode 100644
index 0000000..963d108
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyDoubleTapDelegate.h
@@ -0,0 +1,25 @@
+/* MaplyDoubleTapDelegate.h
+ *
+ * Created by Jesse Crocker on 2/3/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyZoomGestureDelegate.h>
+
+@interface MaplyDoubleTapDelegate : MaplyZoomGestureDelegate
+
+/// How long we animate from starting to end point
+@property (nonatomic) float animTime;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyDoubleTapDragDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyDoubleTapDragDelegate.h
new file mode 100644
index 0000000..53b4233
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyDoubleTapDragDelegate.h
@@ -0,0 +1,22 @@
+/* MaplyDoubleTapDragDelegate.h
+ *
+ * Created by Steve Gifford on 2/7/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyZoomGestureDelegate.h>
+
+@interface MaplyDoubleTapDragDelegate : MaplyZoomGestureDelegate
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyGeomBuilder.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyGeomBuilder.h
new file mode 100644
index 0000000..65a4374
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyGeomBuilder.h
@@ -0,0 +1,301 @@
+/*
+ * MaplyGeomModelBuilder.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 1/20/16
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+#import <WhirlyGlobe/MaplyGeomModel.h>
+
+/**
+ Geometry State is used to describe the visual look of objects as they're added.
+
+ Set the various fields in the geometry state to control how geometry looks when you add it.
+ There are defaults for all of these fields.
+ */
+@interface MaplyGeomState : NSObject
+
+/// Color to use for the geometry
+@property (nonatomic,strong) UIColor *color;
+
+/// Background color for text
+@property (nonatomic,strong) UIColor *backColor;
+
+/// UIImage for MaplyTexture to apply to geometry
+@property (nonatomic,strong) id texture;
+
+/// For more than one texture, use addTexture
+- (void)addTexture:(MaplyTexture *)texture;
+
+@end
+
+/**
+ The geometry builder is used to construct 3D models.
+
+ You use the geometry builder when you have a custom 3D model to build. This can include things like airport runways, buildings, or anything else that's particular to a certain location.
+
+ Start by construting the builder and then adding polygons and strings to it.
+
+ You can combine multiple geometry builders together to build up repeated portions of a model.
+
+ The builder has an "immediate mode" where you add points individually to build up polygons and then add those. This is one of the simpler ways to use the system.
+ */
+@interface MaplyGeomBuilder : NSObject
+
+/// Intialize with the view controller the model will be used in.
+- (id)initWithViewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+/**
+ Create a rectangle around the origin.
+
+ This creates a flat rectangle around the origin (0,0,0) with z = 0.
+
+ @param size The size of the rectangle (x,y).
+
+ @param state The visual state to use when creating the geometry.
+ */
+- (void)addRectangleAroundOrigin:(MaplyCoordinateD)size state:(MaplyGeomState *)state;
+
+/**
+ Create a rectangle around the origin.
+
+ This creates a flat rectangle around the origin (0,0,0) with z = 0.
+
+ @param x Horizontal size of the rectangle.
+
+ @param y Vertical size of the rectangle.
+
+ @param state The visual state to use when creating the geometry.
+ */
+- (void)addRectangleAroundOriginX:(double)x y:(double)y state:(MaplyGeomState *)state;
+
+/**
+ Create a rectangle around the given point.
+
+ This creates a flat rectangle around the point x,y with z = 0.
+
+ @param x X location around which to create the rectangle.
+
+ @param y Y location around which to create the rectangle.
+
+ @param width Horizontal size of the rectangle.
+
+ @param height Vertical size of the rectangle.
+
+ @param state The visual state to use when creating the geometry.
+ */
+- (void)addRectangleAroundX:(double)x y:(double)y width:(double)width height:(double)height state:(MaplyGeomState *)state;
+
+/**
+ Add an attributed string to the geometry builder.
+
+ Add an attributed string, which contains information about color and front to the geometry builder.
+
+ @param str String to add to the geometry.
+
+ @param state The visual state to use when creating the geometry.
+ */
+- (void)addAttributedString:(NSAttributedString *)str state:(MaplyGeomState *)state;
+
+/**
+ Add a string to the geometry.
+
+ Add a string at (0,0) to the geometry with the given font and visual state. The font determines size.
+
+ @param str String to add to geometry.
+
+ @param font Font to use for the string.
+
+ @param state The visual state to use when creating the geometry.
+ */
+- (void)addString:(NSString *)str font:(UIFont *)font state:(MaplyGeomState *)state;
+
+/**
+ Add a string to the geometry.
+
+ Add a string at (0,0) to the geometry with the given font and visual state.
+
+ The string will be scaled to match the width and/or height given. If one of width or height is 0.0 it will be calculated from the other.
+
+ @param str String to add to geometry.
+
+ @param width Width of the string in the final geometry. If set to 0.0, will be calculated.
+
+ @param height Height of the string in the final geometry. If set to 0.0, will be calculated.
+
+ @param font Font to use for the string.
+
+ @param state The visual state to use when creating the geometry.
+ */
+- (void)addString:(NSString *)str width:(double)width height:(double)height font:(UIFont *)font state:(MaplyGeomState *)state;
+
+/**
+ Add a polygon with the given visual state.
+
+ Tesselates the given polygon and adds the resulting triangles to the geometry.
+
+ @param pts An array of 3D points.
+
+ @param numPts Number of points in the 3D array.
+
+ @param state The visual state to use when creating the geometry.
+ */
+- (void)addPolygonWithPts:(MaplyCoordinate3dD *)pts numPts:(int)numPts state:(MaplyGeomState *)state;
+
+/**
+ Add a polygon with the given visual state.
+
+ Tesselates the given polygon and adds the resulting triangles to the geometry.
+
+ @param pts An array of 3D points.
+
+ @param tex Texture coordinates. One for each point.
+
+ @param norms Normals to go with the points.
+
+ @param numPts Number of points in the 3D array.
+
+ @param state The visual state to use when creating the geometry.
+ */
+- (void)addPolygonWithPts:(MaplyCoordinate3dD *)pts tex:(MaplyCoordinateD *)tex norms:(MaplyCoordinate3dD *)norms numPts:(int)numPts state:(MaplyGeomState *)state;
+
+/**
+ Add a point in immediate mode.
+
+ When in immediate mode points are collected until an addCurPoly call. This adds a 3D point.
+ */
+- (void)addCurPointX:(double)x y:(double)y z:(double)z;
+
+/**
+ Add a point in immediate mode
+
+ When in immediate mode points are collected until an addCurPoly call. This add a point at (x,y,0).
+ */
+- (void)addCurPointX:(double)x y:(double)y;
+
+/**
+ Add the current polygon in immediate mode.
+
+ When in immediate mode points are collected until you call this method. Then the points will be tesselated into a set of triangles and added to the geometry with the given visual state.
+ */
+- (void)addCurPoly:(MaplyGeomState *)state;
+
+/**
+ Scale the geometry and strings by this amount.
+
+ The geometry and strings are scaled by the given amount in each dimension.
+ */
+- (void)scale:(MaplyCoordinate3dD)scale;
+
+/**
+ Scale the geometry and strings by the given amount.
+
+ The geometry and strings are scaled by (x,y,z).
+ */
+- (void)scaleX:(double)x y:(double)y z:(double)z;
+
+/**
+ Translate the geometry and strings by the given amount.
+
+ The geometry and strings are translated by the given coordinate.
+ */
+- (void)translate:(MaplyCoordinate3dD)trans;
+
+/**
+ Translate the geometry and strings by the given amount.
+
+ The geometry and strings are translated by (x,y,z).
+ */
+- (void)translateX:(double)x y:(double)y z:(double)z;
+
+/**
+ Rotate the geometry around the given axis by the given angle.
+
+ Roate around the given 3D axis by the number of radians in angle.
+
+ @param angle The angle in radians to rotate by.
+
+ @param axis The axis to rotate around. (0,0,1) would rotate around the Z axis.
+ */
+- (void)rotate:(double)angle around:(MaplyCoordinate3dD)axis;
+
+/**
+ Rotate the geometry around the given axis by the given angle.
+
+ Roate around the given 3D axis by the number of radians in angle.
+
+ @param angle The angle in radians to rotate by.
+
+ @param x X component of the axis to rotate around.
+
+ @param y Y component of the axis to rotate around.
+
+ @param z Z component of the axis to rotate around.
+ */
+- (void)rotate:(double)angle aroundX:(double)x y:(double)y z:(double)z;
+
+/**
+ Apply a transform to the geometry and strings.
+
+ This applies a general 4x4 transform to the geometry and strings. You can construct the MaplyMatrix using a number of different options and combine multiple matrices.
+ */
+- (void)transform:(MaplyMatrix *)matrix;
+
+/**
+ Add the geometry from another builder.
+
+ Multiple geometry builders can be combined to build complex objects.
+
+ This method copies geometry and strings, including their transforms to the current builder.
+ */
+- (void)addGeomFromBuilder:(MaplyGeomBuilder *)modelBuilder;
+
+/**
+ Add the geometry from another builder, applying the given transform.
+
+ Multiple geometry builders can be combined to build complex objects.
+
+ This method transform the source geometry and strings and copies them into the current builder.
+ */
+- (void)addGeomFromBuilder:(MaplyGeomBuilder *)modelBuilder transform:(MaplyMatrix *)matrix;
+
+/**
+ Calculate the bounding box of geometry and strings.
+
+ Calculates the lower left and upper right corners of a rectangular solid that surrounds the geometry and strings for this builder.
+
+ This returns false if there is no valid geometry (or strings) and takes transforms into account if there is.
+ */
+- (bool)getSizeLL:(MaplyCoordinate3dD *)ll ur:(MaplyCoordinate3dD *)ur;
+
+/**
+ Calculate and returns the size of the geometry and strings.
+
+ Calculates the size of the geometry and strings in the builder, taking transforms into account.
+ */
+- (MaplyCoordinate3dD)getSize;
+
+/**
+ Generate a valid MaplyGeomModel that can be instanced and used as a 3D model.
+
+ This call returns a MaplyGeomModel. You'll need a model to make MaplyGeomModelInstance objects and for the addModelInstances:desc:mode: call to a NSObject<MaplyRenderControllerProtocol> (map or globe).
+ */
+- (MaplyGeomModel *)makeGeomModel:(MaplyThreadMode)threadMode;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyGeomModel.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyGeomModel.h
new file mode 100644
index 0000000..7e41021
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyGeomModel.h
@@ -0,0 +1,122 @@
+/*
+ * MaplyGeomModel.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 11/26/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyMatrix.h>
+#import <WhirlyGlobe/MaplyShape.h>
+
+@class MaplyShader;
+
+/**
+ Contains a big pile of geometry and textures (e.g. a model).
+
+ The geometry model
+ */
+@interface MaplyGeomModel : NSObject
+
+/**
+ Initialize with the full path to a Wavefront OBJ model file.
+
+ This creates a model from a Wavefront OBJ file, a standard, simple file format for models. You can then instance and place this model where you might like.
+ */
+- (nullable instancetype)initWithObj:(NSString *__nonnull)fullPath;
+
+/**
+ Initialize with a shape.
+
+ The given shape will be turned into a geometry model so it can be instanced.
+ */
+- (nonnull instancetype)initWithShape:(MaplyShape *__nonnull)shape;
+
+@end
+
+
+/**
+ Place a geometry model at a given location
+
+ Geometry models tend to be expensive so we load and place them in a two step process. First you create the MaplyGeomModel and then you place it in one or more spots with this MaplyGeomModelInstance.
+ */
+@interface MaplyGeomModelInstance : NSObject
+
+/**
+ User data object for selection
+
+ When the user selects a feature and the developer gets it in their delegate, this is an object they can use to figure out what the model instance means to them.
+ */
+@property (nonatomic,strong,nullable) id userObject;
+
+/// The model to instance
+@property (nonatomic,strong,nullable) MaplyGeomModel *model;
+
+/**
+ Where we'd like to place the instanced model.
+
+ This is the center of the object in geographic radians.
+ */
+@property (nonatomic) MaplyCoordinate3d center;
+
+/// Transform used to oriented the model instance
+@property (nonatomic,strong,nullable) MaplyMatrix *transform;
+
+/// Color to force all polygons to use.
+/// If set, this will force all polygons to use this color. nil by default.
+@property (nonatomic,strong,nullable) UIColor *colorOverride;
+
+/// Set if you want to select these
+@property (nonatomic) bool selectable;
+
+@end
+
+/**
+ A version of the geometry model instance that moves.
+
+ This version of the geometry model instance can move in a limited way over time.
+ */
+@interface MaplyMovingGeomModelInstance : MaplyGeomModelInstance
+
+/// The end point for animation
+@property (nonatomic,assign) MaplyCoordinate3d endCenter;
+
+/// How long it will take to get to the endCenter
+@property (nonatomic,assign) NSTimeInterval duration;
+
+@end
+
+/**
+ Sometimes we don't know how many instances there will be of a model until
+ some logic runs on the GPU. We can then take that number and run that
+ number of instances of the given model. [Metal only]
+ */
+@interface MaplyGeomModelGPUInstance : NSObject
+
+/// The model to instance
+@property (nonatomic,strong,nullable) MaplyGeomModel *model;
+
+/// Texture to derive the number of instances from (picked out of the highest, smallest level)
+@property (nonatomic,nullable) MaplyTexture *numInstSource;
+
+/// Need a shader to pull the number of instances out of a texture and shove them in the indirect buffer
+@property (nonatomic,nullable) MaplyShader *numInstShader;
+
+/// Shader to run over for this instance
+@property (nonatomic,nullable) MaplyShader *shader;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyGlobeRenderController.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyGlobeRenderController.h
new file mode 100644
index 0000000..27c7afd
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyGlobeRenderController.h
@@ -0,0 +1,115 @@
+/*
+* MaplyGlobeRenderController.h
+* WhirlyGlobeComponent
+*
+* Created by Steve Gifford on 10/23/10.
+* Copyright 2011-2022 mousebird consulting
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+#import <WhirlyGlobe/MaplyRemoteTileFetcher.h>
+
+/**
+ Animation State used by the WhirlyGlobeViewControllerAnimationDelegate.
+
+ You fill out one of these when you're implementing the animation delegate. Return it and the view controller will set the respective values to match.
+ */
+@interface WhirlyGlobeViewControllerAnimationState : NSObject
+
+/// Heading is calculated from due north
+/// If not set or set to MAXFLOAT, this is ignored
+@property (nonatomic) double heading;
+
+/// Height above the globe
+@property (nonatomic) double height;
+
+/// Tilt as used in the view controller
+/// If not set or set to MAXFLOAT, we calculate tilt the regular way
+@property (nonatomic) double tilt;
+
+/// Roll as used in the view controller
+@property (nonatomic) double roll;
+
+/// Position to move to on the globe
+@property (nonatomic) MaplyCoordinateD pos;
+
+/// If set, this is a point on the screen where pos should be.
+/// By default this is (-1,-1) meaning the screen position is just the middle. Otherwise, this is where the position should wind up on the screen, if it can.
+@property (nonatomic) CGPoint screenPos;
+
+/// If set, the globe will be centered at this point on the screen
+@property (nonatomic) CGPoint globeCenter;
+
+/**
+ Interpolate a new state between the given states A and B.
+
+ This does a simple interpolation (lat/lon, not great circle) between the two animation states.
+ */
++ (nonnull WhirlyGlobeViewControllerAnimationState *)Interpolate:(double)t from:(WhirlyGlobeViewControllerAnimationState *__nonnull)stateA to:(WhirlyGlobeViewControllerAnimationState *__nonnull)stateB;
+
+@end
+
+/**
+ The Globe Render Controller is a standalone renderer for the globe.
+ This is separate from the WhirlyGlobeViewController, but performs a similar function for
+ offline rendering.
+ */
+@interface WhirlyGlobeRenderController : MaplyRenderController
+
+/// Initialize with the size of the target rendering buffer
+- (instancetype __nullable) initWithSize:(CGSize)screenSize mode:(MaplyRenderType)renderType;
+
+/// Initialize as an offline renderer of a given target size with default renderer (Metal)
+- (instancetype __nullable)initWithSize:(CGSize)size;
+
+/** Set this if you're doing frame by frame animation.
+ It will move particles along and run any animations you may have going.
+ **/
+@property (nonatomic,assign) NSTimeInterval currentTime;
+
+/**
+ Set the viewing state all at once
+
+ This sets the position, tilt, height, screen position and heading all at once.
+ */
+- (void)setViewState:(WhirlyGlobeViewControllerAnimationState *__nonnull)viewState;
+
+/**
+ Make a WhirlyGlobeViewControllerAnimationState object from the current view state.
+
+ This returns the current view parameters in a single WhirlyGlobeViewControllerAnimationState.
+ */
+- (nullable WhirlyGlobeViewControllerAnimationState *)getViewState;
+
+/**
+ Takes a snapshot of the current OpenGL view and returns it.
+ */
+- (UIImage *__nullable)snapshot;
+
+/**
+ This version of snapshot just returns the raw NSData from the "screen".
+ */
+- (NSData *__nullable)snapshotData;
+
+
+/**
+ If set, keep north facing upward on the screen as the user moves around.
+
+ Off by default.
+ */
+@property(nonatomic,assign) bool keepNorthUp;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyIconManager.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyIconManager.h
new file mode 100644
index 0000000..7e19b44
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyIconManager.h
@@ -0,0 +1,140 @@
+/*
+ * MaplyIconManager.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 1/11/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+
+/**
+ Holds info about a single style from the MaplySimpleStyleManager.
+ This is enough to build a marker (or other thing, if you like).
+ */
+@interface MaplySimpleStyle : NSObject
+
+/// If there was a title, this is it
+@property (nonatomic,nullable) NSString *title;
+
+/// If there was a description, this is it
+@property (nonatomic,nullable) NSString *desc;
+
+/// Size (in pixels) of the marker to be built
+@property (nonatomic) CGSize markerSize;
+
+/// How big we consider the marker to be when doing layout.
+/// By default, same as the marker size
+@property (nonatomic) CGSize layoutSize;
+
+/// Offset applied to marker
+@property (nonatomic) CGPoint markerOffset;
+
+/// Texture constructed for this icon, if there was a symbol
+@property (nonatomic,nullable) MaplyTexture *markerTex;
+
+/// If this was 0-9 or a-Z instead, this is that
+@property (nonatomic,nullable) NSString *markerString;
+
+/// Color to set for the markert
+@property (nonatomic,nonnull) UIColor *color;
+
+/// Stroke color if there is one
+@property (nonatomic,nonnull) UIColor *strokeColor;
+
+/// Stroke opacity
+@property (nonatomic) float strokeOpacity;
+
+/// Stroke width, if available. Takes scale into account.
+@property (nonatomic) float strokeWidth;
+
+/// Fill color if available
+@property (nonatomic,nonnull) UIColor *fillColor;
+
+/// Fill opacity, if available
+@property (nonatomic) float fillOpacity;
+
+@end
+
+/** Used to generate icons and parse styles for the GeoJSON simple Style spec.
+ https://github.com/mapbox/simplestyle-spec
+
+ Can also be used to define some very simple icon styles directly.
+ */
+@interface MaplySimpleStyleManager : NSObject
+
+/** Fetch the simple UIImage for the icon with the given name.
+ **/
++ (nullable UIImage *)iconForName:(NSString *__nonnull)name size:(CGSize)size;
+
+/** Slightly more complex icon
+ **/
++ (nullable UIImage *)iconForName:(NSString *__nullable)name size:(CGSize)size color:(UIColor *__nullable)color circleColor:(UIColor *__nullable)circleColor strokeSize:(float)strokeSize strokeColor:(UIColor *__nullable)strokeColor;
+
+/** Clear the cache
+ */
++ (void)clearIconCache;
+
+/**
+ Set up the icon manager this way to build textures associated with a particular view controller.
+ */
+- (nonnull id)initWithViewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+/// Markers can be three different sizes. These are the actual sizes associated
+@property (nonatomic) CGSize smallSize,medSize,largeSize;
+
+/// Normal scale from device (e.g. 2x for retina and so on)
+@property (nonatomic) CGFloat scale;
+
+/// We normally put a stroke around generated icons
+/// This is the width (in pixels) of that stroek
+@property (nonatomic) CGFloat strokeWidthForIcons;
+
+/// If set (default) we'll center the marker. If off we'll offset vertically
+@property (nonatomic) bool centerIcon;
+
+/**
+ Mapbox defines a simple style spec that's usually associated with GeoJSON data. Github is a prominent user.
+
+ Pass in a dictionary parsed from JSON (or just make it up yourself) and this will produce (an optional) icon and parse out the rest.
+ This takes screen scale and such into account. It will also cache the same description when passed in multiple times.
+*/
+- (MaplySimpleStyle * __nonnull)makeStyle:(NSDictionary *__nonnull)dict;
+
+/**
+ Takes a single vector object. It will parse out the simple style from the attributes (or provide a default if there is none)
+ and then build the corresponding feature and return a MaplyComponentObject to represent it.
+
+ mode controls if this work is done on this thread or another.
+ */
+- (MaplyComponentObject * __nullable)addFeature:(MaplyVectorObject * __nonnull)vecObj mode:(MaplyThreadMode)mode;
+
+/**
+ Takes an array of vector objects and calls addFeature: on each one.
+
+ mode controls if this work is done on this thread or another.
+ */
+- (NSArray<MaplyComponentObject *> * __nonnull)addFeatures:(NSArray<MaplyVectorObject *> * __nonnull)vecObjs mode:(MaplyThreadMode)mode;
+
+/** Clear the icon cache.
+ Any references to the textures should already be cleared.
+ */
+- (void)clearCache;
+
+/// Delete any cached textures and such
+- (void)shutdown;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyImageTile.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyImageTile.h
new file mode 100644
index 0000000..808634d
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyImageTile.h
@@ -0,0 +1,113 @@
+/*
+ * MaplyImageTile.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 10/18/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+
+@class MaplyElevationChunk;
+
+/**
+ Describes a single tile worth of data, which may be multiple images.
+
+ Delegates can pass back a single UIImage or NSData object, but if they want to do anything more complex, they need to do it with this.
+ */
+@interface MaplyImageTile : NSObject
+
+/**
+ Initialize with an NSData object containing 32 bit pixels.
+
+ This sets up the tile with an NSData object containing raw pixels. The pixels are 32 bit RGBA even if you're targeting a smaller pixel format.
+
+ @param data The NSData object containing 32 bit RGBA pixels.
+
+ @param width The width of the raw image contained in the data object.
+
+ @param height The height of the raw image contained in the data object.
+ */
+- (instancetype)initWithRawImage:(NSData *)data width:(int)width height:(int)height viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+/**
+ Initialize with an NSData object containing 32 bit pixels.
+
+ This sets up the tile with an NSData object containing raw pixels. The pixels are 32 bit RGBA even if you're targeting a smaller pixel format.
+
+ @param data The NSData object containing 32 bit RGBA pixels.
+
+ @param width The width of the raw image contained in the data object.
+
+ @param height The height of the raw image contained in the data object.
+
+ @param comp The number of components (1, 2 or 4)
+ */
+- (instancetype)initWithRawImage:(NSData *)data width:(int)width height:(int)height components:(int)comp viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+/**
+Initialize with an NSData object containing pixels of a given format.
+
+This sets up the tile with an NSData object containing raw pixels. The pixels are defined by the format.
+
+@param data The NSData object containing pixels.
+
+@param format The image format the data is already in.
+
+@param width The width of the raw image contained in the data object.
+
+@param height The height of the raw image contained in the data object.
+*/
+- (instancetype)initWithRawImage:(NSData *)data format:(MaplyQuadImageFormat)format width:(int)width height:(int)height viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+/**
+ Initialize with a single UIImage for the tile.
+
+ This sets up the given UIImage as the return for the given tile. You can then set targetSize and such.
+ */
+- (instancetype)initWithImage:(UIImage *)image viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+/**
+ Initialize with an NSData object containing PNG or JPEG data that can be interpreted by UIImage.
+
+ We're expecting PNG, JPEG or another self identified format (e.g. PKM). These we can interpret ourselves.
+ */
+- (instancetype)initWithPNGorJPEGData:(NSData *)data viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+/**
+ Border size that was set on initialization.
+
+ If there's a built in border as part of the image data passed in during initialization, set it here.
+ Normally this is 0.
+ */
+@property (nonatomic,assign) int borderSize;
+
+/**
+ Target size for the image(s) represented by this tile.
+
+ This instructs the pager to rescale the image(s) to the given target size. This is probably faster than doing it yourself because we can extract the data and rescale in the same step.
+ */
+@property (nonatomic) CGSize targetSize;
+
+/**
+ Preprocess into a simple texture format.
+
+ Extracting from PNG or JPEG or whatever often requires a bit of work. We'll do that work later,
+ if this isn't called. But if you do call it here then you can do that work on your own thread.
+ */
+- (void)preprocessTexture;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyLabel.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyLabel.h
new file mode 100644
index 0000000..ddd52a2
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyLabel.h
@@ -0,0 +1,101 @@
+/*
+ * WGLabel.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 7/24/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+typedef NS_ENUM(NSInteger, MaplyLabelJustify) {
+ MaplyLabelJustifyLeft,
+ MaplyLabelJustifyMiddle,
+ MaplyLabelJustifyRight
+};
+
+/**
+ This is a 3D label.
+
+ The Maply Label is a 3D object that sits on top of the globe (or map) at a specified location. If you want a 2D label that sits on top of everything else, you want the MaplyScreenLabel. Seriously, you probably want that.
+ */
+@interface MaplyLabel : NSObject
+
+/**
+ The location (in geographic) for this label.
+
+ The Maply Label is a 3D object and this is its location on the globe or map. The coordinates are in geographic (lon/lat) and the actual layout is controleld by justify.
+ */
+@property (nonatomic,assign) MaplyCoordinate loc;
+
+/**
+ Size of the label in display units.
+
+ The Maply Label is a 3D object placed on top of the globe or map. This controls the size of that label in display coordinates. For the globe display coordinates are based on a radius of 1.0.
+
+ One or both values of the size can be set. Typically you want to set the height and let the toolkit calculate the width.
+ */
+@property (nonatomic,assign) CGSize size;
+
+/// The text to display on the globe or map at the given location.
+@property (nonatomic,strong) NSString * __nullable text;
+
+/**
+ Text can be accompanied by an optional icon image.
+
+ If set, we'll put this image to the left of the text in the label. The UIImage (or MaplyTexture) will be tracked by the view controller and reused as needed or disposed of when no longer needed.
+
+ The name had to change because Apple's private selector search is somewhat weak.
+ */
+@property (nonatomic,strong) id __nullable iconImage2;
+
+/**
+ An option color override.
+
+ If set, this color will override the color passed in with the NSDictionary in the view controller's add method.
+ */
+@property (nonatomic,strong) UIColor * __nullable color;
+
+/**
+ Label selectability. On by default
+
+ If set, this label can be selected by the user. If not set, this label will never appear in selection results.
+ */
+@property (nonatomic,assign) bool selectable;
+
+/**
+ The text justification based on the location.
+
+ Text can be placed around the location based on this value.
+
+|Justify Value|Description|
+|:------------|:----------|
+|MaplyLabelJustifyLeft|The label will be placed with its left side on the location.|
+|MaplyLabelJustifyMiddle|The label will be centered on the location.|
+|MaplyLabelJustifyRight|The label will be placed with its right side on the location.|
+ */
+@property (nonatomic,assign) MaplyLabelJustify justify;
+
+/**
+ User data object for selection
+
+ When the user selects a feature and the developer gets it in their delegate, this is an object they can use to figure out what the label means to them.
+ */
+@property (nonatomic,strong) id __nullable userObject;
+
+@end
+
+typedef MaplyLabel WGLabel;
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyLight.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyLight.h
new file mode 100644
index 0000000..31c415f
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyLight.h
@@ -0,0 +1,60 @@
+/* MaplyLight.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 1/30/13.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+/**
+ The Light provides a simple interface to basic lighting within the toolkit.
+
+ You can have up to 8 lights in the current version of the toolkit. Obviously this is all shader implementation with OpenGL ES 2.0, so you can always just bypass this and do what you like. However, the default shaders will look for these lights.
+
+ The lights are very simple, suitable for the globe, and contain a position, a couple of colors, and a view dependent flag.
+ */
+@interface MaplyLight : NSObject
+
+/**
+ The location of this particular light in display space.
+
+ This is a single light's location in display space. Display space for the globe is based on a radius of 1.0.
+ */
+@property (nonatomic,assign) MaplyCoordinate3d pos;
+
+/**
+ Controls whether the light takes the model matrix into account or not.
+
+ If set, this light moves with the model (usually the globe). You'd use this for a real sun position. If not set, the light is static and does not move or rotate.
+ */
+@property (nonatomic,assign) bool viewDependent;
+
+/**
+ Ambient color for the light.
+
+ This color will always be added to any given pixel. It provides a baseline lighting value.
+ */
+@property (nonatomic,strong) UIColor *__nullable ambient;
+
+/**
+ Diffuse light color.
+
+ The diffuse color is multiplied by a directional value and so will vary depending on geometry normals.
+ */
+@property (nonatomic,strong) UIColor *__nullable diffuse;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyLocationTracker.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyLocationTracker.h
new file mode 100644
index 0000000..76e6ebc
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyLocationTracker.h
@@ -0,0 +1,174 @@
+/*
+ * MaplyBaseViewController.h
+ * MaplyComponent
+ *
+ * Created by Ranen Ghosh on 11/23/16.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <CoreLocation/CoreLocation.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+#define LOC_TRACKER_POS_MARKER_SIZE 32
+
+@class MaplyBaseViewController;
+
+typedef struct
+{
+ float lonDeg;
+ float latDeg;
+ float headingDeg;
+} MaplyLocationTrackerSimulationPoint;
+
+typedef enum {MaplyLocationLockNone, MaplyLocationLockNorthUp, MaplyLocationLockHeadingUp, MaplyLocationLockHeadingUpOffset} MaplyLocationLockType;
+
+/*
+ Implement the MaplyLocationTrackerDelegate protocol to receive location services callbacks.
+*/
+@protocol MaplyLocationTrackerDelegate
+
+// This is to handle problems / failures further up the line.
+- (void) locationManager:(CLLocationManager * __nonnull)manager didFailWithError:(NSError * __nonnull)error;
+
+- (void) locationManager:(CLLocationManager * __nonnull)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status;
+
+@optional
+
+- (void) updateLocation:(CLLocation * __nonnull)location;
+
+@end
+
+/*
+ Implement the MaplyLocationSimulatorDelegate protocol to provide simulated locations
+*/
+@protocol MaplyLocationSimulatorDelegate
+
+- (MaplyLocationTrackerSimulationPoint)getSimulationPoint;
+
+@optional
+
+- (bool)hasValidLocation;
+
+@end
+
+/*
+ The MaplyLocationTracker class provides support for showing current position and heading on the map or globe.
+
+ Be sure to set NSLocationWhenInUseUsageDescription in your app's Info.plist before using.
+ */
+@interface MaplyLocationTracker : NSObject <CLLocationManagerDelegate>
+
+/// Exposes MaplyLocationTracker's location manager for use elsewhere
+@property (nonatomic, readonly, nullable) CLLocationManager *locationManager;
+
+/**
+ MaplyLocationTracker constructor
+
+ @param viewC The globe or map view controller
+
+ @param useHeading Use location services heading information (requires physical magnetometer)
+
+ @param useCourse Use location services course information as fallback if heading unavailable
+ */
+- (nonnull instancetype)initWithViewC:(MaplyBaseViewController *__nullable)viewC
+ useHeading:(bool)useHeading
+ useCourse:(bool)useCourse;
+
+/**
+ MaplyLocationTracker constructor
+
+ @param viewC The globe or map view controller
+
+ @param delegate The MaplyLocationTrackerDelegate for receiving location event callbacks
+
+ @param useHeading Use location services heading information (requires physical magnetometer)
+
+ @param useCourse Use location services course information as fallback if heading unavailable
+ */
+- (nonnull instancetype)initWithViewC:(MaplyBaseViewController *__nullable)viewC
+ delegate:(NSObject<MaplyLocationTrackerDelegate> *__nullable)delegate
+ useHeading:(bool)useHeading
+ useCourse:(bool)useCourse;
+
+/**
+ MaplyLocationTracker constructor
+
+ @param viewC The globe or map view controller
+
+ @param delegate The MaplyLocationTrackerDelegate for receiving location event callbacks
+
+ @param simulator The MaplyLocationSimulatorDelegate for generating simulated locations
+
+ @param useHeading Use location services heading information (requires physical magnetometer)
+
+ @param useCourse Use location services course information as fallback if heading unavailable
+ */
+- (nonnull instancetype)initWithViewC:(MaplyBaseViewController *__nullable)viewC
+ delegate:(NSObject<MaplyLocationTrackerDelegate> *__nullable)delegate
+ simulator:(NSObject<MaplyLocationSimulatorDelegate> *__nullable)simulator
+ simInterval:(NSTimeInterval)simInterval
+ useHeading:(bool)useHeading
+ useCourse:(bool)useCourse;
+
+/**
+ Min/max visibility for the marker assigned to follow location.
+ */
+@property (nonatomic,assign) float markerMinVis,markerMaxVis;
+
+/**
+ Draw priority for the marker assigned to follow location.
+ */
+@property (nonatomic,assign) int markerDrawPriority;
+
+/**
+ Change lock type
+
+ @param lockType The MaplyLocationLockType value for lock behavior
+
+ @param forwardTrackOffset The vertical offset if using MaplyLocationLockHeadingUpOffset (positive values are below the view center)
+ */
+- (void) changeLockType:(MaplyLocationLockType)lockType forwardTrackOffset:(int)forwardTrackOffset;
+
+/**
+ Stop the MaplyLocationTracker behavior and shut it down.
+ */
+- (void) teardown;
+
+/**
+ Get the current device location
+
+ @return The coordinate if valid, else kMaplyNullCoordinate
+ */
+- (MaplyCoordinate)getLocation;
+
+/**
+ Set the current simulated location.
+ */
+- (void) setLocation:(MaplyLocationTrackerSimulationPoint)point
+ altitude:(double)altitude;
+
+/**
+ Set the current simulated location.
+ */
+- (void) setLocation:(MaplyLocationTrackerSimulationPoint)point
+ altitude:(double)altitude
+ horizontalAccuracy:(double)horizontalAccuracy
+ verticalAccuracy:(double)verticalAccuracy
+ speed:(double)speed;
+;
+
+@end
+
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyMBTileFetcher.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyMBTileFetcher.h
new file mode 100644
index 0000000..278e5dc
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyMBTileFetcher.h
@@ -0,0 +1,46 @@
+/* MaplyMBTileFetcher.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 9/13/18.
+ * Copyright 2011-2022 mousebird consulting inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplySimpleTileFetcher.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+
+/**
+ MBTiles tile fetcher.
+
+ This tile fetcher focuses on a single MBTiles file. You mate this
+ with a QuadImageLoader to do the actual work.
+
+ Will work for image or vector MBTiles files.
+ */
+@interface MaplyMBTileFetcher : MaplySimpleTileFetcher
+
+/// Initialize with the name of the local MBTiles file
+- (nullable instancetype)initWithMBTiles:(NSString *__nonnull)fileName;
+
+/// Initialize with the name of the local MBTiles file and cache size in bytes (rounded up to whole pages)
+- (nullable instancetype)initWithMBTiles:(NSString *__nonnull)fileName
+ cacheSize:(int)cacheSize;
+
+// Coordinate system (probably Spherical Mercator)
+- (MaplyCoordinateSystem * __nonnull)coordSys;
+
+/// Format directly from the metadata
+@property (nonatomic,nullable) NSString *format;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyMarker.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyMarker.h
new file mode 100644
index 0000000..ea31c2d
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyMarker.h
@@ -0,0 +1,85 @@
+/*
+ * WGMarker.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 7/24/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+/**
+ The Marker places a UIImage on the globe or map at a given location.
+
+ The Maply Marker takes a location and image, using those to display a textured rectangle on the globe (or map). Since it's a real 3D object it will get larger and smaller as the user moves around.
+
+ If you want a screen based object that stays the same size and is displayed on top of everything else, look to the MaplyScreenMarker.
+ */
+@interface MaplyMarker : NSObject
+
+/**
+ Center of the marker in geographic coordinates (lon/lat in radians).
+
+ The Maply Marker is a 3D object so this is the center of the marker on the globe or map.
+ */
+@property (nonatomic,assign) MaplyCoordinate loc;
+
+
+/**
+ Size of the marker in display coordinates.
+
+ This is the size of the marker in display coordinates. For the globe display coordinates are based on a radius of 1.0.
+ */
+@property (nonatomic,assign) CGSize size;
+
+/**
+ Image or MaplyTexture to use for the marker.
+
+ If set, we'll display a UIImage at the given location of the given size. If not set, it's just a color rectangle which is not very exciting. The view controller tracks the UIImage and will reuse it as necessary and release it when finished.
+ */
+@property (nonatomic,strong) id __nullable image;
+
+/**
+ Images or MaplyTextures to use for the marker.
+
+ If set we'll animate these images one after the other over the duration.
+ */
+@property (nonatomic,strong) NSArray * __nullable images;
+
+/**
+ The time we'll take to cycle through all the images for the marker.
+
+ If images are passed in, this is the time it will take to cycle through them all. By default this is 5s.
+ */
+@property (nonatomic) double period;
+
+/**
+ Marker selectability. On by default
+
+ If set, this marker can be selected by the user. If not set, this marker will never appear in selection results.
+ */
+@property (nonatomic,assign) bool selectable;
+
+/**
+ User data object for selection
+
+ When the user selects a feature and the developer gets it in their delegate, this is an object they can use to figure out what the label means to them.
+ */
+@property (nonatomic,strong) id __nullable userObject;
+
+@end
+
+typedef MaplyMarker WGMarker;
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyMatrix.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyMatrix.h
new file mode 100644
index 0000000..646a29b
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyMatrix.h
@@ -0,0 +1,65 @@
+/*
+ * MaplyMatrix.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 10/16/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+/**
+ Represents a matrix for position manipulation.
+
+ Encapsulates a 4x4 matrix used for object placement and other things. This is more a wrapper than a full service object.
+ */
+@interface MaplyMatrix : NSObject
+
+/**
+ Construct with yaw, pitch, and roll parameters.
+
+ Construct the matrix with the standard yaw, pitch, and roll used by aircraft.
+ */
+- (nonnull instancetype)initWithYaw:(double)yaw pitch:(double)pitch roll:(double)roll;
+
+/**
+ Construct with a consistent scale in each dimension.
+
+ Construct with the same scale in x,y, and z.
+ */
+- (nonnull instancetype)initWithScale:(double)scale;
+
+/**
+ Construct with a translation.
+
+ Construct with a translation in 3D.
+ */
+- (nonnull instancetype)initWithTranslateX:(double)x y:(double)y z:(double)z;
+
+/**
+ Construct a rotation around the given axis.
+
+ Build a matrix that rotates the given amount (in radians) around the given axis.
+ */
+- (nonnull instancetype)initWithAngle:(double)ang axisX:(double)x axisY:(double)y axisZ:(double)z;
+
+/**
+ Multiply the given matrix with this one and return a new one.
+
+ Multiply the given matrix like so: ret = this * other. Return the new one.
+ */
+- (nonnull instancetype)multiplyWith:(MaplyMatrix * __nonnull)other;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyMoon.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyMoon.h
new file mode 100644
index 0000000..ee967b8
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyMoon.h
@@ -0,0 +1,50 @@
+/* MaplyMoon.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 7/2/15.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyComponentObject.h>
+#import <WhirlyGlobe/WhirlyGlobeViewController.h>
+#import <WhirlyGlobe/MaplyLight.h>
+
+/**
+ Utility for calculating moon position.
+
+ This is a utility class that figures out where the moon is at a given data and provides the position.
+ */
+@interface MaplyMoon : NSObject
+
+/**
+ Initialize with a date.
+
+ Initialize with the given date. The moon position will correspond to that. Must be after 2000.
+ */
+- (nonnull instancetype)initWithDate:(NSDate *__nonnull)date;
+
+/// Location on the globe where the moon would land if it fell straight down. Ouch.
+- (MaplyCoordinate)asCoordinate;
+
+/// Return the location above the globe in lon/lat/distance. Yay geocentric!
+- (MaplyCoordinate3d)asPosition;
+
+/// Illuminated fraction of the moon
+@property (readonly) double illuminatedFraction;
+
+/// Phase of the moon.
+@property (readonly) double phase;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyPanDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyPanDelegate.h
new file mode 100644
index 0000000..bf3dc43
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyPanDelegate.h
@@ -0,0 +1,32 @@
+/* MaplyPanDelegate.h
+ * WhirlyGlobeLib
+ *
+ * Created by Steve Gifford on 1/10/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+
+// Custom pan gesture recognizer that plays well with scroll views.
+@interface MinDelay2DPanGestureRecognizer : UIPanGestureRecognizer
+
+- (void)forceEnd;
+
+@end
+
+@interface MaplyPanDelegate : NSObject <UIGestureRecognizerDelegate>
+
+@property (nonatomic,weak) UIGestureRecognizer *gestureRecognizer;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyParticleSystem.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyParticleSystem.h
new file mode 100644
index 0000000..b5f603c
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyParticleSystem.h
@@ -0,0 +1,215 @@
+/*
+ * MaplyParticleSystem.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 4/26/15.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyShader.h>
+#import <WhirlyGlobe/MaplyRenderTarget.h>
+
+typedef NS_ENUM(NSInteger, MaplyParticleSystemType) {
+ MaplyParticleSystemTypePoint,
+ MaplyParticleSystemTypeRectangle,
+};
+
+/**
+ A particle system is used to spawn large numbers of small moving objects.
+
+ The particle system defines what the objects are and how they're controlled. Actual data is handled through the MaplyParticleBatch.
+
+ You set up a particle system and then add MaplyParticleBatches via a view controller.
+ */
+@interface MaplyParticleSystem : NSObject
+
+/**
+ Name of the particle system.
+
+ The particle system name is used for performance debugging.
+ */
+@property (nonatomic,strong) NSString * __nullable name;
+
+/**
+ The type of the particle system.
+
+ At present particle systems are just point geometry.
+ */
+@property (nonatomic,assign) MaplyParticleSystemType type;
+
+/**
+ Position shader for two stage particles.
+
+ If there is a position shader then it is run first and particle data is then
+ shared between this shader and the regular shader.
+ */
+@property (nonatomic,strong) MaplyShader * __nullable positionShader;
+
+/**
+ Shader to use for rendering particles.
+
+ This can either be a single stage shader or it can be part of a two stage shader with
+ the positionShader.
+ */
+@property (nonatomic,strong) MaplyShader * __nullable renderShader;
+
+/**
+ Individual particle lifetime.
+
+ The created particles will last only a certain amount of time.
+ */
+@property (nonatomic,assign) NSTimeInterval lifetime;
+
+/**
+ The base that particle time is measured from.
+
+ Individual particles will measure their own lifetime against this base value.
+ */
+@property (nonatomic,assign) NSTimeInterval baseTime;
+
+/**
+ Total number of particles to be represented at once.
+
+ This is the most particles we'll have on the screen at any time. Space will be allocated for them, so don't overdo it.
+ */
+@property (nonatomic,assign) int totalParticles;
+
+/**
+ Batch size for MaplyParticleBatch.
+
+ Particles need to be created in large batches for efficiency. This is the size of individual batches.
+
+ Only for OpenGL ES. Metal does particles as one big batch.
+ */
+@property (nonatomic,assign) int batchSize;
+
+/**
+ Metal only.
+ Size of a single to be passed in to the calculation and rendering shaders.
+ */
+@property (nonatomic,assign) int vertexSize;
+
+/**
+ Turn on/off the continuous rendering for particles.
+
+ Normally particle systems force the renderer to draw every frame. That's how the particles move. You can turn that behavior off by setting this to false.
+ */
+@property (nonatomic,assign) bool continuousUpdate;
+
+/**
+ Initialize a particle system with a name.
+
+ The particle system needs the name for performance and debugging. The rest of the values can left to their defaults.
+ */
+- (nonnull instancetype)initWithName:(NSString *__nonnull)name viewC:(NSObject <MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+/**
+ Add an attribute we'll be expecting in each batch.
+
+ Adds an attribute name and type which will be present in each batch.
+
+ OpenGL ES Only. Metal handles things as blocks of memory.
+ */
+- (void)addAttribute:(NSString *__nonnull)attrName type:(MaplyShaderAttrType)type;
+
+/**
+ For two stage shaders, these are the varying outputs from one shader to the next.
+
+ Two stage shaders run a position shader and then a regular render shader
+ from the position output. Add any varying values you want to share per
+ vertex from the former to the latter.
+
+ OpenGL ES Only. Metal does this more simply.
+ */
+- (void)addVarying:(NSString *__nonnull)varyAttrName inputName:(NSString *__nonnull)inputName type:(MaplyShaderAttrType)type;
+
+/**
+ For Metal, we just pass in input and output arrays (at least two) along with the number of entries
+ in those arrays. The shaders do the rest of the work in Metal.
+ */
+- (void)addCalculationNum:(int)numEntries data:(NSMutableArray<NSData *> * __nonnull)dataEntries;
+
+/**
+ Add a texture to the particle system.
+
+ All the textures will be handed over to the shader.
+ */
+- (void)addTexture:(id __nonnull)image;
+
+/**
+ Draw these particles to the given render target.
+
+ Rather than being drawn to the screen, these particles will be drawn to the offscreen render target.
+ */
+- (void)setRenderTarget:(MaplyRenderTarget * __nonnull)renderTarget;
+
+@end
+
+
+/**
+ A particle batch adds a set number of particles to the system.
+
+ The particle batch holds the number of particles defined in the MaplyParticleSystem batchSize property. Each attribute array is added individually via an NSData object. All attributes must be present or the batch is invalid and won't be passed through the system.
+ */
+@interface MaplyParticleBatch : NSObject
+
+/**
+ The particle system this batch belongs to.
+ */
+@property (nonatomic,weak) MaplyParticleSystem * __nullable partSys;
+
+/**
+ The current time.
+
+ This will be set by default. However, you can control what the time basis for a particle batch is.
+ */
+@property (nonatomic,assign) NSTimeInterval time;
+
+/**
+ Initialize with the particle system.
+
+ The batch is initialized with its particle system. You must then call addAttribute:values: repeatedly with attribute arrays.
+ */
+- (nonnull instancetype)initWithParticleSystem:(MaplyParticleSystem *__nonnull)partSys;
+
+/**
+ OpenGL ES only.
+
+ Add an attribute array of the given name.
+
+ Each attribute in the MaplyParticleSystem must be filled in here. The name must correspond and the length of the data must match.
+
+ @return Returns true if the attribute array was valid, false otherwise.
+ */
+- (bool) addAttribute:(NSString *__nonnull)attrName values:(NSData *__nonnull)data;
+
+/**
+ Metal only.
+
+ We add the batch as a single blob of data. Format is up to you and your shader.
+
+ */
+- (void) addData:(NSData * __nonnull)data;
+
+/**
+ Tests if the batch is valid.
+
+ This checks if all the attribute arrays are present and valid.
+ */
+- (bool) isValid;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyPinchDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyPinchDelegate.h
new file mode 100644
index 0000000..06c35b2
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyPinchDelegate.h
@@ -0,0 +1,23 @@
+/* MaplyPinchDelegate.h
+ * WhirlyGlobeLib
+ *
+ * Created by Steve Gifford on 1/10/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyZoomGestureDelegate.h>
+
+@interface MaplyPinchDelegate : MaplyZoomGestureDelegate
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyPoints.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyPoints.h
new file mode 100644
index 0000000..2b2e6fd
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyPoints.h
@@ -0,0 +1,84 @@
+/*
+ * MaplyPoints.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 10/21/15
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+#import <WhirlyGlobe/MaplyMatrix.h>
+
+/**
+ The Maply Points object is used to add a large number of static points to the scene.
+
+ Rather than add a single 3D point we assume you want to add a lot of them all at once. This object lets you do that and lets you assign the various data values to input attributes in your custom shader.
+
+ All the cool kids have custom shaders.
+ */
+@interface MaplyPoints : NSObject
+
+/// Initialie with a hint as to the number of points you'll be adding (not required).
+- (__nonnull id)initWithNumPoints:(int)numPoints;
+
+/// Transform to apply to the point locations. A center is good.
+@property (nonatomic,strong) MaplyMatrix * __nullable transform;
+
+/// Add a geocoordinate in lon/lat and Z (meters).
+- (void)addGeoCoordLon:(float)x lat:(float)y z:(float)z;
+
+/// Directly add a coordinate in display space. Remember the globe is a sphere with radius = 1.0.
+- (void)addDispCoordX:(float)x y:(float)y z:(float)z;
+
+/// Add a display space coordinate, but use doubles for precision.
+- (void)addDispCoordDoubleX:(double)x y:(double)y z:(double)z;
+
+/// Add a color, which will be converted to 8 bits before going to the shader.
+- (void)addColorR:(float)r g:(float)g b:(float)b a:(float)a;
+
+/**
+ Add a new attribute array of the given type.
+
+ If you have a custom shader, this is a convenient way to pass a large array of attributes to it. Just specify the name (attribute name in the shader) and the type and then add the appropriate values. The data will be handed down to the shader at render time.
+
+ @param attrName The name of the attribute as used by the shader.
+
+ @param type The data type of the attribute.
+
+ @return An index (or -1 if invalid) for the attribute. Use this in the addAttribute calls.
+ */
+- (int)addAttributeType:(NSString *__nonnull)attrName type:(MaplyShaderAttrType)type;
+
+/// Add an integer attribute.
+- (void)addAttribute:(int)whichAttr iVal:(int)val;
+
+/// Add a float attribute.
+- (void)addAttribute:(int)whichAttr fVal:(float)val;
+
+/// Add a two component float attribute.
+- (void)addAttribute:(int)whichAttr fValX:(float)valX fValY:(float)valY;
+
+/// Add a three component float attribute.
+- (void)addAttribute:(int)whichAttr fValX:(float)fValX fValY:(float)valY fValZ:(float)valZ;
+
+/// Add a three component float attribute, but we'll store it at doubles until it gets to the shader.
+- (void)addAttribute:(int)whichAttr valX:(double)valX valY:(double)valY valZ:(double)valZ;
+
+/// Add a four commponent float attribute.
+- (void)addAttribute:(int)whichAttr fValX:(float)valX fValY:(float)valY fValZ:(float)valZ fValW:(float)valW;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyQuadImageFrameLoader.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyQuadImageFrameLoader.h
new file mode 100644
index 0000000..b4fea4c
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyQuadImageFrameLoader.h
@@ -0,0 +1,191 @@
+/*
+ * MaplyQuadImageFrameLoader.h
+ *
+ * Created by Steve Gifford on 9/13/18.
+ * Copyright 2012-2022 mousebird consulting inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyQuadImageLoader.h>
+#import <WhirlyGlobe/MaplyActiveObject.h>
+
+@class MaplyQuadImageFrameLoader;
+
+/**
+ Quad Image FrameAnimation runs through the frames in a Quad Image Frame loader over time.
+
+ Set this up with a MaplyQuadImageFrameLoader and it'll run through the available frames from start to finish.
+ At the end it will snap back to the beginning.
+ */
+@interface MaplyQuadImageFrameAnimator : MaplyActiveObject
+
+/// Initialize with the image frame loader and view controller
+- (nonnull instancetype)initWithFrameLoader:(MaplyQuadImageFrameLoader * __nonnull)loader viewC:(MaplyBaseViewController * __nonnull)viewC;
+
+/// How long to animate from start to finish.
+@property (nonatomic,assign) NSTimeInterval period;
+
+/// How long to pause at the end of the sequence before starting back
+@property (nonatomic,assign) NSTimeInterval pauseLength;
+
+/// Remove the animator and stop animating
+- (void)shutdown;
+
+@end
+
+/**
+ The Maply Quad Image Frame Loader can generation per-frame stats. These are them.
+ */
+@interface MaplyQuadImageFrameStats : NSObject
+
+/// Number of tiles this frame is in (loading and loaded)
+@property (nonatomic) int totalTiles;
+
+/// Number of tiles this frame has yet to load
+@property (nonatomic) int tilesToLoad;
+
+@end
+
+/**
+ Stats generated by the Maply Quad Image Frame Loader.
+ */
+@interface MaplyQuadImageFrameLoaderStats : NSObject
+
+/// Total number of tiles managed by the loader
+@property (nonatomic) int numTiles;
+
+/// Per frame stats for current loading state
+@property (nonatomic,nonnull) NSArray<MaplyQuadImageFrameStats *> *frames;
+
+@end
+
+/// How we load frames in the QuadImageFrameLoader
+/// Broad means we load 0 first and the on down
+/// Narrow means we load the frames around the current display first
+typedef NS_ENUM(NSInteger, MaplyLoadFrameMode) {
+ MaplyLoadFrameBroad,
+ MaplyLoadFrameNarrow,
+};
+
+/**
+ The Maply Quad Image Frame Loader is for paging individual frames of image pyramids.
+
+ This works much like the Quad Image Loader, but handles more than one frame. You can animate
+ between the frames with the QuadImageFrameAnimator
+ */
+@interface MaplyQuadImageFrameLoader : MaplyQuadImageLoaderBase
+
+/**
+ Initialize with multiple tile sources (one per frame).
+
+ @param params The sampling parameters describing how to break down the data for projection onto a globe or map.
+ @param tileInfos A list of tile info objects to fetch for each frame.
+ @param viewC the View controller (or renderer) to add objects to.
+ */
+- (nullable instancetype)initWithParams:(MaplySamplingParams *__nonnull)params tileInfos:(NSArray<NSObject<MaplyTileInfoNew> *> *__nonnull)tileInfos viewC:(MaplyBaseViewController * __nonnull)viewC;
+
+/// How frames are loaded (top down vs broad)
+@property (nonatomic,assign) MaplyLoadFrameMode loadFrameMode;
+
+/**
+ Add another rendering focus to the frame loader.
+
+ Normally you'd have one point of focus for a frame loader resulting in one image
+ to be displayed. But if you're using render targets, you may want to have two
+ and combine them in some way yourself. Or more. No idea why you'd do that.
+
+ If you're going to do this, call addFocus right after you create the FrameLoader.
+ */
+- (void)addFocus;
+
+/**
+ Return the number of focii. Normally it's 1.
+
+ See addFocus for what these are. You probably don't need to be using them.
+ */
+- (int)getNumFocus;
+
+/**
+ Set the interpolated location within the array of frames.
+
+ Each set of frames can be accessed from [0.0,numFrames]. Images will be interpolated between
+ those values and may be snapped if data has not yet loaded.
+
+ This value is used once per frame, so feel free to call this as much as you'd like.
+ */
+- (void)setCurrentImage:(double)where;
+
+/**
+ Set the currentImage for the given focus. See addFocus for what those are.
+ */
+- (void)setFocus:(int)focusID currentImage:(double)where;
+
+/**
+ Return the interpolated location within the array of frames.
+ */
+- (double)getCurrentImage;
+
+/**
+ Return the interpolated location within the array of frames for a given focus. See addFocus for what that means.
+ */
+- (double)getCurrentImageForFocus:(int)focusID;
+
+/**
+ Set whether we require the top tiles to be loaded before a frame can be displayed.
+
+ Normally the system wants all the top level tiles to be loaded (just one at level 0)
+ to be in memory before it will display a frame at all. You can turn this off.
+ */
+- (void)setRequireTopTiles:(bool)newVal;
+
+/** Number of tile sources passed in as individual frames.
+ */
+- (int)getNumFrames;
+
+/**
+ An optional render target for this loader.
+
+ The loader can draw to a render target rather than to the screen.
+ You use this in a multi-pass rendering setup.
+
+ This version takes a specific focus. See addFocus for what that means.
+ */
+- (void)setFocus:(int)focusID renderTarget:(MaplyRenderTarget *__nonnull)renderTarget;
+
+/**
+ Shader to use for rendering the image frames for a particular focus.
+
+ Consult addFocus for what this means.
+ */
+- (void)setFocus:(int)focusID shader:(MaplyShader * __nullable)shader;
+
+/**
+ Get the frame stats for what's loaded and what's not.
+ */
+- (MaplyQuadImageFrameLoaderStats * __nonnull)getFrameStats;
+
+/**
+ Change the tile sources and reload all the data.
+ <br>
+ You can change the tile source data is being loaded from. This will
+ force a reload and everything visual should change as the data comes in.
+ */
+- (void)changeTileInfos:(NSArray<MaplyTileInfoNew> * __nullable)tileInfo;
+
+/** Turn off the image loader and shut things down.
+ This unregisters us with the sampling layer and shuts down the various objects we created.
+ */
+- (void)shutdown;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyQuadImageLoader.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyQuadImageLoader.h
new file mode 100644
index 0000000..d5b346d
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyQuadImageLoader.h
@@ -0,0 +1,229 @@
+/*
+ * MaplyQuadImageLoader.h
+ *
+ * Created by Steve Gifford on 4/10/18.
+ * Copyright 2012-2022 Saildrone Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyControllerLayer.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+#import <WhirlyGlobe/MaplyQuadSampler.h>
+#import <WhirlyGlobe/MaplyRemoteTileFetcher.h>
+#import <WhirlyGlobe/MaplyQuadLoader.h>
+
+/**
+ This version of the loader return is used by the MaplyImageLoaderInterpreter.
+
+ When image tiles load, the interpeter fills in these contents, which can
+ include any sort of ComponentObject and, of course, images.
+ */
+@interface MaplyImageLoaderReturn : MaplyLoaderReturn
+
+/// Initialize with the loader this will be attached to
+- (id __nonnull)initWithLoader:(MaplyQuadLoaderBase * __nonnull)loader;
+
+/// Add an image to this loaded return.
+/// You can add multiple, but the interpreter should be expecting that
+- (void)addImageTile:(MaplyImageTile * __nonnull)image;
+
+/// Add a UIImage to the loader return
+/// This just adds a MaplyImageTile wrapper around the UIImage.
+- (void)addImage:(UIImage * __nonnull)image;
+
+/// Return an array of Images
+- (NSArray<MaplyImageTile *> * __nonnull)getImages;
+
+/// Clear out any images. Presumably to replace them.
+- (void)clearImages;
+
+/// If any component objects are associated with the tile, these are them.
+/// They need to start disabled. The system will enable and delete them when it is time.
+- (void)addCompObjs:(NSArray<MaplyComponentObject *> * __nonnull)compObjs;
+
+/// Return the component objects added for this loader return
+- (NSArray<MaplyComponentObject *> *__nonnull)getCompObjs;
+
+/// Clear out any component objects, presumably to replace them
+- (void)clearCompObjs;
+
+/// These component objects are assumed to be overlaid and so only one
+/// set will be displayed at a time.
+- (void)addOvlCompObjs:(NSArray<MaplyComponentObject *> * __nonnull)compObjs;
+
+/// Return the overlay component objects added for this loader return
+- (NSArray<MaplyComponentObject *> *__nonnull)getOvlCompObjs;
+
+/// Clear out any component objects, presumably to replace them
+- (void)clearOvlCompObjs;
+
+@end
+
+/**
+ Image loader intrepreter turns NSData objects into MaplyImageTiles.
+
+ This is the default interpreter used by the MaplyQuadImageLoader.
+ */
+@interface MaplyImageLoaderInterpreter : NSObject<MaplyLoaderInterpreter>
+@end
+
+/**
+ This loader interpreter sticks a designator in the middle of tiles
+ and a line around the edge. Nice for debugging.
+ */
+@interface MaplyOvlDebugImageLoaderInterpreter : MaplyImageLoaderInterpreter
+
+// Intialize with the loader we're using. Need this for extents of tiles
+- (instancetype __nonnull)initWithViewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+@end
+
+/**
+ This loader interpreter makes up an image for the given frame/tile
+ and returns that. It doesn't use any returned data.
+ */
+@interface MaplyDebugImageLoaderInterpreter : MaplyImageLoaderInterpreter
+
+- (instancetype __nonnull)initWithViewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+@end
+
+/**
+ This loader interpreter treats input image data objects as PNGs containing raw data.
+ The difference is we'll use a direct PNG reader to tease it out, rather than UIImage.
+ */
+@interface MaplyRawPNGImageLoaderInterpreter : MaplyImageLoaderInterpreter
+
+/// In some cases we just want to pick values out of the input
+- (void)addMappingFrom:(int)inVal to:(int)outVal;
+
+@end
+
+/// Name of the shared MaplyRemoteTileFetcher
+extern NSString * _Nonnull const MaplyQuadImageLoaderFetcherName;
+
+/**
+ Base object for Maply Quad Image loader.
+
+ Look to the subclasses for actual functionality. This holds methods they share.
+ */
+@interface MaplyQuadImageLoaderBase : MaplyQuadLoaderBase
+
+/** Set the base priority values for produced tiles.
+
+ The system will use a range of values to deal with overlaps.
+ This is the base value.
+ */
+@property (nonatomic) int baseDrawPriority;
+
+// Offset between levels for a calculated draw priority
+@property (nonatomic) int drawPriorityPerLevel;
+
+// Base color for geometry produced
+@property (nonatomic,retain,nonnull) UIColor *color;
+
+// Write to the z buffer when rendering. On by default
+@property (nonatomic,assign) bool zBufferWrite;
+
+// Read from the z buffer when rendering. Off by default
+@property (nonatomic,assign) bool zBufferRead;
+
+// Turn display of loader on or off. Will still load, though.
+@property bool enable;
+
+/**
+ Shader to use for rendering the image frames.
+
+ If not set we'll pick the default visual shader.
+ */
+- (void)setShader:(MaplyShader * __nullable)shader;
+
+/**
+ An optional render target for this loader.
+
+ The loader can draw to a render target rather than to the screen.
+ You use this in a multi-pass rendering setup.
+ */
+- (void)setRenderTarget:(MaplyRenderTarget *__nonnull)renderTarget;
+
+/**
+ In special cases we may have tiles that already have borders baked in. In that case, call this
+ method to set both the total textures size and the number of border pixels around the outside.
+
+ By default this functionality is off.
+ */
+- (void)setTextureSize:(int)texSize borderSize:(int)borderSize;
+
+/**
+ Set the image format for internal imagery storage.
+
+ OpenGL ES offers us several image formats that are more efficient than 32 bit RGBA, but they're not always appropriate. This property lets you choose one of them. The 16 or 8 bit ones can save a huge amount of space and will work well for some imagery, most maps, and a lot of weather overlays.
+
+ Be sure to set this at layer creation, it won't do anything later on.
+
+ | Image Format | Description |
+ |:-------------|:------------|
+ | MaplyImageIntRGBA | 32 bit RGBA with 8 bits per channel. The default. |
+ | MaplyImageUShort565 | 16 bits with 5/6/5 for RGB and none for A. |
+ | MaplyImageUShort4444 | 16 bits with 4 bits for each channel. |
+ | MaplyImageUShort5551 | 16 bits with 5/5/5 bits for RGB and 1 bit for A. |
+ | MaplyImageUByteRed | 8 bits, where we choose the R and ignore the rest. |
+ | MaplyImageUByteGreen | 8 bits, where we choose the G and ignore the rest. |
+ | MaplyImageUByteBlue | 8 bits, where we choose the B and ignore the rest. |
+ | MaplyImageUByteAlpha | 8 bits, where we choose the A and ignore the rest. |
+ | MaplyImageUByteRGB | 8 bits, where we average RGB for the value. |
+ | MaplyImage4Layer8Bit | 32 bits, four channels of 8 bits each. Just like MaplyImageIntRGBA, but a warning not to do anything too clever in sampling. |
+ */
+@property (nonatomic) MaplyQuadImageFormat imageFormat;
+
+@end
+
+/**
+ The Maply Quad Image Loader is for paging image pyramids local or remote.
+
+ This layer pages image pyramids. They can be local or remote, in any coordinate system Maply supports and you provide a MaplyTileInfoNew conformant object to do the actual image tile fetching.
+
+ You probably don't have to implement your own tile source. Go look at the MaplyRemoteTileFetcher and MaplyMBTileFetcher objects. Those will do remote and local fetching.
+ */
+@interface MaplyQuadImageLoader : MaplyQuadImageLoaderBase
+
+/**
+ Initialize with a single tile info object and the sampling parameters.
+
+ @param params The sampling parameters describing how to break down the data for projection onto a globe or map.
+ @param tileInfo A single tile info object describing where the data is and how to get it.
+ @param viewC the View controller (or renderer) to add objects to.
+ */
+- (nullable instancetype)initWithParams:(MaplySamplingParams *__nonnull)params tileInfo:(NSObject<MaplyTileInfoNew> *__nullable)tileInfo viewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+/**
+ Initialize with multiple tile sources and sampling parameters.
+
+ @param params The sampling parameters describing how to break down the data for projection onto a globe or map.
+ @param tileInfos A list of tile info objects to fetch for each tile. If one fails, the tile fails to load.
+ @param viewC the View controller (or renderer) to add objects to.
+ */
+- (nullable instancetype)initWithParams:(MaplySamplingParams *__nonnull)params tileInfos:(NSArray<NSObject<MaplyTileInfoNew> *> *__nonnull)tileInfos viewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+/**
+ Change the tile source and reload all the data.
+ <br>
+ You can change the tile source data is being loaded from. This will
+ force a reload and everything visual should change as the data comes in.
+ */
+- (void)changeTileInfo:(NSObject<MaplyTileInfoNew> *__nonnull)tileInfo;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyQuadLoader.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyQuadLoader.h
new file mode 100644
index 0000000..65ad61f
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyQuadLoader.h
@@ -0,0 +1,236 @@
+/*
+ * MaplyQuadLoader.h
+ *
+ * Created by Steve Gifford on 2/12/19.
+ * Copyright 2012-2022 Saildrone Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+#import <WhirlyGlobe/MaplyControllerLayer.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+#import <WhirlyGlobe/MaplyQuadSampler.h>
+#import <WhirlyGlobe/MaplyRemoteTileFetcher.h>
+
+@class MaplyQuadLoaderBase;
+
+/**
+ Passed in to and returned by the Loader Interpreter.
+
+ We pass this into the interpreter with the unparsed data. It parses it and passes that
+ data back, possibly with an error.
+ */
+@interface MaplyLoaderReturn : NSObject
+
+/// Initialize with the loader this will be attached to
+- (id __nonnull)initWithLoader:(MaplyQuadLoaderBase * __nonnull)loader;
+
+/// Tile this is the data for
+@property (nonatomic) MaplyTileID tileID;
+
+/// If set, the frame. -1 by default
+@property (nonatomic,readonly) int frame;
+
+/// Data returned from a tile request. Unparsed.
+/// You can add multiple of these, but the interpreter should be expecting that
+- (void)addTileData:(id __nonnull) tileData;
+
+/// Return the tile NSData objects as an array
+- (NSArray<id> * __nonnull)getTileData;
+
+/// Return the first data object. You're probably only expecting the one.
+- (id __nullable)getFirstData;
+
+/// Set when the QuadLoader cancels a tile. You can check this in your dataForTile:
+- (bool)isCancelled;
+
+/// If this is set, the tile failed to parse
+/// You can set it and the system will deal with the results
+@property (nonatomic,strong) NSError * __nullable error;
+
+@end
+
+/**
+ Loader Interpreter converts raw data into images and objects.
+
+ Converts data returned from a remote source (or cache) into images and/or
+ MaplyComponentObjects that have already been added to the view (disabled).
+ */
+@protocol MaplyLoaderInterpreter<NSObject>
+
+/** Set when the loader first starts up.
+
+ If you need to tweak loader settings, do it here.
+ */
+- (void)setLoader:(MaplyQuadLoaderBase * __nonnull)loader;
+
+/**
+ Parse the data coming back from a remote request and turn it into something we can use.
+
+ Convert the NSData passed in to image and component objects (e.g. add stuff to the view controller).
+ Everything added should be disabled to start.
+ */
+- (void)dataForTile:(MaplyLoaderReturn * __nonnull)loadReturn loader:(MaplyQuadLoaderBase * __nonnull)loader;
+
+/**
+ Notification that the tile was unloaded by the system. If you're tracking your own resources, you may need this.
+ */
+- (void)tileUnloaded:(MaplyTileID)tileID;
+
+@end
+
+/** Base class for the quad loaders.
+
+ The image, frame, and data paging loaders all share much of the same functionality.
+ */
+@interface MaplyQuadLoaderBase : NSObject
+
+/**
+ Control how tiles are indexed, either from the lower left or the upper left.
+
+ If set, we'll use the OSM approach (also Google Maps) to y indexing. That's that default and it's normally what you're run into.
+
+ Strictly speaking, TMS addressing (the standard) is flipped the other way. So if your tile source looks odd, try setting this to false.
+
+ Default value is true.
+ */
+@property (nonatomic) bool flipY;
+
+/// Set for a lot of debugging output
+@property (nonatomic,assign) bool debugMode;
+
+/// View controller this is attached to.
+/// Useful for delegate calls that might not be tracking that.
+@property (nonatomic,readonly,weak,nullable) NSObject<MaplyRenderControllerProtocol> *viewC;
+
+/// If set, we'll call the interpreter on this queue
+@property (nonatomic,nullable,strong) dispatch_queue_t queue;
+
+/// Number of simulataneous tiles we'll parse
+/// This is really just a limit on the number of tiles we'lll parse concurrently to keep memory use under control
+@property (nonatomic) unsigned int numSimultaneousTiles;
+
+// True if the loader is not currently loading anything
+- (bool)isLoading;
+
+/**
+ Calculate the bounding box for a single tile in geographic.
+
+ This is a utility method for calculating the extents of a given tile in geographic (e.g. lon/lat).
+
+ @param tileID The ID for the tile we're interested in.
+
+ @return The lower left and upper right corner of the tile in geographic coordinates. Returns kMaplyNullBoundingBox in case of error
+ */
+- (MaplyBoundingBox)geoBoundsForTile:(MaplyTileID)tileID;
+
+/**
+ Calculate the bounding box for a single tile in geographic using doubles.
+
+ This is a utility method for calculating the extents of a given tile in geographic (e.g. lon/lat).
+
+ @param tileID The ID for the tile we're interested in.
+
+ @return The lower left and upper right corner of the tile in geographic coordinates. Returns kMaplyNullBoundingBoxD in case of error
+ */
+- (MaplyBoundingBoxD)geoBoundsForTileD:(MaplyTileID)tileID;
+
+/**
+ Calculate the bounding box for a single tile in the local coordinate system.
+
+ This utility method calculates the bounding box for a tile in the coordinate system used for the layer.
+
+ @param tileID The ID for the tile we're interested in.
+
+ @return The lower left and upper right corner of the tile in local coordinates.
+ */
+- (MaplyBoundingBox)boundsForTile:(MaplyTileID)tileID;
+
+/**
+ Calculate the bounding box for a single tile in the local coordinate system using doubles.
+
+ This utility method calculates the bounding box for a tile in the coordinate system used for the layer.
+
+ @param tileID The ID for the tile we're interested in.
+
+ @return The lower left and upper right corner of the tile in geographic coordinates.
+ */
+- (MaplyBoundingBoxD)boundsForTileD:(MaplyTileID)tileID;
+
+/**
+ Return the center of the tile in display coordinates.
+
+ @param tileID The ID for the tile we're interested in.
+
+ @return Return the center in display space for the given tile.
+ */
+- (MaplyCoordinate3d)displayCenterForTile:(MaplyTileID)tileID;
+
+/**
+ Each sampling layer allocates a slot to keep track of continuous zoom levels.
+ Those are passed all the way through to the individual shaders.
+ */
+- (int)getZoomSlot;
+
+/// Use a specific tile fetcher rather than the one shared by everyone else
+- (void)setTileFetcher:(NSObject<MaplyTileFetcher> * __nonnull)tileFetcher;
+
+/// Set the interpreter for the data coming back. If you're just getting images, don't set this.
+- (void)setInterpreter:(NSObject<MaplyLoaderInterpreter> * __nonnull)interp;
+
+/// Return the current interpreter
+- (NSObject<MaplyLoaderInterpreter> * __nullable)getInterpreter;
+
+/**
+ Change the interpreter and reload all the data.
+ <br>
+ You can change the tile interpreter being used to build objects and images.
+ This will then force a reload of the tiles (hopefully from cache) and the
+ visuals will change as everything comes in.
+ */
+- (void)changeInterpreter:(NSObject<MaplyLoaderInterpreter> *__nonnull)interp;
+
+/**
+ Force a reload of the data.
+ <br>
+ All the current loads will be cancelled, any in flight will be ignored
+ and the loader will ask for a whole new set of data.
+ */
+- (void)reload;
+
+/**
+ Force a reload of the tiles overlapping a bounding box.
+ <br>
+ All the current loads will be cancelled, any in flight will be ignored
+ and the loader will ask for a whole new set of data.
+ */
+- (void)reloadArea:(MaplyBoundingBox)bounds;
+
+
+/**
+ Force a reload of the tiles overlapping a set of bounding boxes
+ <br>
+ All the current loads will be cancelled, any in flight will be ignored
+ and the loader will ask for a whole new set of data.
+ */
+- (void)reloadAreas:(NSArray<NSValue*>* __nullable)bounds;
+
+/** Turn off the loader and shut things down.
+ This unregisters us with the sampling layer and shuts down the various objects we created.
+ */
+- (void)shutdown;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyQuadPagingLoader.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyQuadPagingLoader.h
new file mode 100644
index 0000000..18d8b18
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyQuadPagingLoader.h
@@ -0,0 +1,82 @@
+/*
+ * MaplyQuadPagingLoader.h
+ *
+ * Created by Steve Gifford on 2/21/91.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyQuadLoader.h>
+
+/**
+ This version of the loader return is used by the MaplyQuadPagingLoader.
+
+ The Object pager is only expecting Component Objects and will manage
+ those as things are loaded in and out.
+ */
+@interface MaplyObjectLoaderReturn : MaplyLoaderReturn
+
+/// Initialize with the loader this will be attached to
+- (id __nonnull)initWithLoader:(MaplyQuadLoaderBase *__nonnull)loader;
+
+/// If any component objects are associated with the tile, these are them.
+/// They need to start disabled. The system will enable and delete them when it is time.
+- (void)addCompObjs:(NSArray<MaplyComponentObject *> * __nonnull)compObjs;
+
+/// Add a component object to the collection if it's non null
+- (void)addCompObj:(MaplyComponentObject * __nullable)compObj;
+
+/// Return an array of component objects that were added to this loader return
+- (NSArray<MaplyComponentObject *> * __nonnull)getCompObjs;
+
+@end
+
+/** General purpose quad paging loader.
+
+ This quadtree based paging loader is for fetching and load general geometry.
+ There are other loaders that handle images and image animations. This one is
+ purely for geometry.
+
+ You need to fill in at least a MaplyLoaderInterpreter, which is probably your own
+ implementation.
+
+ This replaces the QuadPagingLayer from WhirlyGlobe-Maply 2.x.
+ */
+@interface MaplyQuadPagingLoader : MaplyQuadLoaderBase
+
+/**
+ Initialize with a single tile info object, the interpreter and the sampling parameters.
+
+ @param params The sampling parameters describing how to break down the data for projection onto a globe or map.
+ @param tileInfo A optional tile info object describing where the data is and how to get it.
+ @param loadInterp The interpreter makes geometry from the input data. Or just makes it up if there is no input.
+ @param viewC the View controller (or renderer) to add objects to.
+ */
+- (nullable instancetype)initWithParams:(MaplySamplingParams *__nonnull)params
+ tileInfo:(NSObject<MaplyTileInfoNew> *__nullable)tileInfo
+ loadInterp:(NSObject<MaplyLoaderInterpreter> *__nullable)loadInterp
+ viewC:(MaplyBaseViewController * __nonnull)viewC;
+
+/**
+ Force a reload of the data.
+ <br>
+ All the current loads will be cancelled, any in flight will be ignored and the loader will ask for a whole new set of data.
+ */
+- (void)reload;
+
+- (void)reloadArea:(MaplyBoundingBox)bound;
+
+- (void)reloadAreas:(NSArray<NSValue*>* __nullable)bounds;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyQuadSampler.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyQuadSampler.h
new file mode 100644
index 0000000..5381a95
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyQuadSampler.h
@@ -0,0 +1,103 @@
+/*
+ * MaplyQuadSampler.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 3/27/18.
+ * Copyright 2011-2022 Saildrone Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyControllerLayer.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+
+/**
+ Sampling parameters.
+
+ These are used to describe how we want to break down the globe or
+ flat projection onto the globe.
+ */
+@interface MaplySamplingParams : NSObject
+
+/// The coordinate system we'll be sampling from.
+@property (nonatomic,nonnull,strong) MaplyCoordinateSystem *coordSys;
+
+/// Min zoom level for sampling. Don't set this to anything other than 0 or 1
+@property (nonatomic) int minZoom;
+
+/// Max zoom level for sampling
+@property (nonatomic) int maxZoom;
+
+/// We may want to calculate zoom levels beyond what we actually load.
+/// Useful for zoom scaled features and enable/disable based on zoome
+@property (nonatomic) int reportedMaxZoom;
+
+/// Maximum number of tiles to load
+@property (nonatomic) int maxTiles;
+
+/// Cutoff for loading tiles. This is size in screen space (pixels^2)
+@property (nonatomic) double minImportance;
+
+/// Normally we always load the lowest level
+/// If this is set we only load those lowest level tiles that pass this test
+/// Must be greater than zero and not equal to minImportance to take effect.
+@property (nonatomic) double minImportanceTop;
+
+/// Generate geometry to cover the north and south poles
+/// Only works for world-wide projections
+@property (nonatomic) bool coverPoles;
+
+/// If set, generate skirt geometry to hide the edges between levels
+@property (nonatomic) bool edgeMatching;
+
+/// Tesselation values per level for breaking down the coordinate system (e.g. globe)
+@property (nonatomic) int tessX,tessY;
+
+/// If set, we'll scale the bounding boxes of individual tiles by this before evaluating
+@property (nonatomic) float boundScale;
+
+/// If set, we'll always load the lowest level first and then whatever the target level is
+/// Turn this off to get true single level loading
+/// `forceMinLevelHeight` must be greater than zero for this to have any effect.
+@property (nonatomic) bool forceMinLevel;
+
+/// If set, we'll turn on forceMinLevel and only use it when the viewer is above this height
+@property (nonatomic) double forceMinLevelHeight;
+
+/// If set, we'll try to load a single level
+@property (nonatomic) bool singleLevel;
+
+/// If set, the tiles are clipped to this boundary
+@property (nonatomic) MaplyBoundingBoxD clipBounds;
+@property (nonatomic,readonly) bool hasClipBounds;
+
+/**
+ Detail the levels you want loaded in target level mode.
+
+ The layer calculates the optimal target level. The entries in this array are relative to that level or absolute. For example [0,-4,-2] means the layer will always try to load levels 0, targetLevel-4 and targetLevel-2, but only the latter two if they make sense.
+ */
+@property (nonatomic,nullable,strong) NSArray *levelLoads;
+
+/**
+ Set the min importance for just one level.
+
+ This is useful if you want your lower levels loaded more aggressively.
+ */
+- (void)setMinImportance:(double)minImportance forLevel:(int)level;
+
+/// Decide if these sampling params are the same as others
+- (bool)isEqualTo:(MaplySamplingParams *__nonnull)other;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyRemoteTileFetcher.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyRemoteTileFetcher.h
new file mode 100644
index 0000000..cc26370
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyRemoteTileFetcher.h
@@ -0,0 +1,288 @@
+/*
+ * MaplyRemoteTileFetcher.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 6/15/18.
+ * Copyright 2011-2022 Saildrone Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+
+/**
+ Remote Tile Info Object (New)
+
+ Not to be confused with the old one, which works with the older loading subsystem,
+ the new remote tile info object contains min/max zoom, coordinate system and URL
+ information for fetching individual data tiles.
+ */
+@interface MaplyRemoteTileInfoNew : NSObject<MaplyTileInfoNew>
+
+/**
+ Initialize with enough information to fetch remote tiles.
+
+ This version of the init method takes all the explicit
+ information needed to fetch remote tiles. This includes the
+ base URL and min and max zoom levels.
+
+ @param baseURL The base URL for fetching TMS tiles. This is a replacement URL with {x}, {y}, and {z} in the string.
+
+ @param minZoom The minimum zoom level to fetch. This really should be 0.
+
+ @param maxZoom The maximum zoom level to fetch.
+
+ @return The MaplyRemoteTileInfoNew object or nil on failure.
+ */
+- (nonnull instancetype)initWithBaseURL:(NSString *__nonnull)baseURL minZoom:(int)minZoom maxZoom:(int)maxZoom;
+
+/// Base URL
+@property (nonatomic,readonly,retain,nonnull) NSString *baseURL;
+
+/// Min zoom level
+@property (nonatomic,readonly,assign) int minZoom;
+
+/// Max zoom level
+@property (nonatomic,readonly,assign) int maxZoom;
+
+/**
+ The timeout assigned to the NSMutableURLRequest we're using to fetch tiles.
+
+ This is not set by default. If set, we'll use this value as the timeout on the NSMutableURLRequest we use for fetching tiles. This lets you extent it where appropriate or shorten it if you like.
+ */
+@property (nonatomic,assign) float timeOut;
+
+/**
+ The cache directory for data tiles.
+
+ In general, we want to cache. The globe, in particular,
+ is going to fetch the same tiles over and over, quite a lot.
+ The cacheing behavior is a little dumb. It will just write
+ files to the given directory forever. If you're interacting
+ with a giant image pyramid, that could be problematic.
+ */
+@property (nonatomic, retain,nullable) NSString *cacheDir;
+
+/**
+ Optional headers to add to the NSURLRequest.
+
+ These are name/data pairs which will be stuck in the NSURLRequest header.
+ */
+@property (nonatomic, retain) NSDictionary * __nullable headers;
+
+/**
+ Optional coordinate system describing the tile set.
+
+ This coordinate system is required if the tile info will need
+ to evaluate valid tiles as defined by the addValidBounds:coordSystem: call.
+ */
+@property (nonatomic, retain) MaplyCoordinateSystem * __nullable coordSys;
+
+/**
+ Add a bounding box that defines validity for any tile before it's fetched.
+
+ Not all data sources cover all possible tiles. If you know your data source does not,
+ you can specify what area is valid ahead of times. Tiles that do not overlap that area
+ will not be loaded.
+ */
+- (void)addValidBounds:(MaplyBoundingBoxD)bbox coordSystem:(MaplyCoordinateSystem * __nonnull)coordSys;
+
+@end
+
+/**
+ Fetch Info for remote tile fetches.
+
+ The URL (required) and cacheFile (optional) for the given fetch.
+ This is the object the RemoteTileFetcher expects for the fetchInfo member of the TileFetchRequest.
+ */
+@interface MaplyRemoteTileFetchInfo : NSObject
+
+/// URL to fetch from
+@property (nonatomic,nonnull,retain) NSURLRequest *urlReq;
+
+/// File name for cached file (if present). Save it here when fetched if set.
+@property (nonatomic,nullable,retain) NSString *cacheFile;
+
+/// If you're using local storage (separate from the cache) this will be passed on to the MaplyTileLocalStorage manager
+@property (nonatomic,nullable,retain) id localStorageKey;
+
+@end
+
+/**
+ If you provide LocalStore the RemoteTileFetcher will look for data in local storage first,
+ then try the local file cache and lastly go to the network.
+
+ You can provide the local storage by filling out this protocol and passing it to the RemoteTileFetcher.
+
+ Expect to be called on a random thread and block appropriately.
+ */
+@protocol MaplyTileLocalStorage <NSObject>
+
+/**
+ Return the data for the given tile. nil means you don't have the tile, so we'll try other sources.
+ fetchInfo is a MaplyRemoteTileFetchInfo describing the rest of the tile characteristics.
+ tileID is the tile in question.
+ */
+- (id __nullable)dataForTile:(MaplyRemoteTileFetchInfo * __nonnull)fetchInfo tileID:(MaplyTileID)tileID;
+
+@end
+
+/**
+ If a tile fetch request fails, this object allows you second chance to provide the data.
+ Maybe you have an old version in a cache somewhere. Provide that. Or fail and
+ the tile fetch will continue to fail.
+ */
+@protocol MaplyTileSecondChance <NSObject>
+
+/**
+ Return data for a tile that's already failed to load from local cache and remote fetch.
+ This might be an old version of the data you have lying around. It's up to you.
+ Returning nil means the fetch fails as normal.
+ */
+- (id __nullable)dataForTile:(MaplyRemoteTileFetchInfo * __nonnull)fetchInfo tileID:(MaplyTileID)tileID;
+
+@end
+
+@class MaplyRemoteTileFetcherStats;
+@class MaplyRemoteTileFetcherLog;
+
+/**
+ Remote Tile fetcher fetches tiles from remote URLs.
+
+ The tile fetcher interacts with loaders that want tiles, as demanded by samplers.
+ It's complicated. There's a default one of these that will get used if you pass in nil to the MaplyQuadImageLoader.
+ */
+@interface MaplyRemoteTileFetcher : NSObject<MaplyTileFetcher>
+
+/// Initialize with the number of connections the fetcher can have open at once
+- (instancetype __nonnull)initWithName:(NSString * __nonnull)name connections:(int)numConnections;
+
+/// Number of outstanding connections in parallel
+@property (nonatomic) int numConnections;
+
+/// Local storage is for pre-downloaded tiles, rather than a cache. This is consulted *before* we go out to the network.
+/// If it fails, then we hit the local file cache and then we hit the network
+- (void)setLocalStorage:(NSObject<MaplyTileLocalStorage> * __nullable)localStorage;
+
+/// After a tile fails to load from local storage, local cache and then a remote request, you have one more chance to provide the data
+/// Useful if you've got an old version of the tile lying around you might use in a pinch
+- (void)setSecondChance:(NSObject<MaplyTileSecondChance> * __nullable)secondChance;
+
+/// Return the fetching stats since the beginning or since the last reset
+- (MaplyRemoteTileFetcherStats * __nullable)getStats:(bool)allTime;
+
+/// Reset the counters for one variant of stat
+- (void)resetStats;
+
+/// Reset just the active counters
+- (void)resetActiveStats;
+
+/// Start logging request (and times and such)
+- (void)startLogging;
+
+/// Stop logging and return the log itself
+- (MaplyRemoteTileFetcherLog * __nullable)stopLogging;
+
+// If set, you get way too much debugging output
+@property (nonatomic,assign) bool debugMode;
+
+@end
+
+/// Stats collected by the fetcher
+@interface MaplyRemoteTileFetcherStats : NSObject
+
+@property (nonatomic,readonly,weak,nullable) MaplyRemoteTileFetcher *fetcher;
+
+// Start of stats collection
+@property (nonatomic,nonnull,strong) NSDate *startDate;
+
+// Total requests, remote and cached
+@property (nonatomic) int totalRequests;
+
+// Requests that resulted in a remote HTTP call
+@property (nonatomic) int remoteRequests;
+
+// Total requests cancelled
+@property (nonatomic) int totalCancels;
+
+// Requests failed
+@property (nonatomic) int totalFails;
+
+// Bytes of remote data loaded
+@property (nonatomic) int remoteData;
+
+// Bytes of cached data loaded
+@property (nonatomic) int localData;
+
+// Total time spent waiting for successful remote data requests
+@property (nonatomic) NSTimeInterval totalLatency;
+
+// The maximum number of requests we've had at once (since the last reset)
+@property (nonatomic) int maxActiveRequests;
+
+// Current number of active requests
+@property (nonatomic) int activeRequests;
+
+// Add the given stats to ours
+- (void)addStats:(MaplyRemoteTileFetcherStats * __nonnull)stats;
+
+// Print out the stats
+- (void)dump;
+
+@end
+
+/**
+ Single entry for the logging. Reports on the status of a specific fetch.
+ */
+@interface MaplyRemoteTileFetcherLogEntry : NSObject
+
+/// URL this is about
+@property (nonatomic,nonnull) NSURLRequest *urlReq;
+
+/// Total size of data
+@property (nonatomic) int size;
+
+/// Did we get it at all?
+@property (nonatomic) bool success;
+
+/// True if it was cached on local storage
+@property (nonatomic) bool wasCached;
+
+/// Time when the request was first presented to the RemotetTileFetcher
+@property (nonatomic) NSTimeInterval queuedTime;
+
+/// Time when the remote request was initiated by the system
+@property (nonatomic) NSTimeInterval startedTime;
+
+/// If successful, when we got the request back
+@property (nonatomic) NSTimeInterval finishedTime;
+
+@end
+
+/// Log of remote fetches, how long they took, their results and so on
+@interface MaplyRemoteTileFetcherLog : NSObject
+
+/// When this log begins
+@property (nonatomic) NSTimeInterval startTime;
+
+/// When the log ends
+@property (nonatomic) NSTimeInterval endTime;
+
+/// Individual log entries sorted by finishedTime (probably)
+- (NSArray<MaplyRemoteTileFetcherLogEntry *> * __nullable)getEntries;
+
+/// Print it all out
+- (NSString * __nonnull)dump;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyRenderController.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyRenderController.h
new file mode 100644
index 0000000..0c7c36d
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyRenderController.h
@@ -0,0 +1,1007 @@
+/*
+ * MaplyRenderController.h
+ * WhirlyGlobeMaplyComponent
+ *
+ * Created by Stephen Gifford on 1/19/18.
+ * Copyright 2012-2022 Saildrone Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyScreenMarker.h>
+#import <WhirlyGlobe/MaplyVectorObject.h>
+#import <WhirlyGlobe/MaplyComponentObject.h>
+#import <WhirlyGlobe/MaplySharedAttributes.h>
+#import <WhirlyGlobe/MaplyLight.h>
+#import <WhirlyGlobe/MaplyShader.h>
+#import <WhirlyGlobe/MaplyTexture.h>
+#import <WhirlyGlobe/MaplyParticleSystem.h>
+#import <WhirlyGlobe/MaplyPoints.h>
+#import <WhirlyGlobe/MaplyCluster.h>
+#import <WhirlyGlobe/MaplyRenderTarget.h>
+#import <WhirlyGlobe/MaplyActiveObject.h>
+#import <WhirlyGlobe/MaplyControllerLayer.h>
+
+@class MaplyRemoteTileFetcher;
+
+/// Where we'd like an add to be executed. If you need immediate feedback,
+/// then be on the main thread and use MaplyThreadCurrent. Any is the default.
+typedef NS_ENUM(NSInteger, MaplyThreadMode) {
+ MaplyThreadCurrent,
+ MaplyThreadAny,
+};
+
+/// The various image formats we support. RGBA is the default, and most expensive.
+typedef NS_ENUM(NSInteger, MaplyQuadImageFormat) {
+ MaplyImageIntRGBA,
+ MaplyImageUShort565,
+ MaplyImageUShort4444,
+ MaplyImageUShort5551,
+ MaplyImageUByteRed,MaplyImageUByteGreen,MaplyImageUByteBlue,MaplyImageUByteAlpha,
+ MaplyImageUByteRG,
+ MaplyImageUByteRGB,
+ MaplyImageETC2RGB8,MaplyImageETC2RGBA8,MaplyImageETC2RGBPA8,
+ MaplyImageEACR11,MaplyImageEACR11S,MaplyImageEACRG11,MaplyImageEACRG11S,
+ MaplyImage4Layer8Bit,
+ // Metal only
+ MaplyImageSingleFloat16,MaplyImageSingleFloat32,MaplyImageDoubleFloat16,MaplyImageDoubleFloat32,MaplyImageQuadFloat16,MaplyImageQuadFloat32,
+ MaplyImageInt16,MaplyImageUInt32,MaplyImageDoubleUInt32,MaplyImageQuadUInt32
+};
+
+/// Wrap values for certain types of textures
+#define MaplyImageWrapNone (0)
+#define MaplyImageWrapX (1<<0)
+#define MaplyImageWrapY (1<<1)
+
+@class MaplyRenderController;
+
+/// The system can set up as either GL or Metal
+typedef NS_ENUM(NSInteger, MaplyRenderType) {
+// MaplyRenderGLES,
+ MaplyRenderMetal,
+ MaplyRenderUnknown
+};
+
+/**
+ Render Controller Protocol defines the methods required of a render controller.
+
+ The view controllers and offscreen renderers implement this protocol.
+ */
+@protocol MaplyRenderControllerProtocol <NSObject>
+
+/**
+ Set the offset for the screen space objects.
+
+ In general you want the screen space objects to appear on top of everything else. There used to be structural versions for this, but now you can mix and match where everything appears. This controls the offset that's used to push screen space objects behind everything else in the list (and thus, on top).
+
+ If you set this to 0, you can control the ordering of everything more precisely.
+ */
+@property (nonatomic,assign) int screenObjectDrawPriorityOffset;
+
+/**
+ Clear all the currently active lights.
+
+ There are a default set of lights, so you'll want to do this before adding your own.
+ */
+- (void)clearLights;
+
+/**
+ Reset the lighting back to its default state at startup.
+
+ This clears out all the lights and adds in the default starting light source.
+ */
+- (void)resetLights;
+
+/**
+ Add the given light to the list of active lights.
+
+ This method will add the given light to our active lights. Most shaders will recognize these lights and do the calculations. If you have a custom shader in place, it may or may not use these.
+
+ Triangle shaders use the lights, but line shaders do not.
+ */
+- (void)addLight:(MaplyLight *__nonnull)light;
+
+/// Remove the given light (assuming it's active) from the list of lights.
+- (void)removeLight:(MaplyLight *__nonnull)light;
+
+/**
+ Set the rendering hints to control how the renderer is configured.
+
+ This is a bit vestigial, but still has a few important uses. The hints should be set right after the init call. Any later and they'll probably be ignored.
+
+ The rendering hints are as follows.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyRenderHintZBuffer|bool|If set, we'll explicitly turn on the Z buffer. Normally it's off until a drawable requests it, allowing us to play neat tricks with overlays. The only time you should be turning this on is if you're doing 3D elevation. The default is off.|
+ |kMaplyRenderHintCulling|bool|If set, we'll use the internal culling logic. Texture and drawable atlases have largely made this pointless. Leave it off unless you have a compelling reason to turn it on.|
+ |kMaplyRendererLightingMode|NSString|This can be set to @"none", in which case we use optimized shaders that do no lighting or "regular". The latter is the default.|
+ */
+- (void)setHints:(NSDictionary *__nonnull)hintsDict;
+
+/**
+ Add a cluster generator for making clustered marker images on demand.
+
+ When the layout system clusters a bunch of markers or labels together, it needs new images to represent the cluster.
+
+ You can provide a custom image for each group of markers by filling in one of these generates and passing it in.
+ */
+- (void)addClusterGenerator:(NSObject <MaplyClusterGenerator> *__nonnull)clusterGen;
+
+/**
+ Add one or more screen markers to the current scene.
+
+ This method will add the given MaplyScreenMaker objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param markers An NSArray of MaplyScreenMarker objects.
+
+ @param desc The desciption dictionary which controls how the markers will be constructed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|The color we'll use for the rectangle that makes up a marker. White by default.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The marker will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The marker will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyDrawPriority|NSNumber|If set, the markers are sorted by this number. Larger numbers will be sorted later.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a marker in when it appears and out when it disappears.|
+ |kMaplyFadeIn|NSNumber|The number of seconds to fade a marker in when it appears. This overrides kMaplyFade.|
+ |kMaplyFadeOut|NSNumber|The number of seconds to fade a marker out when it disappears. This override kMaplyFade.|
+ |kMaplyFadeOutTime|NSNumber|If you want to create an object, just to have it fade out at a specific time, this is what you set.|
+ |kMaplyShader|NSString|If set, this is the name of the MaplyShader to use when rendering the screen markers.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyEnableStart|NSNumber|If set, this controls when the resulting objects will be activated.|
+ |kMaplyEnableEnd|NSNumber|If set, this controls when the resulting objects will be deactivated.|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+ |kMaplyClusterGroup|NSNumber|If set, the screen markers will be clustered together according to the given group ID. Off by default, but 0 is the default cluster.|
+
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addScreenMarkers:(NSArray *__nonnull)markers desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more 3D markers to the current scene.
+
+ This method will add the given MaplyMarker objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param markers An NSArray of MaplyMarker objects.
+
+ @param desc The desciption dictionary which controls how the markers will be constructed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|The color we'll use for the rectangle that makes up a marker. White by default.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The marker will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The marker will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a marker in when it appears and out when it disappears.|
+ |kMaplyFadeIn|NSNumber|The number of seconds to fade a marker in when it appears. This overrides kMaplyFade.|
+ |kMaplyFadeOut|NSNumber|The number of seconds to fade a marker out when it disappears. This override kMaplyFade.|
+ |kMaplyFadeOutTime|NSNumber|If you want to create an object, just to have it fade out at a specific time, this is what you set.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyMarkerDrawPriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's off by default, meaning that the geometry will draw on top of anything (respecting the kMaplyDrawPriority).|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addMarkers:(NSArray *__nonnull)markers desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more screen labels to the current scene.
+
+ This method will add the given MaplyScreenLabel objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param labels An NSArray of MaplyScreenLabel objects.
+
+ @param desc The desciption dictionary which controls how the labels will be constructed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyTextColor|UIColor|Color we'll use for the text. Black by default.|
+ |kMaplyBackgroundColor|UIColor|Color we'll use for the rectangle background. Use clearColor to make this invisible.|
+ |kMaplyFont|UIFont|The font we'll use for the text.|
+ |kMaplyLabelHeight|NSNumber|Height of the text in points.|
+ |kMaplyLabelWidth|NSNumber|Width of the text in points. It's best to set Height and leave this out. That way the width will be calculated by the toolkit.|
+ |kMaplyJustify|NSString|This can be set to @"middle", @"left", or @"right" to justify the text around the location.|
+ |kMaplyTextJustify|NSString|This can be kMaplyTextJustifyRight, kMaplyTextJustifyCenter, or kMaplyTextJustifyLeft|
+ |kMaplyShadowSize|NSNumber|If set, we'll draw a shadow with the kMaplyShadowColor offset by this amount. We recommend using an outline instead.|
+ |kMaplyShadowColor|UIColor|If we're drawing a shadow, this is its color.|
+ |kMaplyTextOutlineSize|NSNumber|If set, we'll draw an outline around the text (really draw it twice). The outline will be this large.|
+ |kMaplyTextOutlineColor|UIColor|If we're drawing an outline, it's in this color.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The label will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The label will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyDrawPriority|NSNumber|If set, the labels are sorted by this number. Larger numbers will be sorted later.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a screen label in when it appears and out when it disappears.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyEnableStart|NSNumber|If set, this controls when the resulting objects will be activated.|
+ |kMaplyEnableEnd|NSNumber|If set, this controls when the resulting objects will be deactivated.|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addScreenLabels:(NSArray *__nonnull)labels desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more 3D labels to the current scene.
+
+ This method will add the given MaplyLabel objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param labels An NSArray of MaplyLabel objects.
+
+ @param desc The desciption dictionary which controls how the labels will be constructed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyTextColor|UIColor|Color we'll use for the text. Black by default.|
+ |kMaplyBackgroundColor|UIColor|Color we'll use for the rectangle background. Use clearColor to make this invisible.|
+ |kMaplyFont|UIFont|The font we'll use for the text.|
+ |kMaplyLabelHeight|NSNumber|Height of the text in display coordinates. For the globe these are based on radius = 1.0.|
+ |kMaplyLabelWidth|NSNumber|Width of the text in display coordinates. It's best to set Height and leave this out. That way the width will be calculated by the toolkit.|
+ |kMaplyJustify|NSString|This can be set to @"middle", @"left", or @"right" to justify the text around the location.|
+ |kMaplyShadowSize|NSNumber|If set, we'll draw a shadow with the kMaplyShadowColor offset by this amount. We recommend using an outline instead.|
+ |kMaplyShadowColor|UIColor|If we're drawing a shadow, this is its color.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The label will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The label will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a label in when it appears and out when it disappears.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyLabelDrawPriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's off by default, meaning that the geometry will draw on top of anything (respecting the kMaplyDrawPriority).|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addLabels:(NSArray *__nonnull)labels desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more vectors to the current scene.
+
+ This method will add the given MaplyVectorObject objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param vectors An NSArray of MaplyVectorObject objects.
+
+ @param desc The desciption dictionary which controls how the vectors will look. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the vector features.|
+ |kMaplyVecWidth|NSNumber|If the geometry is not filled, this is the width of the GL lines.|
+ |kMaplyFilled|NSNumber boolean|If set, the areal geometry will be tesselated, taking holes into account. The resulting triangles will be displayed instead of the vectors.|
+ |kMaplySubdivType|NSString|When present, this requests that the geometry be broken up to follow the globe (really only makes sense there). It can be set to kMaplySubdivGreatCircle or kMaplySubdivSimple which do a great circle subdivision and a simple 3-space subdivision respectively. If the key is missing, we do no subdivision at all.|
+ |kMaplySubdivEpsilon|NSNumber|If there's a kMaplySubdivType set this is the epsilon we'll pass into the subdivision routine. The value is in display coordinates. 0.01 is a reasonable value. Smaller results in more subdivision.|
+ |kMaplyVecTexture|UIImage|If set and the kMaplyFilled attribute is set, we will apply the given texture across any areal features. How the texture is applied can be controlled by kMaplyVecTexScaleX, kMaplyVecTexScaleY, kMaplyVecCenterX, kMaplyVecCenterY, and kMaplyVecTextureProjection|
+ |kMaplyVecTexScaleX,kMaplyVecTexScaleY|NSNumber|These control the scale of the texture application. We'll multiply by these numbers before generating texture coordinates from the vertices.|
+ |kMaplyVecCenterX,kMaplyVecCenterY|NSNumber|These control the center of a texture application. If not set we'll use the areal's centroid. If set, we'll use these instead. They should be in local coordinates (probably geographic radians).|
+ |kMaplyVecTextureProjection|NSString|This controls how a texture is projected onto an areal feature. By default we just use the geographic coordinates and stretch them out. This looks odd for very large features. If you set this to kMaplyProjectionTangentPlane then we'll take the center of the feature, make a tangent plane and then project the coordinates onto that tangent plane to get texture coordinates. This looks nice at the poles. If set to kMaplyProjectionScreen the texture is mapped on after screen space projection around the center of the feature.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a vector in when it appears and out when it disappears.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyVectorDrawPriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's off by default, meaning that the geometry will draw on top of anything (respecting the kMaplyDrawPriority).|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplySelectable|NSNumber boolean|Off by default. When enabled, the vector feature will be selectable by a user.|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addVectors:(NSArray *__nonnull)vectors desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Make a copy of the base object and apply the attributes given for the new version.
+
+ This call makes a cheap copy of the vectors in the given MaplyComponentObject and applies the given description to them. You can use this to make a wider or thinner version of a set of vectors, or change their color, while continuing to draw the originals. Or not, as the case may be.
+
+ This is useful for vector maps where we tend to reuse the same geometry at multiple levels and with different colors and line widths.
+
+ Instancing only works with a handful of visual changes. For instance, you can't make a filled and non-filled version.
+
+ @param baseObj The MaplyComponentObject returned by an addVectors: call. This only works for vectors.
+
+ @param desc The description dictionary with controls how vectors will be displayed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the vector features.|
+ |kMaplyVecWidth|NSNumber|If the geometry is not filled, this is the width of the GL lines.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyVectorDrawPriorityDefault.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)instanceVectors:(MaplyComponentObject *__nonnull)baseObj desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more widened vectors to the current scene.
+
+ Build widened vectors
+
+
+ @param desc The description dictionary which controls how vectors will be displayed. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the features.|
+ |kMaplyVecWidth|NSNumber|If the geometry is not filled, this is the width of the lines.|
+ |kMaplyWideVecCoordType|NSNumber|Vectors can be widened in real coordinates (kMaplyWideVecCoordTypeReal) or screen coordinates (kMaplyWideVecCoordTypeScreen). In the latter case they stay the same size now matter how you zoom.|
+ |kMaplyWideVecJoinType|NSNumber|When lines meet in a join there are several options for representing them. These include kMaplyWideVecMiterJoin, which is a simple miter join and kMaplyWideVecBevelJoin which is a more complicated bevel. See http://www.w3.org/TR/SVG/painting.html#StrokeLinejoinProperty for how these look.|
+ |kMaplyWideVecMiterLimit|NSNumber|When using miter joins you can trigger them at a certain threshold.|
+ |kMaplyWideVecTexRepeatLen|NSNumber|This is the repeat size for a texture applied along the widened line. For kMaplyWideVecCoordTypeScreen this is pixels.|
+ |kMaplyVecTexture|UIImage or MaplyTexture|This the texture to be applied to the widened vector.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The vectors will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyVectorDrawPriorityDefault.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addWideVectors:(NSArray *__nonnull)vectors desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more model instances.
+
+ Each MaplyGeomInstance points to a MaplyGeomModel. All those passed in here will be grouped and processed together.
+
+
+ @param desc The description dictionary which controls how the models are displayed, selected, and so forth.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplySelectable|NSNumber boolean|Off by default. When enabled, the vector feature will be selectable by a user.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addModelInstances:(NSArray *__nonnull)modelInstances desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or raw geometry models.
+
+ Each MaplyGeometryModel holds points and triangles in display space. These are relatively "raw" geometry and are passed to the geometry manager as is.
+
+
+ @param desc The description dictionary which controls how the geometry is displayed, selected, and so forth.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplySelectable|NSNumber boolean|Off by default. When enabled, the vector feature will be selectable by a user.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addGeometry:(NSArray *__nonnull)geom desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more MaplyShape children to the current scene.
+
+ This method will add the given MaplyShape derived objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param shapes An NSArray of MaplyShape derived objects.
+
+ @param desc The desciption dictionary which controls how the shapes will look. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the shape features.|
+ |kMaplyShapeSampleX|NSNumber|Number of samples to use in one direction when converting to polygons.|
+ |kMaplyShapeSampleY|NSNumber|Number of samples to use in the other direction when converting to polygons.|
+ |kMaplyShapeInsideOut|NSNumber boolean|If set to YES, we'll make the spheres inside out and such. Set to NO by default.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The shapes will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The shapes will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a shape in when it appears and out when it disappears.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyVectorShapePriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's on by default, meaning that the geometry can be occluded by things drawn first.|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addShapes:(NSArray *__nonnull)shapes desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more MaplySticker objects to the current scene.
+
+ This method will add the given MaplySticker objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param stickers An NSArray of MaplySticker derived objects.
+
+ @param desc The desciption dictionary which controls how the stickers will look. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the stickers.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The stickers will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The stickers will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a sticker in when it appears and out when it disappears.|
+ |kMaplySampleX|NSNumber|Stickers are broken up along two dimensions to adhere to the globe. By default this is done adaptively. If you want to override it, this is the X dimension for the sticker.|
+ |kMaplySampleY|NSNumber|If you want to override it, this is the Y dimension for the sticker.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyVectorShapePriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's off by default, meaning that it will draw on top of things before it..|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyShader|NSString|If set, this is the name of the MaplyShader to use when rendering the sticker(s).|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addStickers:(NSArray *__nonnull)stickers desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Modify an existing sticker. This only supports changing the active textures.
+
+ This method will change attributes of a sticker that's currently in use. At present that's just the images it's displaying.
+
+ @param compObj The component object representing one or more existing stickers.
+
+ @param desc The description dictionary for changes we're making to the sticker.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyStickerImages|NSARray|The array of images to apply to the sticker. You can reuse old ones or introduce new ones.|
+ */
+- (void)changeSticker:(MaplyComponentObject *__nonnull)compObj desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add one or more MaplyBillboard objects to the current scene.
+
+ This method will add the given MaplyBillboard objects to the current scene. It will use the parameters in the description dictionary and it will do it on the thread specified.
+
+ @param billboards An NSArray of MaplyBillboard objects.
+
+ @param desc The description dictionary that controls how the billboards will look. It takes the following entries.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the billboards.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The billboards will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The billboards will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyBillboardDrawPriorityDefault.|
+ |kMaplyBillboardOrient|NSNumber|Controls the billboard orientation. It's either directly toward the eye with kMaplyBillboardOrientEye or takes the ground into account with kMaplyBillboardOrientGround. Ground is the default.
+
+
+ @param threadMode MaplyThreadAny is preferred and will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread.
+ */
+- (MaplyComponentObject *__nullable)addBillboards:(NSArray *__nonnull)billboards desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add a particle system to the scene.
+
+ This adds a particle system to the scene, but does not kick off any particles.
+
+ @param partSys The particle system to start.
+
+ @param desc Any additional standard parameters (none at present).
+
+ @param threadMode MaplyThreadAny will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread. For particles, it's best to make a separate thread and use MaplyThreadCurrent.
+ */
+- (MaplyComponentObject *__nullable)addParticleSystem:(MaplyParticleSystem *__nonnull)partSys desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Change the render target for a particle system.
+
+ This changes the render target for an existing particle system that's already been created.
+ Can pass in nil, which means the particles are rendered to the screen directly.
+ This change takes place immediately, so call it on the main thread.
+ */
+- (void)changeParticleSystem:(MaplyComponentObject *__nonnull)compObj renderTarget:(MaplyRenderTarget *__nullable)target;
+
+/**
+ Add a batch of particles to the current scene.
+
+ Particles are short term objects, typically very small. We create them in large groups for efficience.
+
+ You'll need to fill out the MaplyParticleSystem initially and then the MaplyParticleBatch to create them.
+
+ @param batch The batch of particles to add to an active particle system.
+
+ @param threadMode MaplyThreadAny will use another thread, thus not blocking the one you're on. MaplyThreadCurrent will make the changes immediately, blocking this thread. For particles, it's best to make a separate thread and use MaplyThreadCurrent.
+ */
+- (void)addParticleBatch:(MaplyParticleBatch *__nonnull)batch mode:(MaplyThreadMode)threadMode;
+
+/**
+ Change the representation of the given vector features.
+
+ This will change how any vector features represented by the compObj look.
+
+ You can change kMaplyColor, kMaplyMinVis, kMaplyMaxVis, and kMaplyDrawPriority.
+
+ This version takes a thread mode.
+ */
+- (void)changeVector:(MaplyComponentObject *__nonnull)compObj desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Adds the MaplyVectorObject's passed in as lofted polygons.
+
+ Lofted polygons are filled polygons draped on top of the globe with height. By using a transparent color, these can be used to represent selection or relative values on the globe (or map).
+
+
+ @param polys An NSArray of MaplyVectorObject.
+
+ @param desc The desciption dictionary which controls how the lofted polys will look. It takes the following entries.
+
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the lofted polygons. A bit of alpha looks good.|
+ |kMaplyLoftedPolyHeight|NSNumber|Height of the top of the lofted polygon in display units. For the globe display units are based on a radius of 1.0.|
+ |kMaplyLoftedPolyBase|NSNumber|If present, we'll start the lofted poly at this height. The height is in globe units, based on a radius of 1.0.|
+ |kMaplyLoftedPolyTop|NSNumber boolean|If on we'll create the geometry for the top. On by default.|
+ |kMaplyLoftedPolySide|NSNumber boolean|If on we'll create geometry for the sides. On by default.|
+ |kMaplyLoftedPolyGridSize|NSNumber|The size of the grid (in degrees) we'll use to chop up the vector features to make them follow the sphere (for a globe).|
+ |kMaplyLoftedPolyOutline|NSNumber boolean|If set to @(YES) this will draw an outline around the top of the lofted poly in lines.|
+ |kMaplyLoftedPolyOutlineBottom|NSNumber boolean|If set to @(YES) this will draw an outline around the bottom of the lofted poly in lines.|
+ |kMaplyLoftedPolyOutlineColor|UIColor|If the outline is one this is the outline's color.|
+ |kMaplyLoftedPolyOutlineWidth|NSNumber|This is the outline's width if it's turned on.|
+ |kMaplyLoftedPolyOutlineDrawPriority|NSNumber|Draw priority of the lines created for the lofted poly outline.|
+ |kMaplyLoftedPolyOutlineSide|NSNumber boolean|If set and we're drawing an outline, this will create lines up the sides.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The lofted polys will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The lofted polys will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a lofted poly in when it appears and out when it disappears.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyLoftedPolysShapePriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's on by default, meaning that it can be occluded by geometry coming before it.|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addLoftedPolys:(NSArray *__nonnull)polys desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add a group of points to the display.
+
+ Adds a group of points all at once. We're assuming you want to draw a lot of points, so you have to group them together into a MaplyPoints.
+
+
+ @param points The points to add to the scene.
+
+ @param desc The desciption dictionary which controls how the points will look. It takes the following entries.
+
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyColor|UIColor|Color we'll use for the lofted polygons. A bit of alpha looks good.|
+ |kMaplyMinVis|NSNumber|This is viewer height above the globe or map. The lofted polys will only be visible if the user is above this height. Off by default.|
+ |kMaplyMaxVis|NSNumber|This is viewer height above the globe or map. The lofted polys will only be visible if the user is below this height. Off by default.|
+ |kMaplyMinViewerDist|NSNumber|Minimum distance from the viewer at which to display object(s).|
+ |kMaplyMaxViewerDist|NSNumber|Maximum distance from the viewer at which to display object(s).|
+ |kMaplyViewableCenterX|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center X coordinate.|
+ |kMaplyViewableCenterY|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Y coordinate.|
+ |kMaplyViewableCenterZ|MaplyCoordinate3dWrapper|When evaulating min/max viewer distance, we'll use this center Z coordinate.|
+ |kMaplyFade|NSNumber|The number of seconds to fade a lofted poly in when it appears and out when it disappears.|
+ |kMaplyDrawPriority|NSNumber|Geometry is sorted by this value before being drawn. This ensures that some objects can come out on top of others. By default this is kMaplyLoftedPolysShapePriorityDefault.|
+ |kMaplyZBufferRead|NSNumber boolean|If set this geometry will respect the z buffer. It's on by default, meaning that it can be occluded by geometry coming before it.|
+ |kMaplyZBufferWrite|NSNumber boolean|If set this geometry will write to the z buffer. That means following geometry that reads the z buffer will be occluded. This is off by default.|
+ |kMaplyEnable|NSNumber boolean|On by default, but if off then the feature exists, but is not turned on. It can be enabled with enableObjects:|
+ |kMaplyUUID|NSString|Unique ID to match up alternate representations of the same element.|
+ |kMaplyRepresentation|NSString|Name of the representation presented by this object.|
+
+ @return Returns a MaplyComponentObject, which can be used to make modifications or delete the objects created.
+ */
+- (MaplyComponentObject *__nullable)addPoints:(NSArray * __nonnull)points desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Represent an image as a MaplyTexture.
+
+ This version of addTexture: allows more precise control over how the texture is represented. It replaces the other addTexture: and addTextureToAtlas calls.
+
+ @param image The UIImage to add as a texture.
+
+ @param desc A description dictionary controlling how the image is converted to a texture and represented in the system.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyTexFormat|NSNumber|The texture format to use for the image. Consult addTexture:imageFormat:wrapFlags:mode: for a list. Default is MaplyImageIntRGBA.|
+ |kMaplyTexMinFilter|NSNumber|Filter to use for minification. This can be kMaplyMinFilterNearest or kMaplyMinFilterLinear. Default is kMaplyMinFilterLinear.|
+ |kMaplyTexMagFilter|NSNumber|Filter to use for magnification. This can be kMaplyMinFilterNearest or kMaplyMinFilterLinear. Default is kMaplyMinFilterLinear.|
+ |kMaplyTexWrapX|NSNumber boolean|Texture wraps in x direction. Off by default.|
+ |kMaplyTexWrapY|NSNumber boolean|Texture wraps in y direction. Off by default.|
+ |kMaplyTexAtlas|NSNumber boolean|If set, the texture goes into an appropriate atlas. If not set, it's a standalone texture (default).|
+
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred.
+ */
+- (MaplyTexture *__nullable)addTexture:(UIImage *__nonnull)image desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)threadMode;
+
+/**
+ Create an empty texture and return it.
+
+ Empty textures are used for offscreen rendering and other crazy stuff. You probably don't want to do this.
+
+ @param spec The description dictionary controlling the format and other textures goodies.
+
+ |Key|Type|Description|
+ |:--|:---|:----------|
+ |kMaplyTexFormat|NSNumber|The texture format to use for the image. Consult addTexture:imageFormat:wrapFlags:mode: for a list. Default is MaplyImageIntRGBA.|
+ |kMaplyTexMinFilter|NSNumber|Filter to use for minification. This can be kMaplyMinFilterNearest or kMaplyMinFilterLinear. Default is kMaplyMinFilterLinear.|
+ |kMaplyTexMagFilter|NSNumber|Filter to use for magnification. This can be kMaplyMinFilterNearest or kMaplyMinFilterLinear. Default is kMaplyMinFilterLinear.|
+ |kMaplyTexWrapX|NSNumber boolean|Texture wraps in x direction. Off by default.|
+ |kMaplyTexWrapY|NSNumber boolean|Texture wraps in y direction. Off by default.|
+ |kMaplyTexAtlas|NSNumber boolean|If set, the texture goes into an appropriate atlas. If not set, it's a standalone texture (default).|
+ |kMaplyTexMipmap|NSNumber boolean|If set, we'll create the given texture with mipmap levels.|
+
+ @param sizeX The horizontal size of the textures (in pixels).
+
+ @param sizeY Vertical size of the texture (in pixels).
+ */
+- (MaplyTexture *__nullable)createTexture:(NSDictionary * _Nullable)spec sizeX:(int)sizeX sizeY:(int)sizeY mode:(MaplyThreadMode)threadMode;
+
+/**
+ Creates a new texture that references part of an existing texture.
+
+ @param x Horizontal offset within the existing texture.
+ @param y Vertical offset within the existing texture.
+ @param width Width of the chunk to make a new texture.
+ @param height Height of the chunk to make a new texture.
+ @param threadMode For MaplyThreadAny we'll do the add on another thread. For MaplyThreadCurrent we'll block the current thread to finish the add. MaplyThreadAny is preferred if you're on the main thread.
+ */
+- (MaplyTexture *__nullable)addSubTexture:(MaplyTexture *__nonnull)tex xOffset:(int)x yOffset:(int)y width:(int)width height:(int)height mode:(MaplyThreadMode)threadMode;
+
+/**
+ Remove the OpenGL ES textures associated with the given MaplyTextures.
+
+ MaplyTextures will remove their associated OpenGL textures when they go out of scope. This method does it expicitly and clears out the internals of the MaplyTexture.
+
+ Only call this if you're managing the texture explicitly and know you're finished with them.
+ */
+- (void)removeTextures:(NSArray *__nonnull)texture mode:(MaplyThreadMode)threadMode;
+
+/**
+ Add a render target to the system
+
+ Sets up a render target and will start rendering to it on the next frame.
+
+ Keep the render target around so you can remove it later.
+ */
+- (void)addRenderTarget:(MaplyRenderTarget * _Nonnull)renderTarget;
+
+/**
+ Set the texture a given render target is writing to.
+
+ Render targets start out with one, but you may wish to change it.
+ */
+- (void)changeRenderTarget:(MaplyRenderTarget * __nonnull)renderTarget tex:(MaplyTexture * __nullable)tex;
+
+/**
+ Remove the given render target from the system.
+
+ Ask the system to stop drawing to the given render target. It will do this on the next frame.
+ */
+- (void)removeRenderTarget:(MaplyRenderTarget * _Nonnull)renderTarget;
+
+/**
+ Set up the the mask render target. We use it to keep one set of features from render on top of another set.
+ */
+- (void)startMaskTarget:(NSNumber * __nullable)scale;
+
+/**
+ Turn off the render target for masks.
+ */
+- (void)stopMaskTarget;
+
+/**
+ Normally the layout layer runs periodically if you change something or when you move around.
+ You can ask it to run ASAP right here. Layout runs on its own thread, so there may still be a delay.
+ */
+- (void)runLayout;
+
+/**
+ Request a one time clear for the render target.
+
+ Rather than clearing every frame, you may want to specifically request a clear. This will
+ be executed at the next frame and then not again.
+*/
+- (void)clearRenderTarget:(MaplyRenderTarget * _Nonnull)renderTarget mode:(MaplyThreadMode)threadMode;
+
+/**
+ Remove all information associated with the given MaplyComponentObject's.
+
+ Every add call returns a MaplyComponentObject. This will remove any visible features, textures, selection data, or anything else associated with it.
+
+ @param theObjs The MaplyComponentObject's we wish to remove.
+
+ @param threadMode For MaplyThreadAny we'll do the removal on another thread. For MaplyThreadCurrent we'll block the current thread to finish the removal. MaplyThreadAny is preferred.
+ */
+- (void)removeObjects:(NSArray *__nonnull)theObjs mode:(MaplyThreadMode)threadMode;
+
+/**
+ Disable a group of MaplyComponentObject's all at once.
+
+ By default all of the geometry created for a given object will appear. If you set kMaplyEnable to @(NO) then it will exist, but not appear. This has the effect of setting kMaplyEnable to @(NO).
+
+ @param theObjs The objects to disable.
+
+ @param threadMode For MaplyThreadAny we'll do the disable on another thread. For MaplyThreadCurrent we'll block the current thread to finish the disable. MaplyThreadAny is preferred.
+ */
+- (void)disableObjects:(NSArray *__nonnull)theObjs mode:(MaplyThreadMode)threadMode;
+
+/**
+ Enable a group of MaplyComponentObject's all at once.
+
+ By default all of the geometry created for a given object will appear. If you set kMaplyEnable to @(NO) then it will exist, but not appear. This has the effect of setting kMaplyEnable to @(YES).
+
+ @param theObjs The objects to enable.
+
+ @param threadMode For MaplyThreadAny we'll do the enable on another thread. For MaplyThreadCurrent we'll block the current thread to finish the enable. MaplyThreadAny is preferred.
+ */
+- (void)enableObjects:(NSArray *__nonnull)theObjs mode:(MaplyThreadMode)threadMode;
+
+/**
+ Set the representation to use for one or more UUIDs
+
+ @param uuids Array of NSString UUIDs to update
+ @param repName The representation name to apply, nil to return to the default
+ @param threadMode For MaplyThreadAny we'll do the enable on another thread. For MaplyThreadCurrent we'll block the current thread to finish the enable. MaplyThreadAny is preferred.
+ */
+- (void)setRepresentation:(NSString *__nullable)repName
+ ofUUIDs:(NSArray<NSString *> *__nonnull)uuids
+ mode:(MaplyThreadMode)threadMode;
+
+/**
+ Set the representation to use for one or more UUIDs
+
+ @param uuids Array of NSString UUIDs to update
+ @param repName The representation name to apply, nil to return to the default
+ @param fallbackRepName The representation to use of no item with `repName` exists.
+ @param threadMode For MaplyThreadAny we'll do the enable on another thread. For MaplyThreadCurrent we'll block the current thread to finish the enable. MaplyThreadAny is preferred.
+ */
+- (void)setRepresentation:(NSString *__nullable)repName
+ fallbackRepName:(NSString *__nullable)fallbackRepName
+ ofUUIDs:(NSArray<NSString *> *__nonnull)uuids
+ mode:(MaplyThreadMode)threadMode;
+
+/**
+ Pass a uniform block through to a shader. Only for Metal.
+
+ Custom Metal shaders may have their own uniform blocks associated with a known bufferID.
+ This is how you pass those through for objects you've already created.
+ Useful for things like custom animation.
+ */
+- (void)setUniformBlock:(NSData *__nonnull)uniBlock buffer:(int)bufferID forObjects:(NSArray<MaplyComponentObject *> *__nonnull)compObjs mode:(MaplyThreadMode)threadMode;
+
+/**
+ Call this to start journaling changes for this thread.
+
+ Your can collect up your add/remove/enable changes on the current thread. Call startChanges to start collecting and endChanges to flush the changes.
+
+ This has no real meaning on the main thread and don't collect too many changes. They take memory.
+ */
+- (void)startChanges;
+
+/**
+ Call this to flush your journal changes out ot the scene.
+
+ This is the other end of startChanges.
+ */
+- (void)endChanges;
+
+/**
+ Add a compiled shader. We'll refer to it by the scene name.
+
+ Once you've create a MaplyShader, you'll need to add it to the scene to use it.
+
+ @param shader The working shader (be sure valid is true) to add to the scene.
+ */
+- (void)addShaderProgram:(MaplyShader *__nonnull)shader;
+
+/**
+ Look for a shader with the given name.
+
+ This is the shader's own name as specified in the init call, not the scene name as might be specified in addShaderProgram:sceneName:
+
+ @return Returns the registered shader if it found one.
+ */
+- (MaplyShader *__nullable)getShaderByName:(NSString *__nonnull)name;
+
+/**
+ Remove a shader that was added earlier.
+ */
+- (void)removeShaderProgram:(MaplyShader *__nonnull)shader;
+
+/**
+ Return the coordinate system being used for the display.
+
+ This returns the local coordinate system, which is used to unroll the earth (for the globe) or via a scaling factor (for the flat map).
+ */
+- (MaplyCoordinateSystem *__nullable)coordSystem;
+
+- (void)setClearColor:(UIColor *__nonnull)clearColor;
+
+/// Return the framebuffer size in pixels (no scale)
+- (CGSize)getFramebufferSize;
+
+// For internal use only
+- (MaplyRenderController * __nullable)getRenderControl;
+
+/// Return the renderer type being used
+- (MaplyRenderType)getRenderType;
+
+/**
+ Add the given active object to the scene.
+
+ Active objects are used for immediate, frame based updates. They're fairly expensive, so be careful. After you create one, you add it to the scene here.
+ */
+- (void)addActiveObject:(MaplyActiveObject *__nonnull)theObj;
+
+/// Remove an active object from the scene.
+- (void)removeActiveObject:(MaplyActiveObject *__nonnull)theObj;
+
+/// Remove an array of active objects from the scene
+- (void)removeActiveObjects:(NSArray *__nonnull)theObjs;
+
+/**
+ Add a MaplyControllerLayer to the globe or map.
+
+ At present, layers are for paged geometry such as image tiles or vector tiles. You can create someting like a MaplyQuadImageTilesLayer, set it up and then hand it to addLayer: to add to the scene.
+ */
+- (bool)addLayer:(MaplyControllerLayer *__nonnull)layer;
+
+/// Remove a MaplyControllerLayer from the globe or map.
+- (void)removeLayer:(MaplyControllerLayer *__nonnull)layer;
+
+/// Remove zero or more MaplyControllerLayer objects from the globe or map.
+- (void)removeLayers:(NSArray *__nonnull)layers;
+
+/// Remove all the user created MaplyControllerLayer objects from the globe or map.
+- (void)removeAllLayers;
+
+/// Return a tile fetcher we may share between loaders
+- (MaplyRemoteTileFetcher * __nullable)addTileFetcher:(NSString * __nonnull)name;
+
+/**
+ If in Metal rendering mode, return the Metal device being used.
+ */
+- (id<MTLDevice> __nullable)getMetalDevice;
+
+/**
+ If in Metal rendering mode, return the shader library set up by the toolkit.
+ */
+- (id<MTLLibrary> __nullable)getMetalLibrary;
+
+/**
+ An explicit teardown. For render controllers you allocate standalone, this is a good idea.
+ */
+- (void)teardown;
+
+@end
+
+/**
+ The Render Controller is a standalone WhirlyGlobe-Maply renderer.
+
+ This Render Controller is used for offline rendering.
+ */
+@interface MaplyRenderController : NSObject<MaplyRenderControllerProtocol>
+
+/// Initialize as an offline renderer of a given target size of the given rendering type
+- (instancetype __nullable)initWithSize:(CGSize)size mode:(MaplyRenderType)renderType;
+
+/// Initialize as an offline renderer of a given target size with default renderer (Metal)
+- (instancetype __nullable)initWithSize:(CGSize)size;
+
+/// If set up in offline mode, this is how we draw
+- (UIImage * __nullable)renderToImage;
+
+/// Return the raw RGBA pixels from the rendered image rather than a UIImage
+- (NSData * __nullable)renderToImageData;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyRenderTarget.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyRenderTarget.h
new file mode 100644
index 0000000..5f6034c
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyRenderTarget.h
@@ -0,0 +1,119 @@
+/*
+ * MaplyRenderTarget.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 1/13/17.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyTexture.h>
+
+typedef NS_ENUM(NSUInteger,MaplyMipmapType) {
+ /// Don't generate a mipmap
+ MaplyMipmapNone,
+ /// Generate a basic mipmap
+ MaplyMipmapAverage,
+ /// Generate a mipmap using Gauss blurring
+ MaplyMipmapGauss
+};
+
+/**
+ Represents a render target (other than the screen)
+
+ Individual objects can ask to be drawn somewhere other than the screen.
+ This is how we do that.
+
+ A render target is just a link between a render every frame and a MaplyTexture. To get at the actual image you use the MaplyTexture.
+
+ At the moment a render target can only draw the full screen, possibly at a lower resolution.
+ */
+@interface MaplyRenderTarget : NSObject
+
+/**
+ The texture we'll draw into.
+
+ This is the texture we'll draw into. Use createTexture to set it up.
+ */
+@property (nonatomic,strong) MaplyTexture *texture;
+
+/**
+ If set, we'll clear the target textures every frame before rendering to it.
+
+ If not set, we won't clear the render target texture between frames.
+
+ True by default.
+ */
+@property (nonatomic) bool clearEveryFrame;
+
+/**
+ If we're generating a mipmap for the attached texture of a render target, this controls
+ how we do it. The default is none.
+ */
+@property (nonatomic) MaplyMipmapType mipmapType;
+
+/**
+ If set, we'll caclulate the min/max for this render target every frame.
+ This is a GPU based calculation for Metal.
+ */
+@property (nonatomic) bool calculateMinMax;
+
+/**
+ Clear the render target to this color every frame.
+
+ Default is clear black.
+ */
+@property (nonatomic,strong) UIColor *clearColor;
+
+
+/**
+ Clear the render target to this value on every frame.
+
+ This is for render targets that are not purely color, such as multiple floats.
+ */
+@property (nonatomic,assign) float clearVal;
+
+/**
+ If set, anything rendered to this render target will blend with what's there.
+
+ If not set, what's rendered will replace what was there before.
+ This is the way it normally works for screen rendering.
+
+ Set to false by default.
+ */
+@property (nonatomic) bool blend;
+
+/**
+ Retrieves a single data value out of the render target. Size is the number of components * size of components.
+ It's best to call this in the snapshot callback. We know the destination isn't being written to at the moment.
+ Metal only.
+ */
+- (NSData *)getValueAtX:(int)x y:(int)y;
+
+/**
+ Returns the whole render target snapshot in the NSData.
+ It's best to call this in the snapshot callback. We know the destination isn't being written to at the moment.
+ Metal only.
+ */
+- (NSData *)getSnapshot;
+
+/**
+ Retreives the min/max data values if those are being calculated.
+ It's best to call this in the snapshot callback. We know the destination isn't being written to at the moment.
+ Metal only.
+ */
+- (NSData *)getMinMaxValues;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyRotateDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyRotateDelegate.h
new file mode 100644
index 0000000..2cb073b
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyRotateDelegate.h
@@ -0,0 +1,29 @@
+/* MaplyRotateDelegate.h
+ * WhirlyGlobeLib
+ *
+ * Created by rghosh0 around 9/26/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+
+@interface MaplyRotateDelegate : NSObject <UIGestureRecognizerDelegate>
+
+//The gesture recognizer
+@property (nonatomic,retain) UIGestureRecognizer* gestureRecognizer;
+
+/// The minimum angle (degrees) that must be subtended before rotation begins
+@property(nonatomic,assign) float rotateThreshold;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyScreenLabel.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyScreenLabel.h
new file mode 100644
index 0000000..f0c00e6
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyScreenLabel.h
@@ -0,0 +1,187 @@
+/*
+ * WGScreenLabel.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 7/24/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+@class MaplyVectorObject;
+
+/// Don't move the label at all
+#define kMaplyLayoutNone (1<<0)
+/// Okay to place centered on point
+#define kMaplyLayoutCenter (1<<1)
+/// Okay to place to the right of a point
+#define kMaplyLayoutRight (1<<2)
+/// Okay to place it to the left of a point
+#define kMaplyLayoutLeft (1<<3)
+/// Okay to place on top of a point
+#define kMaplyLayoutAbove (1<<4)
+/// Okay to place below a point
+#define kMaplyLayoutBelow (1<<5)
+
+/**
+ The Screen Label is a 2D label that tracks a given geographic location.
+
+ This screen label will track the given geographic position. If it's behind the globe it will disappear. The label is rendered in a fixed size and will always appear on top of other geometry.
+ */
+@interface MaplyScreenLabel : NSObject
+
+/**
+ Location of the screen label in geographic (lat/lon) in radians.
+
+ The screen label will track this position. If it would be behind the globe (in globe mode), then it will disappear.
+ */
+@property (nonatomic,assign) MaplyCoordinate loc;
+
+/**
+ An optional rotation to apply to the screen label.
+
+ This is a rotation we'll apply after the screen position has been calculated. You can use this to do things like track the orientation of roads.
+
+ Rotation is in radians counter-clockwise from north.
+ */
+@property (nonatomic,assign) float rotation;
+
+/**
+ When the screen is rotated, try to keep the label upright.
+
+ This tells the layout and display engine to keep the label oriented upright no matter what. In practice this means it will manipulate the rotation by 180 degrees.
+ */
+@property (nonatomic,assign) bool keepUpright;
+
+/**
+ The actual text to display.
+
+ This is a simple NSString for the text. Things like font are set in the NSDictionary passed in to the add call in the view controller.
+ */
+@property (nonatomic,strong) NSString * __nullable text;
+
+/**
+ Text can be accompanied by an optional icon image.
+
+ If set, we'll put this image to the left of the text in the screen label. The UIImage will be tracked by the view controller and reused as needed or disposed of when no longer needed.
+
+ The name had to change because Apple's private selector search is somewhat weak.
+ */
+@property (nonatomic,strong) UIImage * __nullable iconImage2;
+
+/**
+ Icon size in points.
+
+ If there is an icon image, this is how big it is.
+ */
+@property (nonatomic,assign) CGSize iconSize;
+
+/**
+ An optional offset for the whole screen label.
+
+ If set, we'll move the screen label around by this amount before rendering it. These are screen coordinates, not geographic.
+ */
+@property (nonatomic,assign) CGPoint offset;
+
+/**
+ An optional color override.
+
+ If set, this color will override the color passed in with the NSDictionary in the view controller's add method.
+ */
+@property (nonatomic,strong) UIColor * __nullable color;
+
+/**
+ Label selectability. On by default
+
+ If set, this label can be selected by the user. If not set, this screen label will never appear in selection results.
+ */
+@property (nonatomic,assign) bool selectable;
+
+/**
+ The layout importance compared to other features, 0 by default.
+
+ The toolkit has a simple layout engine that runs several times per second. It controls the placement of all participating screen based features, such as MaplyScreenLabel and MaplyScreenMaker objects. This value controls the relative importance of this particular object. By default that importance is 0 so the object must compete with others. Setting it to MAXFLOAT will bypass the layout engine entirely and the object will always appear.
+ */
+@property (nonatomic,assign) float layoutImportance;
+
+/**
+ The placement rules for the layout engine to follow.
+
+ The layout engine isn't the brightest bulb in the string and it needs placement hints. This value tells the engine where we can move the label around. These are bit flags, so OR them together as needed. The default is everything.
+
+|Layout Flag|Meaning|
+|:----------|:------|
+|kMaplyLayoutRight|The layout engine can put this label to the right of the location point.|
+|kMaplyLayoutLeft|The layout engine can put this label to the left of the location point.|
+|kMaplyLayoutAbove|The layout engine may put this label above the location point, centered.|
+|kMaplyLayoutBelow|The layout engine may put this albel below the location point, centered.|
+ */
+@property (nonatomic,assign) int layoutPlacement;
+
+/**
+ The size of the label for layout purposes.
+
+ If layoutImportance is not set to MAXFLOAT, the screen label will get throw into the mix when doing screen layout. With this, you can set the size of the label when considering layout. If you set this to (0,0) the maker will take up no space, but still be considered in the layout.
+ */
+@property (nonatomic,assign) CGSize layoutSize;
+
+/**
+ If this is present, we'll render an ID into the mask layer to be used by other features to mask against.
+ */
+@property (nonatomic,retain,nullable) NSString *maskID;
+
+/**
+ If set, we'll lay out the the text along the given linear or areal feature.
+ Takes the first feature in the vector, if there are multiple.
+ */
+@property (nonatomic,retain,nullable) MaplyVectorObject *layoutVec;
+
+
+/**
+ Used to resolve to resolve labels that show the same thing.
+
+ By default this is nil and not used to resolve conflicts. When you set it to
+ something, such as a string, it will be used to resolve display conflicts.
+ Only one object that has this unique ID (evaluated with isEqualToString:) will be displayed.
+ Importance is evaluated first, so the most important will be placed first.
+ */
+@property (nonatomic,retain,nullable) NSString *uniqueID;
+
+/**
+ User data object for selection
+
+ When the user selects a feature and the developer gets it in their delegate, this is an object they can use to figure out what the screen label means to them.
+ */
+@property (nonatomic,strong) id __nullable userObject;
+
+@end
+
+/**
+ A version of the maply screen label that moves.
+
+ This version of the screen label can move in a limited way over time.
+ */
+@interface MaplyMovingScreenLabel : MaplyScreenLabel
+
+/// The end point for animation
+@property (nonatomic,assign) MaplyCoordinate endLoc;
+
+/// How long it will take the screen label to get to endLoc
+@property (nonatomic,assign) NSTimeInterval duration;
+
+@end
+
+typedef MaplyScreenLabel WGScreenLabel;
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyScreenMarker.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyScreenMarker.h
new file mode 100644
index 0000000..8ed1bab
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyScreenMarker.h
@@ -0,0 +1,168 @@
+/* MaplyScreenMarker.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 7/21/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+@class MaplyVectorObject;
+
+/**
+ The Screen Marker is a 2D object that displays an image on the screen tracking a given location.
+
+ The screen marker will track the given geographic location and display a centered rectangle with the given image. Essentially it's a free floating icon, similar to the MaplyScreenLabel and it will always be drawn on top of other objects. If the location would be behind the globe (in globe mode), the marker will disappear.
+
+ If you're looking for a 3D marker object, that's the MaplyMarker.
+ */
+@interface MaplyScreenMarker : NSObject
+
+/**
+ The location we're tracking for this particular screen marker.
+
+ Locations are in geographic (lon/lat in radians).
+ */
+@property (nonatomic,assign) MaplyCoordinate loc;
+
+/**
+ Screen size in points.
+
+ The marker will always be this size on the screen. The size is specified in pixels.
+ */
+@property (nonatomic,assign) CGSize size;
+
+/**
+ An optional rotation to apply to the screen marker.
+
+ This is a rotation we'll apply after the screen position has been calculated. The angle is in radians counter-clockwise from north.
+ */
+@property (nonatomic,assign) double rotation;
+
+/**
+ Image or texture to use for the marker.
+
+ If set we'll stretch this UIImage (or MaplyTexture) out over the marker rectangle. If not set, the marker will just be a colored rectangle. The view controller tracks this object and will reuse its texture and dispose of it as needed.
+ */
+@property (nonatomic,strong) id __nullable image;
+
+/**
+ Images to display on the sticker.
+
+ If this is set rather than image, we will cycle through these images on the screen marker. It will take period time to cycle through them all.
+ */
+@property (nonatomic,strong) NSArray * __nullable images;
+
+/**
+ The time we'll take to cycle through all the images for the marker.
+
+ If images are passed in, this is the time it will take to cycle through them all. By default this is 5s.
+ */
+@property (nonatomic) double period;
+
+/**
+ Color for this particular marker.
+
+ If set, this the color we'll use for the marker or how we'll tint the image.
+
+ This overrides the color set in the description dictionary.
+ */
+@property (nonatomic,strong) UIColor * __nullable color;
+
+/**
+ The layout importance compared to other features, 0 by default.
+
+ The toolkit has a simple layout engine that runs several times per second. It controls the placement of all participating screen based features, such as MaplyScreenLabel and MaplyScreenMaker objects. This value controls the relative importance of this particular object. By default that importance is 0 so the object must compete with others. Setting it to MAXFLOAT will bypass the layout engine entirely and the object will always appear.
+ */
+@property (nonatomic,assign) float layoutImportance;
+
+/**
+ The size of the marker for layout purposes.
+
+ If layoutImportance is not set to MAXFLOAT, the screen marker will get throw into the mix when doing screen layout. With this, you can set the size of the marker when considering layout. If you set this to (0,0) the maker will take up no space, but still be considered in the layout.
+ */
+@property (nonatomic,assign) CGSize layoutSize;
+
+/**
+ Screen markers are usually grouped together for rendering efficiency. This controls the order of the marker within that grouping.
+ orderBy is less important than drawPriority.
+ Default is 0 and means no ordering.
+ */
+@property (nonatomic,assign) long orderBy;
+
+/**
+ Offset in screen coordinates.
+
+ Set to zero by default, this is the offset we'll apply to a given screen marker before it's drawn. The values are screen points.
+ */
+@property (nonatomic,assign) CGPoint offset;
+
+/**
+ Vertex attributes to apply to this screen marker.
+
+ MaplyVertexAttribute objects are passed all the way to the shader. Read that page for details on what they do.
+
+ The array of vertex attributes provided here will be copied onto all the vertices we create for the shader. This means you can use these to do things for a single billboard in your shader.
+ */
+@property (nonatomic,strong) NSArray * __nullable vertexAttributes;
+
+/**
+ Screen marker selectability. On by default
+
+ If set, this marker can be selected by the user. If not set, this screen marker will never appear in selection results.
+ */
+@property (nonatomic,assign) bool selectable;
+
+/**
+ A unique identifier for the marker that's propagated through the system.
+ */
+@property (nonatomic,retain,nullable) NSString *uniqueID;
+
+/**
+ If this is present, we'll render an ID into the mask layer to be used by other features to mask against.
+ */
+@property (nonatomic,retain,nullable) NSString *maskID;
+
+/**
+ If set, we'll lay out the marker along the given linear or areal feature.
+ Takes the first feature in the vector, if there are multiple.
+ */
+@property (nonatomic,retain,nullable) MaplyVectorObject *layoutVec;
+
+/**
+ User data object for selection
+
+ When the user selects a feature and the developer gets it in their delegate, this is an object they can use to figure out what the screen marker means to them.
+ */
+@property (nonatomic,strong) id __nullable userObject;
+
+@end
+
+/**
+ A version of the maply screen marker that moves.
+
+ This version of the screen marker can move in a limited way over time.
+ */
+@interface MaplyMovingScreenMarker : MaplyScreenMarker
+
+/// The end point for animation
+@property (nonatomic,assign) MaplyCoordinate endLoc;
+
+/// How long it will take the screen marker to get to endLoc
+@property (nonatomic,assign) NSTimeInterval duration;
+
+@end
+
+typedef MaplyScreenMarker WGScreenMarker;
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyScreenObject.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyScreenObject.h
new file mode 100644
index 0000000..4779746
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyScreenObject.h
@@ -0,0 +1,106 @@
+/*
+ * MaplyScreenObject
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 2/28/15
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+
+/**
+ The Maply Screen Object is used to build up a more complex screen object from multiple pieces.
+
+ You can use one or more of these to build up a combination of labels and images that form a single marker, label, or billboard.
+ */
+@interface MaplyScreenObject : NSObject
+
+/**
+ Add a string to the screen object
+
+ @param str The string to add
+
+ @param font The font to use
+
+ @param color The foreground color of the string.
+ */
+- (void)addString:(NSString *)str font:(UIFont *)font color:(UIColor *)color;
+
+/**
+ Add an attributed string to the screen object.
+
+ This adds an annotated string to the screen object. The size will be based on the length of the string and the font.
+ */
+- (void)addAttributedString:(NSAttributedString *)str;
+
+/**
+ Add an image scaled to the given size.
+
+ Adds a UIImage or MaplyTexture object scaled to the given size.
+ */
+- (void)addImage:(id)image color:(UIColor *)color size:(CGSize)size;
+
+/**
+ Add an image scaled to the given size and offset by the given amount.
+
+ The other version of this call centers around (0,0) so this lets you nudge it.
+ */
+- (void)addImage:(id)image color:(UIColor *)color size:(CGSize)size offset:(CGPoint)offset;
+
+/**
+ Calculate and return the current bounding box of the screen object.
+ */
+- (MaplyBoundingBox)getSize;
+
+/**
+ Apply a scale to all the pieces of the screen object.
+ */
+- (void)scaleX:(double)x y:(double)y;
+
+/**
+ Apply a translation to all the pieces of the screen object.
+ */
+- (void)translateX:(double)x y:(double)y;
+
+/**
+ Add the contents of the given screen object to this screen object.
+ */
+- (void)addScreenObject:(MaplyScreenObject *)screenObj;
+
+@end
+
+/**
+ Features missing to replicate ScreenMarker and ScreenLabel.
+ rotation
+ images (for animation)
+ period (for animation)
+ color
+ layoutImportance
+ layoutSize
+ layoutPlacement (right, left, above, below)
+ vertexAttributes
+ keepUpright
+
+ ScreenObjectInstance (new object)
+ location
+ endLoc/duration (moving fields)
+ selectable
+ ScreenObject pointer
+ Selected version ScreenObject pointer
+ uniqueID
+ userObject (for selection)
+ */
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyShader.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyShader.h
new file mode 100644
index 0000000..45e309e
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyShader.h
@@ -0,0 +1,174 @@
+/*
+ * MaplyShader.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 2/7/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+#import <Metal/Metal.h>
+
+@protocol MaplyRenderControllerProtocol;
+@class MaplyTexture;
+
+/**
+ The various types of attributes that can be passed in to shaders.
+ */
+typedef NS_ENUM(NSInteger, MaplyShaderAttrType){
+ MaplyShaderAttrTypeInt,
+ MaplyShaderAttrTypeFloat,
+ MaplyShaderAttrTypeFloat2,
+ MaplyShaderAttrTypeFloat3,
+ MaplyShaderAttrTypeFloat4
+};
+
+/**
+ The shader is a direct interface to OpenGL ES 2.0 shader language.
+
+ You can set your own shader programs in the toolkit! Yeah, that's as complex as it sounds.
+
+ The underyling toolkit makes a distinction between the name of the shader and the scene name. The scene name is used as a way to replace the default shaders we use for triangles and lines. This would let you replace the shaders you're already using with your own. See the addShaderProgram: method in the MaplyBaseViewController.
+
+ You can also add your own shader and hook it up to any features that can call out a specific shader, such as the MaplyQuadImageTilesLayer.
+
+ When writing a new shader, go take a look at DefaultShaderPrograms.mm, particularly the vertexShaderTri and fragmentShaderTri. The documentation here is for the uniforms and attributes the system is going to hook up for you. All of these are optional, but obviously nothing much will happen if you don't use the vertices.
+
+**Uniform Values**
+
+These are uniform values provided to each shader, if requested.
+
+ |uniform|type|description|
+ |:------|:---|:----------|
+ |u_mvpMatrix|mat4| The model/view/projection matrix. Shaders typically run vertices through this. |
+ |u_mvMatrix|mat4| The model/view matrix. Less comonly used. |
+ |u_mvNormalMatrix|mat4| The model/view matrix for normals. A shader typically uses this when we want view dependent lighting. |
+ |u_fade|float| Available in regular drawables, but not yet in big drawables (e.g. atlases). This is intended to fade geometry in and out over time. |
+ |u_interp|float| If we're doing multiple textures, this is how to interpolate them. |
+ |u_numLights|int| The number of active lights to use. |
+ |light[8]|directional_light| A data structure for each active light. See the table below. |
+ |material|material_properties| Material information used to calculate lighting. See the table below. |
+ |u_hasTexture|bool| True if there's a texture available to fetch data from. |
+ |s_baseMapX|sampler2D| s_baseMap0, s_baseMap1 and so forth are references to texture data. |
+
+**Material properties**
+
+These are the fields for the material properties.
+
+|field|type|description|
+|:----|:---|:----------|
+|ambient|vec4| The ambient value for the material. Shaders typically multiply by this value when calculating ambient lighting. |
+|diffuse|vec4| The diffuse value for the material. Shaders typically multiply by this value when calculating diffuse lighting. |
+|specular|vec4| Not currently used. |
+|specular_exponent|float| Not currently used. |
+
+**Light properties**
+
+These are the fields for each individual light.
+
+ |field|type|description|
+ |:----|:---|:----------|
+ |direction|vec3| The light's direction, used in diffuse lighting. |
+ |halfplane|vec3| This would be used in specular lighting. |
+ |ambient|vec4| The ambient value of the light. |
+ |diffuse|vec4| The diffuse value of the light. |
+ |specular|vec4| Not currently used. |
+ |viewdepend|float| If greater than 0.0, the shader should run each normal through the u_mvNormalMatrix. |
+
+**Attributes**
+
+These are the per vertex attributes provided to each vertex shader.
+
+ |field|type|description|
+ |:----|:---|:----------|
+ |a_position|vec3| The position in display space for a vertex. Shaders typically multiply this by u_mvpMatrix. |
+ |a_texCoord0|vec2| If textures are present, this is the texture coordinate for the first one. |
+ |a_texCoord1|vec2| If two textures are present, this is the texture coordinate for the second. |
+ |a_color|vec4| An RGBA color for the vertex. |
+ |a_normal|vec3| A normal in display space. This is used purely for lighting and often run through u_mvNormalMatrix. |
+ |a_elev|float| An optional elevation value provided by the MaplyQuadImageTiles layer. You can use it to do elevation dependent shading. |
+
+ */
+@interface MaplyShader : NSObject
+
+/**
+ Initialize with Metal shader functions tied to a particular view controller. Metal only.
+
+ This initializer just ties the given functions to this MaplyShader. All the real work is
+ done by Metal.
+
+ @param name The name of the shader program. Used for identification and sometimes lookup.
+
+ @param vertexFunc The MTLFunction for vertex processing.
+
+ @param fragFunc The MTLFunction for fragment processing.
+
+ @param baseViewC The view controller where we'll register the new shader.
+
+ @return Returns a shader program if it succeeded. IT may not work, however, so call valid first.
+ */
+- (nullable instancetype)initMetalWithName:(NSString *__nonnull)name vertex:(id<MTLFunction> __nonnull)vertexFunc fragment:(id<MTLFunction> __nullable)fragFunc viewC:(NSObject<MaplyRenderControllerProtocol> *__nonnull)baseViewC;
+
+/**
+ Name of the shader program.
+
+ This is the name passed in to the init call. You can search by this name in some circumstances.
+ */
+@property (nonatomic,strong) NSString * __nullable name;
+
+/**
+ Present a texture to this shader for use. Metal Only.
+
+ For a Metal shader we can pass in zero or more textures starting at WKSTextureEntryLookup (DefaultShadersMTL.h).
+ This index is offset from there. Start at 0.
+ */
+- (void)setTexture:(MaplyTexture * __nonnull)tex forIndex:(int)idx viewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+/**
+ Remove a texture we presented to the Shader ealier. Metal Only.
+
+ The texture itself will not be deleted, just the reference to it in the shader.
+ */
+- (void)removeTexture:(MaplyTexture * __nonnull)tex viewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+/**
+ For Metal shaders we don't set the individual uniform values passed in, we set them all together as a block. These are typically set
+ through the ComponentObject interface, but can be set gobally here.
+
+ Metal Only.
+ */
+- (bool)setUniformBlock:(NSData *__nonnull)uniBlock buffer:(int)bufferID;
+
+/**
+ If set, this program is expecting to be called once for each level of a render target's texture.
+ Essentially, it runs a reduce operation, starting from some source and working its way up to the 1x1 texture at the top.
+ */
+- (void)setReduceMode:(bool)reduceMode;
+
+/**
+ Check if the shader is valid.
+
+ The shader setup can fail in a number of ways. Check this after creating the shader to see if it succeded. If not, look to getError to see why.
+ */
+- (bool)valid;
+
+/**
+ Return the compilation error if there was one.
+
+ Shader construction can fail in a number of interesting ways. Call valid to see if it did fail, and then call this method to see why.
+ */
+- (NSString *__nullable)getError;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyShape.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyShape.h
new file mode 100644
index 0000000..51dc1eb
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyShape.h
@@ -0,0 +1,318 @@
+/*
+ * MaplyShape.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 9/28/12.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyMatrix.h>
+#import <WhirlyGlobe/MaplyTexture.h>
+
+/**
+ Maply Shape is the base class for the actual shape objects.
+
+ The maply shape is just the base class. Look to MaplyShapeCircle, MaplyShapeCylinder, MaplyShapeSphere, MaplyShapeGreatCircle, and MaplyShapeLinear.
+ */
+@interface MaplyShape : NSObject
+
+/**
+ The color of the shape.
+
+ We can set object color in the NSDictionary passed in with the add method. We can also override that here.
+ */
+@property (nonatomic,strong) UIColor * __nullable color;
+
+/**
+ If set, the object is selectable
+
+ The object is selectable if this is set when the object is passed in to an add call. If not set, you'll never see it in selection.
+ */
+@property (nonatomic,assign) bool selectable;
+
+/**
+ User data object for selection
+
+ When the user selects a feature and the developer gets it in their delegate, this is an object they can use to figure out what the shape means to them.
+ */
+@property (nonatomic,strong) id __nullable userObject;
+
+/**
+ If set, this shape is in clip coordinates and will not be transformed.
+
+ Some objects (the rectangle) can be used as overlays in clip coordinates. This is set if that's the case.
+ */
+@property (nonatomic,assign) bool clipCoords;
+
+@end
+
+/**
+ Shows a circle at the given location on the globe or map.
+
+ This object represents a circle at the given geographic location. It needs a radius (in display coordinates) and can optionally have a height above the globe or map.
+ */
+@interface MaplyShapeCircle : MaplyShape
+
+/**
+ Center of the circle in local coordinates.
+
+ This is the center of the circle in geographic.
+ */
+@property (nonatomic,assign) MaplyCoordinate center;
+
+/**
+ Radius of the circle in display units.
+
+ This is the radius of the circle, but not in geographic. It's in display units. Display units for the globe are based on a radius of 1.0. Scale accordingly. For the map, display units typically run from -PI to +PI, depending on the coordinate system.
+ */
+@property (nonatomic,assign) float radius;
+
+/**
+ Offset height above the globe in display units.
+
+ This is the height above the globe for the center of the circle. It's also in display units, like the radius.
+ */
+@property (nonatomic,assign) float height;
+
+@end
+
+typedef MaplyShapeCircle WGShapeCircle;
+
+/**
+ Display a sphere at the given location with the given radius.
+
+ This object represents a sphere at the
+ */
+@interface MaplyShapeSphere : MaplyShape
+
+/**
+ Center of the sphere in local coordinates.
+
+ The x and y coordinates correspond to longitude and latitude and are in geographic (radians). The Z value is in display coordinates. For that globe that's based on a radius of 1.0. Scale accordingly.
+ */
+@property (nonatomic,assign) MaplyCoordinate center;
+
+/**
+ Radius of the sphere in display units.
+
+ This is the radius of the sphere, but not in geographic. It's in display units. Display units for the globe are based on a radius of 1.0. Scale accordingly. For the map, display units typically run from -PI to +PI, depending on the coordinate system.
+ */
+@property (nonatomic,assign) float radius;
+
+/**
+ Offset height above the globe in display units.
+
+ This is the height above the globe for the center of the sphere. It's also in display units, like the radius.
+ */
+@property (nonatomic,assign) float height;
+
+@end
+
+typedef MaplyShapeSphere WGShapeSphere;
+
+/**
+ Represent a cyclinder on the globe or map.
+
+ This object represents a cylinder with it's base tied to the surface of the globe or map and it's top pointed outward (on the globe anyway). The base can be offset and the overall radius and height are adjustable.
+ */
+@interface MaplyShapeCylinder : MaplyShape
+
+/**
+ Center of the cylinder's base in geographic.
+
+ The x and y coordinates correspond to longitude and latitude and are in geographic (radians).
+ */
+@property (nonatomic,assign) MaplyCoordinate baseCenter;
+
+/**
+ Base height above the globe in display units.
+
+ This is an optional base offset from the globe or map. The cylinder will be offset by this amount. It's also in display units, like the radius.
+ */
+@property (nonatomic,assign) float baseHeight;
+
+/**
+ Radius of the cylinder in display units.
+
+ This is the radius of the cylinder, but not in geographic. It's in display units. Display units for the globe are based on a radius of 1.0. Scale accordingly. For the map, display units typically run from -PI to +PI, depending on the coordinate system.
+ */
+@property (nonatomic,assign) float radius;
+
+/**
+ Height of the cylinder in display units.
+
+ This is the height of the cylinder. The top of the cylinder will be at baseHeight+height. It's also in display units, like the radius.
+ */
+@property (nonatomic,assign) float height;
+
+@end
+
+typedef MaplyShapeCylinder WGShapeCylinder;
+
+/**
+ Represents an great circle or great circle with height.
+
+ Great circles are the shortest distance between two points on a globe. We extend that a bit here, by adding height. The result is a curved object that can either sit on top of the globe or rise above it. In either case it begins and ends at the specified points on the globe.
+ */
+@interface MaplyShapeGreatCircle : MaplyShape
+
+/// Starting point in geographic coordinates.
+@property (nonatomic,assign) MaplyCoordinate startPt;
+
+/// End point in geographic coordinates
+@property (nonatomic,assign) MaplyCoordinate endPt;
+
+/**
+ Height of the great circle shape right in its middle.
+
+ This is the height of the great circle right in the middle. It will built toward that height and then go back down as it reaches the endPt. The height is in display units. For the globe that's based on a radius of 1.0.
+ */
+@property (nonatomic,assign) float height;
+
+/**
+ Line width for the great circle geometry.
+
+ The great circle is implemented as a set of lines. This is the width, in pixels, of those lines.
+ */
+@property (nonatomic,assign) float lineWidth;
+
+/**
+ Angle between start and end points in radians
+ */
+- (float)calcAngleBetween;
+
+@end
+
+/**
+ Represents a simple rectangle in 3D.
+
+ The rectangle is a 2D object in 3D. Specify the lower left and upper right coordinates as
+ well as an optional texture.
+ */
+@interface MaplyShapeRectangle : MaplyShape
+
+/// Lower left corner in 3D
+@property (nonatomic,assign) MaplyCoordinate3dD ll;
+
+/// Upper right corner in 3D
+@property (nonatomic,assign) MaplyCoordinate3dD ur;
+
+/// If set, the textures to stretch across the rectangle.
+@property (nonatomic,nullable,strong) NSMutableArray *textures;
+
+/// Add a texture to stretch across the rectangle
+- (void)addTexture:(MaplyTexture * __nonnull)texture;
+
+@end
+
+/**
+ A linear feature offset from the globe.
+
+ The main difference between this object and a regular MaplyVectorObject is that you specify coordiantes in 3D. You can use this to create linear features that are offset from the globe.
+ */
+@interface MaplyShapeLinear : MaplyShape
+
+/**
+ Line width in pixels
+
+ The linear is implemented as a set of line segments in OpenGL ES. This is their line width in pixels.
+ */
+@property (nonatomic,assign) float lineWidth;
+
+/**
+ Initialize with coordinates and coordinate array size
+
+ This initializer will make a copy of the coordinates and use them to draw the lines. The x and y values are in geographic. The z values are offsets from the globe (or map) and are in display units. For the globe display units are based on a radius of 1.0.
+ */
+- (nullable instancetype)initWithCoords:(MaplyCoordinate3d * __nonnull)coords numCoords:(int)numCoords;
+
+/**
+ Return the coordinates for this linear feature.
+
+ @return Returns the number of coordinates and a pointer to the coordinate array.
+ */
+- (int)getCoords:(MaplyCoordinate3d *__nullable *__nonnull)retCoords;
+
+@end
+
+/**
+ An extruded shape with an arbitrary outline.
+
+ This object represents an extruded shape with the given thickness. It can be oriented according to the pitch, roll, yaw and height.
+ */
+@interface MaplyShapeExtruded : MaplyShape
+
+/**
+ Construct with the coordinates for the outline to extrude.
+
+ Pass in pairs of doubles that correspond to the
+ */
+- (nonnull instancetype)initWithOutline:(NSArray * __nonnull)coords;
+
+/**
+ Construct with the coordinates for the outline to extrude.
+
+ Pass in pairs of doubles that correspond to the
+ */
+- (nonnull instancetype)initWithOutline:(double * __nonnull)coords numCoordPairs:(int)numCoordPairs;
+
+/**
+ Number of coordinate pairs in this shape.
+ */
+@property (nonatomic,readonly) int numCoordPairs;
+
+/**
+ Array of coordinate values.
+ */
+@property (nonatomic,readonly) double * __nullable coordData;
+
+/**
+ Where we'd like to place the extruded shape.
+
+ This is the center of the object in geographic radians.
+ */
+@property (nonatomic) MaplyCoordinate center;
+
+/**
+ Scale for coordinates. Set to 1/EarthRadiusInMeters by default.
+
+ The coordinates will be scaled by this before creating the geometry. By default this is set to 1/EarthRadius(m) so you can build your shape in meters. Also applies to thickness and height.
+ */
+@property (nonatomic,assign) double scale;
+
+/**
+ Thickness for the resulting shape.
+
+ We build an extruded shape out of this information and this is its thickness. If this is zero, you just get a double sided polygon.
+ */
+@property (nonatomic,assign) double thickness;
+
+/**
+ Height to place the resulting shape at.
+
+ We'll put this shape at the given height above the surface of the globe or map.
+ */
+@property (nonatomic,assign) double height;
+
+/**
+ The transform to apply to this shape.
+
+ If set, this transform is applied before placing the feature. You can set a transform matrix up with roll, pitch, and yaw.
+ */
+@property (nonatomic,strong) MaplyMatrix * __nullable transform;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplySharedAttributes.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplySharedAttributes.h
new file mode 100644
index 0000000..00bd24d
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplySharedAttributes.h
@@ -0,0 +1,406 @@
+/*
+ * MaplySharedAttributes.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 9/19/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+/// Use this hint to turn the zbuffer on or off. Pass in an NSNumber boolean. Takes effect on the next frame.
+extern NSString* const kMaplyRenderHintZBuffer;
+#define kWGRenderHintZBuffer kMaplyRenderHintZBuffer
+/// Use this hint to turn culling optimization on or off. Pass in an NSNumber boolean.
+extern NSString* const kMaplyRenderHintCulling;
+#define kWGRenderHintCulling kMaplyRenderHintCulling
+/// These are options for lighting modes, basically different default shader programs. Only works with OpenGL ES 2.0 mode.
+/// Accepted values are: none,regular
+extern NSString* const kMaplyRendererLightingMode;
+#define kWGRendererLightingMode kMaplyRendererLightingMode
+
+/// These are used for all object descriptions.
+
+/// If the z buffer is on, this will let you resolve. Takes an NSNumber boolean
+extern NSString* const kMaplyDrawOffset;
+#define kWGDrawOffset kMaplyDrawOffset
+/// This helps decide what order things are drawn in. Useful when the z buffer is off or you're using transparency.
+/// Takes an NSNumber int.
+extern NSString* const kMaplyDrawPriority;
+#define kWGDrawPriority kMaplyDrawPriority
+/// Minimum point at which a feature is visible. Takes an NSNumber float. The radius of the globe is 1.0
+extern NSString* const kMaplyMinVis;
+#define kWGMinVis kMaplyMinVis
+/// Maximum point at which a feature is visible. Takes an NSNumber float. The radius of the globe is 1.0
+extern NSString* const kMaplyMaxVis;
+#define kWGMaxVis kMaplyMaxVis
+/// Minimum distance from the viewer at which to display geometry.
+extern NSString* const kMaplyViewerMinDist;
+/// Maximum distance from the viewer at which to display geometry.
+extern NSString* const kMaplyViewerMaxDist;
+/// Center to use when evaluating distance to viewable geometry (X)
+extern NSString* const kMaplyViewableCenterX;
+/// Center to use when evaluating distance to viewable geometry (Y)
+extern NSString* const kMaplyViewableCenterY;
+/// Center to use when evaluating distance to viewable geometry (Z)
+extern NSString* const kMaplyViewableCenterZ;
+/// The amount of time for a feature to fade in or out. Takes an NSNumber float for seconds.
+extern NSString* const kMaplyFade;
+#define kWGFade kMaplyFade
+/// Fade the feature in over time.
+extern NSString* const kMaplyFadeIn;
+/// Fade the feature out over time
+extern NSString* const kMaplyFadeOut;
+/// When to start fading out
+extern NSString* const kMaplyFadeOutTime;
+/// Enable or disable an object. This can be used to create an object disabled.
+extern NSString* const kMaplyEnable;
+/// If set, we'll enable the objects only between the start and end time
+extern NSString* const kMaplyEnableStart;
+/// If set, we'll enable the objects only between the start and end time
+extern NSString* const kMaplyEnableEnd;
+/// Request a given object take the z buffer into account
+extern NSString* const kMaplyZBufferRead;
+/// Have a given object write itself to the z buffer
+extern NSString* const kMaplyZBufferWrite;
+/// Set the render target if the given geometry type supports it
+extern NSString* const kMaplyRenderTarget;
+/// The the UUID of the object
+extern NSString* const kMaplyUUID;
+/// The representation of the UUID this object embodies
+extern NSString* const kMaplyRepresentation;
+
+/// Assign a shader program to a particular feature. Use the shader program's name
+extern NSString* const kMaplyShader;
+/// An NSDictionary containing uniforms to apply to a shader before drawing
+extern NSString* const kMaplyShaderUniforms;
+
+/// Keep drawing for this number of frames after we'd normally stop
+extern NSString* const kMaplyExtraFrames;
+
+/// Stars, moon, stars, atmosphere
+extern const int kMaplyStarsDrawPriorityDefault;
+extern const int kMaplySunDrawPriorityDefault;
+extern const int kMaplyMoonDrawPriorityDefault;
+extern const int kMaplyAtmosphereDrawPriorityDefault;
+/// Where we start image layer draw priorities
+extern const int kMaplyImageLayerDrawPriorityDefault;
+/// We'll start filling in features right around here
+extern const int kMaplyFeatureDrawPriorityBase;
+extern const int kMaplyStickerDrawPriorityDefault;
+extern const int kMaplyMarkerDrawPriorityDefault;
+extern const int kMaplyVectorDrawPriorityDefault;
+extern const int kMaplyParticleSystemDrawPriorityDefault ;
+extern const int kMaplyLabelDrawPriorityDefault;
+extern const int kMaplyLoftedPolysDrawPriorityDefault;
+extern const int kMaplyShapeDrawPriorityDefault;
+extern const int kMaplyBillboardDrawPriorityDefault;
+extern const int kMaplyModelDrawPriorityDefault;
+extern const int kMaplyMaxDrawPriorityDefault;
+
+#define kWGMarkerDrawPriorityDefault kMaplyMarkerDrawPriorityDefault
+#define kWGVectorDrawPriorityDefault kMaplyVectorDrawPriorityDefault
+#define kWGStickerDrawPriorityDefault kMaplyStickerDrawPriorityDefault
+
+/// These are used just for the screen and regular labels
+
+/// Color of the text being rendered. Takes a UIColor.
+extern NSString* const kMaplyTextColor;
+#define kWGTextColor kMaplyTextColor
+/// Background color for the text. Takes a UIColor.
+extern NSString* const kMaplyBackgroundColor;
+#define kWGBackgroundColor kMaplyBackgroundColor
+/// Font to use in rendering text. Takes a UIFont.
+extern NSString* const kMaplyFont;
+#define kWGFont kMaplyFont
+/// Default height of the text. If for screen space, this in points. If for 3D, remember that
+// the radius of the globe is 1.0. Expects an NSNumber float.
+extern NSString* const kMaplyLabelHeight;
+#define kWGLabelHeight kMaplyLabelHeight
+/// Default width of the text. See height for more info and, in general, use height instead.
+extern NSString* const kMaplyLabelWidth;
+#define kWGLabelWidth kMaplyLabelWidth
+/// Justification for label placement. This takes an NSString with one of:
+/// middle, left, right
+extern NSString* const kMaplyJustify;
+#define kWGJustify kMaplyJustify
+/// If set, we'll draw a shadow behind each label with this as the stroke size
+extern NSString* const kMaplyShadowSize;
+#define kWGShadowSize kMaplyShadowSize
+/// If shadow size is being used, we can control the shadow color like so
+extern NSString* const kMaplyShadowColor;
+#define kWGShadowColor kMaplyShadowColor
+/// If outline is being used, we can control the color
+extern NSString* const kMaplyTextOutlineSize;
+/// Vertical line spacing. Defaults to the Font's line spacing
+extern NSString* const kMaplyTextLineSpacing;
+/// If outline is being used, we can control the stroke size
+extern NSString* const kMaplyTextOutlineColor;
+/// When creating textures, we may pass in the size
+extern NSString* const kMaplyTexSizeX;
+/// When creating textures, we may pass in the size
+extern NSString* const kMaplyTexSizeY;
+
+/// How to justify multi-line text
+extern NSString* const kMaplyTextJustify;
+/// Justify text to the right
+extern NSString* const kMaplyTextJustifyRight;
+/// Justify text to the left
+extern NSString* const kMaplyTextJustifyLeft;
+/// Justify text to the center
+extern NSString* const kMaplyTextJustifyCenter;
+
+/// Controls how text is laid out along a line or polygon. Set a number (- for left or inside, + for right or outside)
+extern NSString* const kMaplyTextLayoutOffset;
+/// If laying out along a line (or polygon), the amount of screen space to leave between labels
+extern NSString* const kMaplyTextLayoutSpacing;
+/// Layout as many labels as possible along a line (or polygon). Set a number (0 for no repeat, -1 for as many as possible, or a number of instances)
+extern NSString* const kMaplyTextLayoutRepeat;
+/// Turn on debugging lines for the layout engine
+extern NSString* const kMaplyTextLayoutDebug;
+
+/// These are used for screen and regular markers.
+extern NSString* const kMaplyClusterGroup;
+
+/// Color is used for the polygon generated for a marker. It will combine with the image,
+/// if there is one or it will be visible if there is no texture. Takes a UIColor
+extern NSString* const kMaplyColor;
+#define kWGColor kMaplyColor
+
+/// Width is used by the vector layer for line widths
+extern NSString* const kMaplyVecWidth;
+#define kWGVecWidth kMaplyVecWidth
+
+/// If filled is set, we draw the areals as filled polygons
+extern NSString* const kMaplyFilled;
+#define kWGFilled kMaplyFilled
+
+/// If set, the texture to apply to the feature
+extern NSString* const kMaplyVecTexture;
+/// The format of the image given by kMaplyVecTexture, default MaplyImage4Layer8Bit
+extern NSString* const kMaplyVecTextureFormat;
+/// X scale for textures applied to vectors
+extern NSString* const kMaplyVecTexScaleX;
+/// Y scale for textures applied to vectors
+extern NSString* const kMaplyVecTexScaleY;
+
+/// The projection to use when generating texture coordinates
+extern NSString* const kMaplyVecTextureProjection;
+/// Tangent plane projection for texture coordinates
+extern NSString* const kMaplyProjectionTangentPlane;
+/// Screen space "projection" for texture coordinates
+extern NSString* const kMaplyProjectionScreen;
+/// No projection for texture coordinates
+extern NSString* const kMaplyProjectionNone;
+
+/// If set to true we'll centered any drawables we create for features
+/// This fixes the jittering problem when zoomed in close
+extern NSString* const kMaplyVecCentered;
+
+/// Center of the feature, to use for texture calculations
+extern NSString* const kMaplyVecCenterX;
+extern NSString* const kMaplyVecCenterY;
+
+/// For wide vectors, we can widen them in screen space or display space
+extern NSString* const kMaplyWideVecCoordType;
+
+/// Widened vectors are widened in real space. The width is in meters.
+extern NSString* const kMaplyWideVecCoordTypeReal;
+/// Widened vectors are widened in screen space. The width is in pixels.
+extern NSString* const kMaplyWideVecCoordTypeScreen;
+
+/// Controls the wide vector implementation. Basic implementation by default.
+extern NSString* const kMaplyWideVecImpl;
+
+/// Default/old implementation of the wide vectors
+extern NSString* const kMaplyWideVecImplDefault;
+
+/// Performance implementation of the wide vectors
+extern NSString* const kMaplyWideVecImplPerf;
+
+/// For wide vectors we can control the line joins
+/// See: http://www.w3.org/TR/SVG/painting.html#StrokeLinejoinProperty
+extern NSString* const kMaplyWideVecJoinType;
+
+/// Widened vectors are joined with miters
+extern NSString* const kMaplyWideVecMiterJoin;
+// Note: Not yet implemented
+/// Widened vectors are joined with a curve
+//extern NSString* const kMaplyWideVecRoundJoin @"round"
+/// Widened vectors are joined with a bevel
+extern NSString* const kMaplyWideVecBevelJoin;
+
+/// Number of pixels to use in blending the edges of the wide vectors
+extern NSString* const kMaplyWideVecEdgeFalloff;
+
+/// For wide vectors we can control the ends
+/// See: http://www.w3.org/TR/SVG/painting.html#StrokeLinecapProperty
+//extern NSString* const kMaplyWideVecLineCapType @"wideveclinecaptype"
+
+// Note: These are not currently implemented
+
+/// Widened vector ends are flush
+//extern NSString* const kMaplyWideVecButtCap;
+/// Widened vector ends are round (e.g. hot dog roads)
+//extern NSString* const kMaplyWideVecRoundCap;
+/// Widened vector ends are extended a bit and then flush
+//extern NSString* const kMaplyWideVecSquareCap;
+
+/// Miter joins will turn to bevel joins past this number of degrees
+extern NSString* const kMaplyWideVecMiterLimit;
+
+/// This is the length you'd like the texture to start repeating after.
+/// It's real world coordinates for kMaplyWideVecCoordTypeReal and pixel size for kMaplyWideVecCoordTypeScreen
+extern NSString* const kMaplyWideVecTexRepeatLen;
+
+/// Offset to left (negative) or right (positive) of the centerline
+extern NSString* const kMaplyWideVecOffset;
+
+/// Close any un-closed areal features when drawing lines for them
+extern NSString* const kMaplyVecCloseAreals;
+
+/// If set we'll break up a vector feature to the given epsilon on a globe surface
+extern NSString* const kMaplySubdivEpsilon;
+/// If subdiv epsilon is set we'll look for a subdivision type. Default is simple.
+extern NSString* const kMaplySubdivType;
+/// Subdivide the vector edges along a great circle
+extern NSString* const kMaplySubdivGreatCircle;
+/// Subdivide the vector edges along a great circle with ellipsoidal math
+extern NSString* const kMaplySubdivGreatCirclePrecise;
+/// Subdivide into a fixed number of segmenets
+extern NSString* const kMaplySubdivStatic;
+/// Subdivide the vectors edges along lat/lon
+extern NSString* const kMaplySubdivSimple;
+/// Clip features along a grid of the given size
+extern NSString* const kMaplySubdivGrid;
+/// Used to turn off selection in vectors
+extern NSString* const kMaplySelectable;
+
+/// These are used for stickers
+
+/// Sampling size along one dimension
+extern NSString* const kMaplySampleX;
+#define kWGSampleX kMaplySampleX
+/// Sampling size along one dimension
+extern NSString* const kMaplySampleY;
+#define kWGSampleY kMaplySampleY
+/// Images to use when changing a sticker
+extern NSString* const kMaplyStickerImages;
+/// Image format to use for the new images
+extern NSString* const kMaplyStickerImageFormat;
+
+/// These are used for billboards
+
+/// Billboard orientation
+extern NSString* const kMaplyBillboardOrient;
+/// Billboards are oriented toward the eye, but rotate on the ground
+extern NSString* const kMaplyBillboardOrientGround;
+/// Billboards are oriented only towards the eye
+extern NSString* const kMaplyBillboardOrientEye;
+
+/// These are used for lofted polygons
+
+/// Height above the ground
+extern NSString* const kMaplyLoftedPolyHeight;
+/// Boolean that turns on/off top (on by default)
+extern NSString* const kMaplyLoftedPolyTop;
+/// Boolean that turns on/off sides (on by default)
+extern NSString* const kMaplyLoftedPolySide;
+/// If present, we'll start the lofted poly above 0 height
+extern NSString* const kMaplyLoftedPolyBase;
+/// Grid size we used to chop the lofted polygons up (10 degress by default)
+extern NSString* const kMaplyLoftedPolyGridSize;
+/// If set to @(YES) this will draw an outline around the top of the lofted poly in lines
+extern NSString* const kMaplyLoftedPolyOutline;
+/// If set to @(YES) this will draw an outline around the bottom of the lofted poly in lines
+extern NSString* const kMaplyLoftedPolyOutlineBottom;
+/// If the outline is one this is the outline's color
+extern NSString* const kMaplyLoftedPolyOutlineColor;
+/// This is the outline's width if it's turned on
+extern NSString* const kMaplyLoftedPolyOutlineWidth;
+/// Draw priority of the lines created for the lofted poly outline
+extern NSString* const kMaplyLoftedPolyOutlineDrawPriority;
+/// If set and we're drawing an outline, this will create lines up the sides
+extern NSString* const kMaplyLoftedPolyOutlineSide;
+
+/// These are used for shapes
+
+/// Samples (x) to use when converting shape to polygons
+extern NSString* const kMaplyShapeSampleX;
+/// Samples (y) to use when converting shape to polygons
+extern NSString* const kMaplyShapeSampleY;
+/// If set to true, we'll tessellate a shape using the opposite vertex ordering
+extern NSString* const kMaplyShapeInsideOut;
+/// Center for the shape geometry
+extern NSString* const kMaplyShapeCenterX;
+extern NSString* const kMaplyShapeCenterY;
+extern NSString* const kMaplyShapeCenterZ;
+
+/// These are used by active vector objects
+extern NSString* const kMaplyVecHeight;
+extern NSString* const kMaplyVecMinSample;
+
+/// These are used by the particle systems
+extern NSString* const kMaplyPointSize;
+extern const float kMaplyPointSizeDefault;
+
+/// These are used by the texture
+extern NSString* const kMaplyTexFormat;
+extern NSString* const kMaplyTexMinFilter;
+extern NSString* const kMaplyTexMagFilter;
+extern NSString* const kMaplyMinFilterNearest;
+extern NSString* const kMaplyMinFilterLinear;
+extern NSString* const kMaplyTexAtlas;
+extern NSString* const kMaplyTexWrapX;
+extern NSString* const kMaplyTexWrapY;
+extern NSString* const kMaplyTexMipmap;
+
+/// These are the various shader programs we set up by default
+extern NSString* const kMaplyShaderDefaultTri;
+extern NSString* const kMaplyDefaultTriangleShader;
+extern NSString* const kMaplyShaderTriExp;
+
+extern NSString* const kMaplyShaderDefaultModelTri;
+
+extern NSString* const kMaplyShaderDefaultTriNoLighting;
+extern NSString* const kMaplyNoLightTriangleShader;
+extern NSString* const kMaplyShaderNoLightTriangleExp;
+extern NSString* const kMaplyShaderDefaultMarker;
+
+extern NSString* const kMaplyShaderDefaultTriScreenTex;
+
+extern NSString* const kMaplyShaderDefaultTriMultiTex;
+extern NSString* const kMaplyShaderDefaultTriMultiTexRamp;
+extern NSString* const kMaplyShaderDefaultTriNightDay;
+
+extern NSString* const kMaplyShaderDefaultLine;
+extern NSString* const kMaplyDefaultLineShader;
+
+extern NSString* const kMaplyShaderDefaultLineNoBackface;
+extern NSString* const kMaplyNoBackfaceLineShader;
+
+extern NSString* const kMaplyShaderBillboardGround;
+extern NSString* const kMaplyShaderBillboardEye;
+
+extern NSString* const kMaplyShaderDefaultWideVector;
+extern NSString* const kMaplyShaderWideVectorPerformance;
+extern NSString* const kMaplyShaderWideVectorExp;
+
+extern NSString* const kMaplyScreenSpaceDefaultMotionProgram;
+extern NSString* const kMaplyScreenSpaceDefaultProgram;
+extern NSString* const kMaplyScreenSpaceMaskProgram;
+extern NSString* const kMaplyScreenSpaceExpProgram;
+
+extern NSString* const kMaplyShaderParticleSystemPointDefault;
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplySimpleTileFetcher.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplySimpleTileFetcher.h
new file mode 100644
index 0000000..78307c2
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplySimpleTileFetcher.h
@@ -0,0 +1,88 @@
+/*
+ * MaplySimpleTileFetcher.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 5/31/19.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+
+/** Simple Tile Fetcher is meant for sub classing.
+
+ Some data sources aren't all that complex. You read from a local source,
+ you return the data. Something else turns it into visible objects. Simple.
+
+ To implement one of those, subclass the Simple Tile Fetcher and let it do the
+ tricky bits.
+ */
+@interface MaplySimpleTileFetcher : NSObject<MaplyTileFetcher>
+
+/// Your Subclass must call this init method
+- (nullable instancetype)initWithName:(NSString * __nonnull)name minZoom:(int)minZoom maxZoom:(int)maxZoom;
+
+/// The quad paging loader variants need a TileInfo object, even if it's very simple
+- (nullable NSObject<MaplyTileInfoNew> *)tileInfo;
+
+/// Dispatch queue the data fetcher is doing its work on
+@property (nonnull) dispatch_queue_t queue;
+
+/// Set by default. We won't every return an error on failing to load. Useful for sparse data sets
+@property bool neverFail;
+
+/// Name used for debugging
+@property NSString * __nonnull name;
+
+/// Min zoom level
+- (int)minZoom;
+
+/// Max zoom level
+- (int)maxZoom;
+
+/** Override dataForTile:tileID: to return your own data for a given tile.
+ The fetchInfo can be a custom object (if you set it up that way) or
+ you can just use the tileID argument.
+
+ You'll be called on the dispatch queue.
+
+ You can return either an NSData or a MaplyLoaderReturn
+ */
+- (id __nullable)dataForTile:(id __nonnull)fetchInfo tileID:(MaplyTileID)tileID;
+
+/** Override the shutdown method.
+
+ Call the superclass shutdown method *first* and then run your own shutdown.
+ */
+- (void)shutdown;
+
+@end
+
+// Internal object used by the QuadImageLoader to generate tile load info
+@interface MaplySimpleTileInfo : NSObject<MaplyTileInfoNew>
+
+// Initialize with a min/max zoom
+- (instancetype __nonnull)initWithMinZoom:(int)inMinZoom maxZoom:(int)inMaxZoom;
+
+@end
+
+
+// Encapsulates a single tile load request
+@interface MaplySimpleTileFetchInfo : NSObject
+
+@property (nonatomic,assign) int x;
+@property (nonatomic,assign) int y;
+@property (nonatomic,assign) int level;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyStarsModel.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyStarsModel.h
new file mode 100644
index 0000000..0cbf7aa
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyStarsModel.h
@@ -0,0 +1,59 @@
+/* MaplyStarsModel.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 6/4/15.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyComponentObject.h>
+#import <WhirlyGlobe/WhirlyGlobeViewController.h>
+
+/**
+ The Stars Model parses and then displays a star field.
+
+ This is used to display a star field around the earth.
+ */
+@interface MaplyStarsModel : NSObject
+
+/// Read stars from the given file
+- (nullable instancetype)initWithFileName:(NSString *__nonnull)fileName;
+
+/// Use the given image for each point.
+/// The given image will be sampled for individual points.
+- (void)setImage:(UIImage *__nonnull)image;
+
+/**
+ Add stars to the given view controller
+
+ Turn the star positions into geometry to display. This object will track the resulting geometry objects.
+
+ @param viewC The view controller to add the start geometry to.
+
+ @param date The date for the
+
+ @param desc Additional parameters that may related to the geometry.
+
+ @param mode Thread mode to use when adding the geometry.
+ */
+- (bool)addToViewC:(WhirlyGlobeViewController *__nonnull)viewC date:(NSDate *__nonnull)date desc:(NSDictionary *__nullable)desc mode:(MaplyThreadMode)mode;
+
+/**
+ Remove star geometry from the registered view controller.
+
+ Removes any objects created for the star geometry.
+ */
+- (void)removeFromViewC;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplySticker.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplySticker.h
new file mode 100644
index 0000000..5ccf386
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplySticker.h
@@ -0,0 +1,85 @@
+/*
+ * MaplySticker.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 11/27/12.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+
+/**
+ Stickers are rectangles placed on the globe with an image.
+
+ The Maply Sticker will stretch a rectangle (in geographic) over the given extents and tack the given image on top of it. Stickers differ from MaplyMarker objects in that they're big. They can stretch over a larger are and need to be subdivided as such.
+ */
+@interface MaplySticker : NSObject
+
+/// The lower left corner (in geographic) of the sticker
+@property (nonatomic,assign) MaplyCoordinate ll;
+
+/// The upper right corner (in geographic) of the sticker
+@property (nonatomic,assign) MaplyCoordinate ur;
+
+/// Angle of rotation around center
+@property (nonatomic,assign) float rotation;
+
+/**
+ If present, this is the coordinate system the sticker is represented in.
+
+ By default the coordinates are in geographic. If this is present, the coordinates are in this system.
+ */
+@property (nonatomic,strong) MaplyCoordinateSystem * __nullable coordSys;
+
+/**
+ Image (or MaplyTexture) to stretch over the sticker.
+
+ The UIImage (or MaplyTexture) is cached in the view controller, so multiple references will result in the same texture being used. The view controller also cleans up the images when it's done with it.
+ */
+@property (nonatomic,strong) id __nullable image;
+
+/**
+ Images to stretch over the sticker.
+
+ This is an NSArray of UIImages (or MaplyTextures). The images will be cached in the view controller, so multiple references will result in the same texture being used. The view controller also cleans up the images when it's done with them.
+
+ All the images passed in here will be presented to the shader program, if it has variables for them. It's up to you to do something with them in the shader.
+ */
+@property (nonatomic,strong) NSArray * __nullable images;
+
+/**
+ Set the image format for the created textures.
+
+ OpenGL ES offers us several image formats that are more efficient than 32 bit RGBA, but they're not always appropriate. This property lets you choose one of them. The 16 or 8 bit ones can save a huge amount of space and will work well for some imagery, most maps, and a lot of weather overlays.
+
+ | Image Format | Description |
+ |:-------------|:------------|
+ | MaplyImageIntRGBA | 32 bit RGBA with 8 bits per channel. The default. |
+ | MaplyImageUShort565 | 16 bits with 5/6/5 for RGB and none for A. |
+ | MaplyImageUShort4444 | 16 bits with 4 bits for each channel. |
+ | MaplyImageUShort5551 | 16 bits with 5/5/5 bits for RGB and 1 bit for A. |
+ | MaplyImageUByteRed | 8 bits, where we choose the R and ignore the rest. |
+ | MaplyImageUByteGreen | 8 bits, where we choose the G and ignore the rest. |
+ | MaplyImageUByteBlue | 8 bits, where we choose the B and ignore the rest. |
+ | MaplyImageUByteAlpha | 8 bits, where we choose the A and ignore the rest. |
+ | MaplyImageUByteRGB | 8 bits, where we average RGB for the value. |
+ | MaplyImage4Layer8Bit | 32 bits, four channels of 8 bits each. Just like MaplyImageIntRGBA, but a warning not to do anything too clever in sampling. |
+ */
+@property (nonatomic) MaplyQuadImageFormat imageFormat;
+
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplySun.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplySun.h
new file mode 100644
index 0000000..a7722eb
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplySun.h
@@ -0,0 +1,47 @@
+/* MaplySun.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 6/24/15.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyComponentObject.h>
+#import <WhirlyGlobe/WhirlyGlobeViewController.h>
+#import <WhirlyGlobe/MaplyLight.h>
+
+/**
+ Utility for calculating sun position and shading info.
+
+ This is a utility class that figures out where the sun is at a given date and provides positional information for lighting calculations.
+ */
+@interface MaplySun : NSObject
+
+/**
+ Initialize with a date.
+
+ Initialize with the given date. The sun position will correspond to that.
+ */
+- (nonnull instancetype)initWithDate:(NSDate *__nonnull)date;
+
+/// Return the vector corresponding to the sun location from the earth.
+- (MaplyCoordinate3d)getDirection;
+
+/// Makes up a light that corresponds to the sun's location at a given time
+- (nonnull MaplyLight *)makeLight;
+
+/// Returns the location above the globe in lon/lat. Yay geocentrism!
+- (MaplyCoordinate3d)asPosition;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTapDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTapDelegate.h
new file mode 100644
index 0000000..2acf077
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTapDelegate.h
@@ -0,0 +1,30 @@
+/* MaplyTapDelegate.h
+ * WhirlyGlobeLib
+ *
+ * Created by Steve Gifford on 1/20/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyTapMessage.h>
+
+/** Maply tap gesture delegate responds to a tap
+ by sending out a notification.
+ */
+@interface MaplyTapDelegate : NSObject <UIGestureRecognizerDelegate>
+
+/// Gesture recognizer created for the delegate
+@property (nonatomic,weak) UITapGestureRecognizer *gestureRecognizer;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTapMessage.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTapMessage.h
new file mode 100644
index 0000000..6500e2f
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTapMessage.h
@@ -0,0 +1,35 @@
+/* MaplyTapMessage.h
+ * WhirlyGlobeLib
+ *
+ * Created by Steve Gifford on 9/19/11.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+
+/** Tap Message is an
+ indication that the user tapped on the map.
+ It's passed as the object in a notification.
+ */
+@interface MaplyTapMessage : NSObject
+
+/// View that was touched
+@property (nonatomic,retain) UIView *view;
+//// Touch location on view in 2D
+@property (nonatomic,assign) CGPoint touchLoc;
+/// Where the eye was.
+@property (nonatomic,assign) float heightAboveSurface;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTexture.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTexture.h
new file mode 100644
index 0000000..d9eb9df
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTexture.h
@@ -0,0 +1,31 @@
+/*
+ * MaplyTexture.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 10/25/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+/**
+ Represents an OpenGL texture.
+
+ The MaplyTexture is an opaque object used to track OpenGL ES textures. You create one from the MaplyBaseViewController's addImage call. Then that texture will live until this object is released.
+
+ These can be used in place of UIImages in the various objects (e.g. MaplyScreenMarker).
+ */
+@interface MaplyTexture : NSObject
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTextureBuilder.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTextureBuilder.h
new file mode 100644
index 0000000..74d842c
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTextureBuilder.h
@@ -0,0 +1,47 @@
+/*
+ * MaplyTextureBuilder.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 5/30/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+
+/**
+ The Maply Linear Texture Builder is used to construct linear textures
+ for use on widened vectors.
+
+ Linear textures of this type are used to represent dotted and dashed lines. These may come from Mapnik configuration files or you can just make them up yourself.
+
+ After creating an image with this object, you'll want to pass it as a parameter to the widened vector add method.
+ */
+@interface MaplyLinearTextureBuilder : NSObject
+
+/**
+ Set the pattern of dots and empty spaces.
+
+ This is an array of NSNumbers (treated as integers) that specify how big an element in the given pattern is. The first element is on, the next off and so forth.
+ */
+- (void)setPattern:(NSArray *)elements;
+
+/**
+ Build the image from the size and elements specified.
+
+ If you've set a reasonable size and added a pattern, this will render the pattern into the image and return it. If the size of the image differs from the size of the elements, they will be scaled to the image.
+ */
+- (UIImage *)makeImage;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTileSourceNew.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTileSourceNew.h
new file mode 100644
index 0000000..8c5bcd0
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTileSourceNew.h
@@ -0,0 +1,161 @@
+/*
+ * MaplyTileSourceNew.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 9/13/18.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyImageTile.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+
+/**
+ This represents the indentifier for a unique tile in the pyramid.
+
+ Each tile in an image (or vector tile) pyramid can be uniquely
+ identified by an x, y, and level. The levels start at zero and run to
+ a maximum. x and y also start at zero and run to 2^level-1.
+
+
+ How these are interpreted is up to the tile source itself. For example, some tile sources start at the lower left for (0,0) and run to the upper left. Others do it the opposite way. There's a flipY option in the MaplyQuadImageTileLayer to deal with this, but the system doesn't care all that much as long as you are consistent.
+ @see MaplyTileSource
+ @see MaplyQuadPagingLayer
+ @see MaplyQuadImageTilesLayer
+ */
+typedef struct
+{
+ int x, y, level;
+} MaplyTileID;
+
+/// Convert a MaplyTileID to an NSString
+NSString *__nonnull MaplyTileIDString(MaplyTileID tileID);
+
+/**
+ Tile Info Protocol.
+
+ This describes a single source of data tiles. A uses these to
+ figure out what to load when and where. The loader passes the result of
+ fetchInfoForTile to a MaplyTileFetcher to get the data it wants.
+ */
+@protocol MaplyTileInfoNew<NSObject>
+
+/**
+ The minimum zoom level available.
+
+ This is the lowest level we'll try to fetch. Any levels below that will be filled in with placeholders. Those are empty, but they allow us to load tiles beneath.
+ */
+- (int)minZoom;
+
+/**
+ The maximum zoom level available.
+
+ This is the highest level (e.g. largest) that we'll
+ fetch for a given pyramid tile source. The source can sparse,
+ so you are not required to have these tiles available, but this
+ is as high as the loader will fetch.
+ */
+- (int)maxZoom;
+
+/**
+ FetchInfo object for a given tile.
+
+ The FetchInfo object is specific to the type of TileFetcher you're using and
+ tells the fetcher how to get the data you wawnt.
+ RemoteTileFetchers want a RemoteTileInfoNew object.
+ */
+- (id __nullable)fetchInfoForTile:(MaplyTileID)tileID flipY:(bool)flipY;
+
+@end
+
+/**
+ A tile source that just returns nil. You can use this like a tile source where you need one that doesn't do anything.
+ */
+@interface MaplyTileInfoNone : NSObject<MaplyTileInfoNew>
+@end
+
+
+
+/**
+ Generic Tile fetcher request.
+
+ A single request for a single tile of data from a single source.
+ The tile fetcher will... fetch this and call the success or failure callback.
+ */
+@interface MaplyTileFetchRequest : NSObject
+
+/// Priority before importance. Less is more important.
+@property (nonatomic) int priority;
+/// How important this is to us. Probably screen space.
+@property (nonatomic) float importance;
+/// If all other values are equal, sort by this.
+/// It keeps requests we're waiting for grouped together
+@property (nonatomic) int group;
+
+/// Tile ID for this tile
+@property (nonatomic,assign) MaplyTileID tileID;
+
+/// An object representing the tile source. Used for sorting. Not accessed by the fetcher.
+@property (nonatomic,weak,nullable) id tileSource;
+
+/** This is requested from a TileInfo object by a loader and then passed
+ along to the TileFetcher. TileFetchers expect certain objects.
+ The RemoteTileFetcher wants a RemoteFetchInfo object and will check.
+ Other fetchers will want other things.
+ */
+@property (nonatomic,nonnull,strong) id fetchInfo;
+
+/**
+ Tile Fetcher success callback.
+
+ Called on a new dispatch queue and won't be marked as loaded until it returns.
+ This is a good way to limit how many things are loading/parsing at the same time.
+ */
+@property (nonatomic,nullable) void (^success)(MaplyTileFetchRequest * __nonnull,id __nonnull);
+
+/**
+ Tile Fetcher failure callback.
+ */
+@property (nonatomic,nullable) void (^failure)(MaplyTileFetchRequest * __nonnull,NSError * __nonnull);
+
+@end
+
+/**
+ Tile Fetcher protocol.
+
+ The tile fetcher interacts with loaders that want tiles, as demanded by samplers.
+ A given data source (e.g. remote URL, MBTiles) needs one of these to fetch and return data.
+ */
+@protocol MaplyTileFetcher<NSObject>
+
+/// Add a whole group of requests at once.
+/// This is useful if we want to avoid low priority tiles grabbing the slots first
+- (void)startTileFetches:(NSArray<MaplyTileFetchRequest *> *__nonnull)requests;
+
+/// Update an active request with a new priority and importance
+- (id __nullable)updateTileFetch:(id __nonnull)fetchID priority:(int)priority importance:(double)importance;
+
+/// Name of this tile fetcher. Used for coordinating tile sources.
+- (NSString * __nonnull)name;
+
+/// Cancel a group of requests at once
+/// Use the object returned by the startTileFetch call (which is just a Request object)
+- (void)cancelTileFetches:(NSArray * __nonnull)requestRets;
+
+/// Kill all outstanding connections and clean up
+- (void)shutdown;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTouchCancelAnimationDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTouchCancelAnimationDelegate.h
new file mode 100644
index 0000000..74c1391
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTouchCancelAnimationDelegate.h
@@ -0,0 +1,26 @@
+/* MaplyTouchCancelAnimationDelegate.h
+ * WhirlyGlobeLib
+ *
+ * Created by Jesse Crocker on 7/15/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+
+@interface MaplyTouchCancelAnimationDelegate : NSObject <UIGestureRecognizerDelegate>
+
+/// The gesture recognizer
+@property (nonatomic,strong) UIGestureRecognizer *gestureRecognizer;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTwoFingerTapDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTwoFingerTapDelegate.h
new file mode 100644
index 0000000..0e8fe6e
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyTwoFingerTapDelegate.h
@@ -0,0 +1,25 @@
+/* MaplyTwoFingerTapDelegate.h
+ *
+ * Created by Jesse Crocker on 2/4/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyZoomGestureDelegate.h>
+
+@interface MaplyTwoFingerTapDelegate : MaplyZoomGestureDelegate
+
+// How long we animate from one place to the next
+@property (nonatomic) float animTime;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyUpdateLayer.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyUpdateLayer.h
new file mode 100644
index 0000000..772cea1
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyUpdateLayer.h
@@ -0,0 +1,100 @@
+/*
+ * MaplyUpdateLayer.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 4/13/15.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyComponentObject.h>
+#import <WhirlyGlobe/MaplyControllerLayer.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+
+@class MaplyUpdateLayer;
+
+/**
+ An encapsulation of where the viewer is and what they're looking at.
+
+ This wraps information about where the viewer is currently looking from and at.
+ */
+@interface MaplyViewerState : NSObject
+
+/// Position of the viewer
+- (MaplyCoordinate3d) eyePos;
+
+@end
+
+
+/**
+ The update delegate is called if the viewer moves, but not too often.
+
+ Use this delegate to generate features around the viewer when they move. You can control how far they have to move (in display coordinates) and how often you'll receive updates.
+ */
+@protocol MaplyUpdateDelegate
+
+/**
+ Called when the MaplyUpdateLayer is initialized.
+
+ This is called after things are set up. You'll be on the layer thread here.
+ */
+- (void)start:(MaplyUpdateLayer *__nonnull)layer;
+
+/**
+ Called when the viewer moves.
+
+ You'll be called on the layer thread when the viewer moves more than your moveDist, subject to calls no more frequent than the minTime.
+ */
+- (void)viewerMovedTo:(MaplyViewerState *__nonnull)viewState layer:(MaplyUpdateLayer *__nonnull)layer;
+
+/**
+ Called when the update layer is shutting down.
+
+ Clean up your own data here.
+ */
+- (void)teardown:(MaplyUpdateLayer *__nonnull)layer;
+
+@end
+
+/**
+ This layer will call a delegate as the user moves around, but constrained to distance and time.
+
+ This layer is responsible for calling a delegate you provide as the user moves their viewpoint around. You'll be called if they move from than a certain amount, but not more often than the minimum time.
+ */
+@interface MaplyUpdateLayer : MaplyControllerLayer
+
+/// The minimum distance that will trigger a delegate call. Distance is in display units (radius of the earth = 1.0).
+@property (nonatomic,readonly) double moveDist;
+
+/// The delegate will be called no more often than this amount (in seconds).
+@property (nonatomic,readonly) double minTime;
+
+/// Maximum time to go without getting an update (if things are moving)
+@property (nonatomic) double maxLag;
+
+/**
+ Initalize the update layer with a delegate and parameters.
+
+ @param delegate The delegate that will be called every time the user moves, subject to the values.
+
+ @param moveDist The minimum distance that will trigger a delegate call. Distance is in display units (radius of the earth = 1.0).
+
+ @param minTime The delegate will be called no more often than this amount (in seconds).
+ */
+- (nonnull instancetype)initWithDelegate:(NSObject<MaplyUpdateDelegate> *__nullable)delegate moveDist:(double)moveDist minTime:(double)minTime;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVariableTarget.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVariableTarget.h
new file mode 100644
index 0000000..9259826
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVariableTarget.h
@@ -0,0 +1,88 @@
+/*
+ * MaplyVariableTarget.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 9/18/18.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyTexture.h>
+#import <WhirlyGlobe/MaplyRenderTarget.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+
+/**
+ A variable target manages two pass rendering for one type of variable.
+
+ Set up the variable target
+ */
+@interface MaplyVariableTarget : NSObject
+
+/// Initialize with the variable type and view controller
+- (nonnull instancetype)initWithType:(MaplyQuadImageFormat)type viewC:(NSObject<MaplyRenderControllerProtocol> * __nonnull)viewC;
+
+/// Render target created for this variable target
+@property (nonatomic,readonly,strong,nonnull) MaplyRenderTarget *renderTarget;
+
+/// Scale the screen by this amount for the render target
+- (void)setScale:(double)scale;
+
+/// Color of the rectangle used to draw the render target
+@property (nonatomic,strong,nonnull) UIColor *color;
+
+/// Draw priority of the rectangle we'll use to draw the render target to the screen
+@property (nonatomic,assign) int drawPriority;
+
+/// If set (by default), then we clear out the render target every frame
+@property (nonatomic,assign) bool clearEveryFrame;
+
+/// When we're clearing, use this value. 0 by default
+@property (nonatomic,assign) float clearVal;
+
+/// Shader used to draw the render target to the screen.
+/// Leave this empty and we'll provide our own
+@property (nonatomic,strong,nullable) MaplyShader *shader;
+
+/// By default we'll build a rectangle to display the target
+@property (nonatomic,assign) bool buildRectangle;
+
+/// If set, the rectangle rendered to the screen will read from the z Buffer
+/// Useful, when doing depth comparisons
+@property (nonatomic,assign) bool zBuffer;
+
+/// Rectangle created to show the variable target (if that's set)
+@property (nonatomic,readonly,nullable) MaplyComponentObject *rectObj;
+
+/// Size of the texture in pixels for the render target
+@property (nonatomic,readonly) CGSize texSize;
+
+/// The texture we're rendering to (as part of the render target)
+@property (nonatomic,readonly,strong,nullable) MaplyTexture *renderTex;
+
+/// Passing in another variable target will let us assign that target to the
+/// rectangle used to render this variable target's data. This is used if
+/// you need the contents of more than one target in a shader.
+- (void)addVariableTarget:(MaplyVariableTarget * __nonnull)target;
+
+// Pass this uniform block to the geometry we create for rendering (if it was created)
+- (void)setUniformBlock:(NSData *__nonnull)uniBlock buffer:(int)bufferID;
+
+/// Clear the target for the next frame
+- (void)clear;
+
+/// Stop rendering to the target and release everything
+- (void)shutdown;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorObject.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorObject.h
new file mode 100644
index 0000000..80b2ca4
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorObject.h
@@ -0,0 +1,562 @@
+/* MaplyVectorObject.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 8/2/12.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+
+@class MaplyBaseViewController;
+
+/// Data type for the vector. Multi means it contains multiple types
+typedef NS_ENUM(NSInteger, MaplyVectorObjectType) {
+ MaplyVectorNoneType,
+ MaplyVectorPointType,
+ MaplyVectorLinearType,
+ MaplyVectorLinear3dType,
+ MaplyVectorArealType,
+ MaplyVectorMultiType,
+};
+
+
+/**
+ Maply Vector Object represents zero or more vector features.
+
+ The Vector Object can hold several vector features of the same or different types. It's meant to be a fairly opaque structure, often read from GeoJSON or Shapefiles. It's less opaque than originally planned, however, and sports a number of specific methods.
+
+ If you're doing real vector manipulation, it's best to do it somewhere else and then create one of these as needed for display.
+
+ Vector Objects can be created directly or read from a MaplyVectorDatabase. They are typically then displayed on top of a MaplyViewController or WhirlyGlobeViewController as vectors.
+
+ Vector Objects vertices are always in geographic, with longitude = x and latitude = y.
+ */
+@interface MaplyVectorObject : NSObject
+
+/// Turn this off to make this vector invisible to selection.
+/// On by default.
+@property (nonatomic,assign) bool selectable;
+
+/**
+ Return the attributes for the vector object.
+
+ All vectors should have some set of attribution. If there's more than one vector feature here, we'll return the attributes on the first one.
+
+ The attribution is returned as an NSDictionary and, though you can modify it, you probably shouldn't.
+ */
+@property (nonatomic,readonly) NSMutableDictionary *__nullable attributes;
+
+/**
+ Parse vector data from geoJSON.
+
+ Returns one object to represent the whole thing, which might include multiple different vectors. This version uses the faster JSON parser.
+
+ We assume the geoJSON is all in decimal degrees in WGS84.
+ */
++ (MaplyVectorObject *__nullable)VectorObjectFromGeoJSON:(NSData *__nonnull)geoJSON;
+
+/**
+ Parse vector data from geoJSON.
+
+ Returns one object to represent the whole thing, which might include multiple different vectors. This version uses slower JSON parser.
+
+ We assume the geoJSON is all in decimal degrees in WGS84.
+*/
++ (MaplyVectorObject *__nullable)VectorObjectFromGeoJSONApple:(NSData *__nonnull)geoJSON;
+
+/**
+ Parse vector data from geoJSON.
+
+ Returns one object to represent the whole thing, which might include multiple different vectors. This version parses its data from an NSDictionary, which had to be parsed from JSON at some point. Probably the slower path.
+
+ We assume the geoJSON is all in decimal degrees in WGS84.
+ */
++ (MaplyVectorObject *__nullable)VectorObjectFromGeoJSONDictionary:(NSDictionary *__nonnull)geoJSON;
+
+// Note: Reader turned off
+#if 0
+/**
+ Read vector objects from the given cache file.
+
+ MaplyVectorObject's can be written and read from a binary file. We use this for caching data locally on the device.
+
+ @param fileName Name of the binary vector file.
+
+ @return The vector object(s) read from the file or nil on failure.
+ */
++ (MaplyVectorObject *__nullable)VectorObjectFromFile:(NSString *__nonnull)fileName;
+#endif
+
+/**
+ Read vector objects from the given shapefile.
+
+ This will read all the shapes in the given shapefile into memory and return them as one MaplyVectorObject.
+
+ @param fileName The basename of the shape file. Don't include the extension.
+
+ @return The vector object(s) read from the file or nil on failure.
+ */
++ (MaplyVectorObject *__nullable)VectorObjectFromShapeFile:(NSString *__nonnull)fileName;
+
+/**
+ Parse vector objects from a JSON assembly.
+
+ This version can deal with non-compliant assemblies returned by the experimental OSM server
+ */
++ (NSDictionary *__nullable)VectorObjectsFromGeoJSONAssembly:(NSData *__nonnull)geoJSON;
+
+/**
+ Initialize with a single data point and attribution.
+
+ This version takes a single coordinate and the attributes to go with it.
+ */
+- (nonnull instancetype)initWithPoint:(MaplyCoordinate)coord attributes:(NSDictionary *__nullable)attr;
+
+/**
+ Initialize with a single data point and attribution.
+
+ This version takes a single coordinate and the attributes to go with it.
+ */
+- (nonnull instancetype)initWithPointRef:(const MaplyCoordinate *__nonnull)coord attributes:(NSDictionary *__nullable)attr;
+
+/**
+ Initialize with a linear feature.
+
+ This version takes an array of coordinates (2 `NSNumber`s per coordinate, in degrees) and the attribution.
+ With this it will make a linear feature.
+ Prefer the `inDegrees:` overload to reduce ambiguity.
+ Returns nil if the coordinate array contains an odd number of values.
+ */
+- (nullable instancetype)initWithLineString:(const NSArray<NSNumber*> *__nonnull)coords
+ attributes:(NSDictionary *__nullable)attr;
+
+/**
+ Initialize with a linear feature.
+
+ This version takes an array of coordinate pairs (as NSNumber) and the attribution. With this it will make a linear feature.
+ Returns nil if the coordinate array contains an odd number of values.
+ */
+- (nullable instancetype)initWithLineString:(const NSArray<NSNumber*> *__nonnull)coords
+ attributes:(NSDictionary *__nullable)attr
+ inDegrees:(bool)inDegrees;
+
+/**
+ Initialize with a linear feature.
+
+ This version takes an array of coordinates, the size of that array and the attribution. With this it will make a linear feature.
+ */
+- (nonnull instancetype)initWithLineString:(const MaplyCoordinate *__nonnull)coords
+ numCoords:(int)numCoords
+ attributes:(NSDictionary *__nullable)attr;
+
+/**
+ Inintialize as an areal feature.
+
+ This version takes an array of coordinates, the size of that array and the attribution.
+ With this it will make a single area feature with one (exterior) loop. To add loops, call `addHole:numCoords:`
+ */
+- (nonnull instancetype)initWithAreal:(const MaplyCoordinate *__nonnull)coords
+ numCoords:(int)numCoords
+ attributes:(NSDictionary *__nullable)attr;
+
+/**
+ Inintialize as an areal feature.
+
+ This version takes an array of coordinates (2 `NSNumber`s per coordinate, in radians).
+ With this it will make a single area feature with one (exterior) loop. To add loops, call addHole:numCoords:
+ Prefer the `inDegrees:` overload to reduce ambiguity.
+ Returns nil if the coordinate array contains an odd number of values.
+*/
+- (nullable instancetype)initWithArealArray:(const NSArray<NSNumber *> *__nonnull)coords
+ attributes:(NSDictionary *__nullable)attr;
+
+/**
+ Inintialize as an areal feature.
+
+ This version takes an array of coordinates (2 `NSNumber`s per coordinate, in radians).
+ With this it will make a single area feature with one (exterior) loop. To add loops, call `addHole:numCoords:`
+ Returns nil if the coordinate array contains an odd number of values.
+*/
+- (nullable instancetype)initWithArealArray:(const NSArray<NSNumber *> *__nonnull)coords
+ attributes:(NSDictionary *__nullable)attr
+ inDegrees:(bool)inDegrees;
+
+/**
+ Initializes with vectors parsed from geoJSON.
+
+ Returns one object to represent the whole thing, which might include multiple different vectors. This version uses the faster JSON parser.
+
+ We assume the geoJSON is all in decimal degrees in WGS84.
+ */
+- (nullable instancetype)initWithGeoJSON:(NSData *__nonnull)geoJSON;
+
+/**
+ Initializes with vector parsed from geoJSON.
+
+ Returns one object to represent the whole thing, which might include multiple different vectors. This version uses slower JSON parser.
+
+ We assume the geoJSON is all in decimal degrees in WGS84.
+ */
+- (nullable instancetype)initWithGeoJSONApple:(NSData *__nonnull)geoJSON;
+
+/**
+ Initializes with vector parsed from geoJSON.
+
+ Returns one object to represent the whole thing, which might include multiple different vectors. This version parses its data from an NSDictionary, which had to be parsed from JSON at some point. Probably the slower path.
+
+ We assume the geoJSON is all in decimal degrees in WGS84.
+ */
+- (nullable instancetype)initWithGeoJSONDictionary:(NSDictionary *__nonnull)geoJSON;
+
+// Note: Turned off with reading
+#if 0
+/**
+ Initializes with vectors read from the given cache file.
+
+ MaplyVectorObject's can be written and read from a binary file. We use this for caching data locally on the device.
+
+ @param fileName Name of the binary vector file.
+
+ @return The vector object(s) read from the file or nil on failure.
+ */
+- (nullable instancetype)initWithFile:(NSString *__nonnull)fileName;
+#endif
+
+/**
+ Initializes with vectors read from the given shapefile.
+
+ This will read all the shapes in the given shapefile into memory and return them as one MaplyVectorObject.
+
+ @param fileName The basename of the shape file. Don't include the extension.
+
+ @return The vector object(s) read from the file or nil on failure.
+ */
+- (nullable instancetype)initWithShapeFile:(NSString *__nonnull)fileName;
+
+
+// Note: Vector writing turned off
+#if 0
+/**
+ Write the vector object to the given file on the device.
+
+ We support a binary format for caching vector data. Typically you write these files on the device or in the simulator and then put them in a place you can easily find them when needed.
+
+ @param fileName The file to read the vector data from.
+
+ @return Returns true on succes, false on failure.
+ */
+- (bool)writeToFile:(NSString *__nonnull)fileName;
+#endif
+
+/**
+ Make a deep copy of the vector object and return it.
+
+ This makes a complete copy of the vector object, with all features and nothing shared.
+
+ Had to rename this because Apple's private method scanner is dumb.
+ */
+- (MaplyVectorObject *__nonnull)deepCopy2;
+
+/**
+ Reproject from one coordinate system to another.
+
+ This reprojects every single point in the points, linears, and areals (and mesh) from the source coordinate system to the destionation.
+
+ Typically, you'll want Plate Carree for display, the destSystem is probably that.
+
+ For various reasons (e.g. scale), this will probably not work right for you.
+
+ @param srcSystem The source coordinate system. The data is already in this sytem.
+
+ @param destSystem The destination coordinate system. The data will be in this system on return.
+ */
+- (void)reprojectFrom:(MaplyCoordinateSystem *__nonnull)srcSystem to:(MaplyCoordinateSystem *__nonnull)destSystem;
+
+/**
+ Dump the feature(s) out as text
+
+ This will write each feature out as text for debugging.
+ */
+- (NSString *__nonnull)log;
+
+/**
+ Add a hole to an existing feature.
+
+ This method is expecting to find exactly one areal feature. If it finds one, it will add the given hole as a loop on the end of the list of loops.
+ */
+- (void)addHole:(const MaplyCoordinate *__nonnull)coords numCoords:(int)numCoords;
+
+/**
+ Returns the type of the vector feature.
+
+ This method returns the type of the vector. Since vector objects can contain multiple types of vectors at once, this is somewhat complicated.
+
+|Type | Description |
+|:----|:-----------:|
+|MaplyVectorNoneType | There are no features in this object. |
+|MaplyVectorPointType | There are only points (and multi-points) in the object. |
+|MaplyVectorLinearType | There are only linear features in the object. |
+|MaplyVectorLinear3dType | There are only linear features with Z values in the object. |
+|MaplyVectorArealType | There are only areal features in the object. |
+|MaplyVectorMultiType | There are multiple features of different types in the object. |
+ */
+- (MaplyVectorObjectType)vectorType;
+
+/**
+ Run a point in polygon test on all the areal features within the object.
+
+ We'll run a point in polygon test on all the areal features within the vector object. If the point is within one of them, we return true, otherwise false.
+ */
+- (bool)pointInAreal:(MaplyCoordinate)coord;
+
+/**
+ Test if any linear feature is within distance of coord
+ */
+- (bool)pointNearLinear:(MaplyCoordinate)coord distance:(float)maxDistance inViewController:(MaplyBaseViewController *__nonnull)vc;
+
+/**
+ Calculate the center of the entire set of vectors in this object.
+ */
+- (MaplyCoordinate)center;
+
+/**
+ Copy the vectors in the given vector object into this one.
+ */
+- (void)mergeVectorsFrom:(MaplyVectorObject *__nonnull)otherVec;
+
+/**
+ For a linear feature, calculate the mid oint and rotation at that point.
+
+ The vector object contains a number of half baked geometric queries, this being one of them.
+
+ This finds the middle (as measured by distance) of a linear feature and then calculations an angle corresponding to the line segment that middle sits in.
+
+ Why? Think label road placement.
+ */
+- (bool)linearMiddle:(MaplyCoordinate *__nonnull)middle rot:(double *__nonnull)rot;
+
+- (bool)linearMiddle:(MaplyCoordinate *__nullable)middle rot:(double *__nullable)rot displayCoordSys:(MaplyCoordinateSystem *__nonnull)coordSys;
+
+/**
+ For a linear feature, calculate the mid point.
+
+ This is a convenience method to be called without pointers (Swift)
+
+ If you need both the mid point and the rotation, this method is less efficient than the method with pointers.
+
+ @return kMaplyNullCoordinate in case of error
+
+ */
+- (MaplyCoordinate)linearMiddle:(MaplyCoordinateSystem *__nonnull)coordSys;
+
+/**
+ For a linear feature, calculate the mid point and returns the rotation at that point.
+
+ This is a convenience method to be called without pointers (Swift)
+
+ If you need both the mid point and the rotation, this method is less efficient than the method with pointers.
+
+ @return DBL_MIN in case of error
+ */
+- (double)linearMiddleRotation:(MaplyCoordinateSystem *__nonnull)coordSys;
+
+/**
+ return the middle coordinate in a line feature
+
+ @return kMaplyNullCoordinate in case of error
+ */
+- (MaplyCoordinate)middleCoordinate;
+
+/**
+ return the middle coordinate in a line feature.
+ */
+- (bool)middleCoordinate:(MaplyCoordinate *__nonnull)middle;
+
+/**
+ Calculate the center and extents of the largest loop in an areal feature.
+
+ The vector object contains a number of half baked geometric queries, this being one of them.
+
+ If this vector contains at least one areal feature, we'll determine which loop is the largest and return the center of that loop, as well as its bounding box.
+
+ Why? Think label placement on an areal feature.
+
+ @return Returns false if there was no loop (i.e. probably isn't an areal)
+ */
+- (bool)largestLoopCenter:(MaplyCoordinate *__nullable)center mbrLL:(MaplyCoordinate *__nullable)ll mbrUR:(MaplyCoordinate *__nullable)ur;
+
+/**
+ Calculate the centroid of the largest loop in the areal feature.
+
+ The centroid is a better center for label placement than the middle of the largest loop as calculated by largestLoopCenter:mbrLL:mbrUR:
+
+ @return Returns the centroid structure. If there was no loop (i.e. probably isn't an areal), the result will be kMaplyNullCoordinate
+ */
+- (MaplyCoordinate)centroid;
+
+/**
+ Calculate the centroid of the largest loop in the areal feature.
+
+ The centroid is a better center for label placement than the middle of the largest loop as calculated by largestLoopCenter:mbrLL:mbrUR:
+
+ @return Returns false if there was no loop (probably wasn't an areal).
+ */
+- (bool)centroid:(MaplyCoordinate *__nonnull)centroid;
+
+/**
+ Calculate the bounding box of all the features in this vector object.
+
+ @return kMaplyNullBoundingBox in case of error
+ */
+- (MaplyBoundingBox)boundingBox;
+
+/**
+ Calculate the bounding box of all the features in this vector object.
+ */
+- (bool)boundingBoxLL:(MaplyCoordinate *__nonnull)ll ur:(MaplyCoordinate *__nonnull)ur;
+
+/**
+ Calculate the area of the outer loops.
+
+ This returns the area of the outer loops of any areal features in the VectorObject.
+ */
+- (double)areaOfOuterLoops;
+
+/**
+ Convert any linear features into areal features.
+
+ Convert linear features to areal features by closing each one individually.
+ */
+- (MaplyVectorObject * _Nonnull )linearsToAreals;
+
+/**
+ Convert any areal features into outlines.
+ */
+- (MaplyVectorObject * __nonnull)arealsToLinears;
+
+/**
+ Reverse the direction of areal loops in-place
+ */
+- (void)reverseAreals;
+
+/**
+ Return a copy with the areal loops reversed
+ */
+- (MaplyVectorObject * __nonnull)reversedAreals;
+
+/**
+ Filter out edges created from clipping areal features on the server.
+
+ In some very specific cases (OSM water) we get polygons that are obviously clipped
+ along internal boundaries. We can clear this up with some very, very specific logic.
+
+ Input must be closed areals and output is linears.
+ */
+- (MaplyVectorObject *__nonnull)filterClippedEdges;
+
+/**
+ Convert a feature to an NSArray of NSArrays of CLLocation points.
+
+ This is intended for areal features. It will convert those coordinates to CLLocation values and return them. Obviously this is intended for things that need CLLocation values.
+
+ @return Returns an NSArray of NSArray's which then contain CLLocation points.
+ */
+- (NSArray *__nullable)asCLLocationArrays;
+
+/**
+ Return the data as an NSArray of NSNumbers.
+
+ If this is a linear, we'll return the points as an NSArray of NSNumbers.
+ */
+- (NSArray *__nullable)asNumbers;
+
+/**
+ Split up this feature into individual features and return an array of them.
+
+ A vector object can represent multiple features with no real rhyme or reason to it. This method will make one vector object per feature, allowing you to operate on those individually.
+
+ @return An NSArray of MaplyVectorObject.
+ */
+- (NSArray<MaplyVectorObject *> *__nonnull)splitVectors;
+
+/**
+ Subdivide the edges in this feature to a given tolerance.
+
+ This will break up long edges in a vector until they lie flat on a globe to a given epsilon. The epislon is in display coordinates (radius = 1.0). This routine breaks this up along geographic boundaries.
+ */
+- (void)subdivideToGlobe:(float)epsilon;
+
+/**
+ Subdivide the edges in this feature to a given tolerance, using great circle math.
+
+ This will break up long edges in a vector until they lie flat on a globe to a given epsilon using a great circle route. The epsilon is in display coordinates (radius = 1.0).
+ */
+- (void)subdivideToGlobeGreatCircle:(float)epsilon;
+
+/**
+ Subdivide the edges in this feature to a given tolerance, using great circle math.
+
+ This version samples a great circle to display on a flat map.
+ */
+- (void)subdivideToFlatGreatCircle:(float)epsilon;
+
+
+/**
+ Subdivide the edges in this feature to a given tolerance, using ellipsoidal great circle math.
+
+ This will break up long edges in a vector until they lie flat on a globe to a given epsilon using a great circle route. The epsilon is in display coordinates (radius = 1.0).
+ */
+- (void)subdivideToGlobeGreatCirclePrecise:(float)epsilon;
+
+/**
+ Subdivide the edges in this feature to a given tolerance, using ellipsoidal great circle math.
+
+ This version samples a great circle to display on a flat map.
+ */
+- (void)subdivideToFlatGreatCirclePrecise:(float)epsilon;
+
+/**
+ Tesselate the areal geometry in this vector object and return triangles.
+
+ This will attempt to tesselate the areals (with holes) and turn them into triangles. No attribution will be assigned to the new triangles, so be aware. The tesselator is the GLU based one and does a decent job. Odds are if there's something wrong it's in the input data.
+ */
+- (MaplyVectorObject *__nonnull)tesselate;
+
+/**
+ Clip the given (presumably areal) feature(s) to a grid in radians of the given size.
+
+ This will run through the loops in the input vectors and clip them against a grid. The grid size is given in radians.
+
+ @return New areal features broken up along the grid.
+ */
+- (MaplyVectorObject *__nullable)clipToGrid:(CGSize)gridSize;
+
+/**
+
+ Clip the given (probably areal) features to the given bounding box.
+
+ This will run through the loops of the areal features and clip them against a bounding box.
+
+ The bounding box should be in the same coordinate system as the grid, probably radians.
+
+ @return The new areal features will be clipped along the bounding box.
+ */
+- (MaplyVectorObject *__nullable)clipToMbr:(MaplyCoordinate)ll upperRight:(MaplyCoordinate)ur;
+
+@end
+
+typedef MaplyVectorObject WGVectorObject;
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorStyle.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorStyle.h
new file mode 100644
index 0000000..2d30fab
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorStyle.h
@@ -0,0 +1,214 @@
+/* MaplyVectorStyle.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 1/3/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplyBaseViewController.h>
+
+@class MaplyVectorTileData;
+
+/**
+ Settings that control how vector tiles look in relation to their styles.
+
+ These are set based on the sort of device we're on, particularly retina vs. non-retina. They can be manipulated directly as well for your needs.
+ */
+@interface MaplyVectorStyleSettings : NSObject
+
+/// Initialize with the (presumably) retina scale
+- (instancetype __nonnull)initWithScale:(CGFloat)scale;
+
+/// Line widths will be scaled by this amount before display.
+@property (nonatomic) float lineScale;
+/// Text sizes will be scaled by this amount before display.
+@property (nonatomic) float textScale;
+/// Markers (symbols+circles) will be scaled by this amount before display.
+@property (nonatomic) float markerScale;
+/// Symbols will be scaled by this amount before display.
+@property (nonatomic) float symbolScale;
+/// Circles will be scaled by this amount before display.
+@property (nonatomic) float circleScale;
+/// Importance for markers in the layout engine
+@property (nonatomic) float markerImportance;
+/// Default marker size when none is specified
+@property (nonatomic) float markerSize;
+/// Importance for labels in the layout engine
+@property (nonatomic) float labelImportance;
+/// If set we'll use the zoom levels defined in the style
+@property (nonatomic) bool useZoomLevels;
+
+/// For symbols we'll try to pull a UUID out of this field to stick in the marker and label uniqueID
+@property (nonatomic,nullable) NSString *uuidField;
+
+/// Draw priority calculated as offset from here
+@property (nonatomic) int baseDrawPriority;
+
+/// Offset between levels
+@property (nonatomic) int drawPriorityPerLevel;
+
+/**
+ The overall map scale calculations will be scaled by this amount.
+
+ We use the map scale calculations to figure out what is dispalyed and when. Not what to load in, mind you, that's a separate, but related calculation. This controls the scaling of those calculations. Scale it down to load things in later, up to load them in sooner.
+ */
+@property (nonatomic) float mapScaleScale;
+
+/// Dashed lines will be scaled by this amount before display.
+@property (nonatomic) float dashPatternScale;
+
+/// Use widened vectors (which do anti-aliasing and such)
+@property (nonatomic) bool useWideVectors;
+
+/// Where we're using old vectors (e.g. not wide) scale them by this amount
+@property (nonatomic) float oldVecWidthScale;
+
+/// If we're using widened vectors, only activate them for strokes wider than this. Defaults to zero.
+@property (nonatomic) float wideVecCuttoff;
+
+/// If set, this is the shader we'll use on the areal features.
+@property (nonatomic,strong) NSString * _Nullable arealShaderName;
+
+/// If set, we'll make all the features selectable. If not, we won't.
+@property (nonatomic) bool selectable;
+
+/// If set, icons will be loaded from this directory
+@property (nonatomic, strong) NSString * _Nullable iconDirectory;
+
+/// The default font family for all text
+@property (nonatomic,strong) NSString * _Nullable fontName;
+
+@end
+
+@protocol MaplyVectorStyle;
+
+/**
+ Protocol for styling the vectors.
+
+ You pass in an object which adheres to this protocol and will style
+ the vectors read by a MaplyMapnikVectorTiles object. In general, this will be
+ a parsed Mapnik vector file, but you can substitute your own logic as well.
+ */
+@protocol MaplyVectorStyleDelegate <NSObject>
+
+/**
+ Return the styles that apply to the given feature (attributes).
+ */
+- (nullable NSArray *)stylesForFeatureWithAttributes:(NSDictionary *__nonnull)attributes
+ onTile:(MaplyTileID)tileID
+ inLayer:(NSString *__nonnull)layer
+ viewC:(NSObject<MaplyRenderControllerProtocol> *__nonnull)viewC;
+
+/// Return true if the given layer is meant to display for the given tile (zoom level)
+- (BOOL)layerShouldDisplay:(NSString *__nonnull)layer tile:(MaplyTileID)tileID;
+
+/// Return the style associated with the given UUID.
+- (nullable NSObject<MaplyVectorStyle> *)styleForUUID:(long long)uiid viewC:(NSObject<MaplyRenderControllerProtocol> *__nonnull)viewC;
+
+/// Return the style for the background
+- (nullable NSObject<MaplyVectorStyle> *)backgroundStyleViewC:(NSObject<MaplyRenderControllerProtocol> *__nonnull)viewC;
+
+// Return a list of all the styles in no particular order. Needed for categories and indexing
+- (NSArray * __nonnull)allStyles;
+
+@end
+
+/**
+ Base protocol for the vector styles.
+
+ Maply Vector Style is the protocol the your vector style needs to
+ implement for the vector tile parsers to recognize it.
+ */
+@protocol MaplyVectorStyle<NSObject>
+
+/// Unique Identifier for this style
+- (long long) uuid;
+
+/// Category used for sorting
+- (NSString * _Nullable) getCategory;
+
+/// Set if this geometry is additive (e.g. sticks around) rather than replacement
+- (bool) geomAdditive;
+
+/// Construct objects related to this style based on the input data.
+- (void)buildObjects:(NSArray * _Nonnull)vecObjs
+ forTile:(MaplyVectorTileData * __nonnull)tileData
+ viewC:(NSObject<MaplyRenderControllerProtocol> * _Nonnull)viewC
+ desc:(NSDictionary * _Nullable)desc;
+
+/// Construct objects related to this style based on the input data.
+- (void)buildObjects:(NSArray * _Nonnull)vecObjs
+ forTile:(MaplyVectorTileData * __nonnull)tileData
+ viewC:(NSObject<MaplyRenderControllerProtocol> * _Nonnull)viewC
+ desc:(NSDictionary * _Nullable)desc
+ cancelFn:(bool(^__nullable)(void))cancelFn;
+
+@end
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**
+ Use a style delegate to interpret vector data.
+
+ Run the style delegate against the given vectors. The resulting features are added to the
+ given view controller using the thread mode specified.
+
+ @param vecObjs An array of MaplyVectorObject.
+
+ @param styleDelegate The style delegate that controls how the vectors will look.
+
+ @param viewC View controller to add the geometry to.
+
+ @param threadMode MaplyThreadCurrent will block until all the features are added. MaplyThreadAny will do some of the work on another thread.
+ */
+NSArray<MaplyComponentObject*> * _Nonnull AddMaplyVectorsUsingStyle(NSArray<MaplyVectorObject*> * _Nonnull vecObjs,
+ NSObject<MaplyVectorStyleDelegate> * _Nonnull styleDelegate,
+ NSObject<MaplyRenderControllerProtocol> * _Nonnull viewC,
+ MaplyThreadMode threadMode);
+
+/**
+ Use a style delegate to interpret vector data.
+
+ Run the style delegate against the given vectors. The resulting features are added to the
+ given view controller using the thread mode specified.
+
+ @param vecObjs An array of MaplyVectorObject.
+
+ @param styleDelegate The style delegate that controls how the vectors will look.
+
+ @param viewC View controller to add the geometry to.
+
+ @param tileId The tile where the feature originates.
+
+ @param enable Automatically enable the generated objects
+
+ @param threadMode MaplyThreadCurrent will block until all the features are added. MaplyThreadAny will do some of the work on another thread.
+
+ @param desc Additional attributes to include with the generated component objects
+ */
+NSArray<MaplyComponentObject*> * _Nonnull AddMaplyVectorsUsingStyleAndAttributes(
+ NSArray<MaplyVectorObject*> * _Nonnull vecObjs,
+ NSObject<MaplyVectorStyleDelegate> * _Nonnull styleDelegate,
+ NSObject<MaplyRenderControllerProtocol> * _Nonnull viewC,
+ MaplyTileID tileId,
+ bool enable,
+ MaplyThreadMode threadMode,
+ NSDictionary * _Nullable desc);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorStyleSimple.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorStyleSimple.h
new file mode 100644
index 0000000..ccb309e
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorStyleSimple.h
@@ -0,0 +1,85 @@
+/* MaplyVectorStyleSimple.m
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 3/15/16.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <WhirlyGlobe/MapboxVectorTiles.h>
+
+/**
+ Simple default style to see something in vector tile data.
+
+ A simple vector style that displays each layer in a random color.
+ Use this as a starting point for your own style.
+ */
+@interface MaplyVectorStyleSimpleGenerator : NSObject<MaplyVectorStyleDelegate>
+
+@property (nonatomic,weak) NSObject<MaplyRenderControllerProtocol> *viewC;
+
+/// Initialize with a map view controller
+- (id)initWithViewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+/// uuid for the styles
+- (long long)generateID;
+
+@end
+
+/**
+ Base class for the simple vector style.
+ */
+@interface MaplyVectorStyleSimple : NSObject<MaplyVectorStyle>
+
+/// Unique Identifier for this style
+@property (nonatomic) long long uuid;
+
+/// Set if this geometry is additive (e.g. sticks around) rather than replacement
+@property (nonatomic) bool geomAdditive;
+
+/// Priority for sorting among layers
+@property (nonatomic) int drawPriority;
+
+@property (nonatomic,weak) NSObject<MaplyRenderControllerProtocol> *viewC;
+
+- (id)initWithGen:(MaplyVectorStyleSimpleGenerator *)gen viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+@end
+
+/**
+ Simple filled polygon with a random color.
+ */
+@interface MaplyVectorStyleSimplePolygon : MaplyVectorStyleSimple
+
+@property (nonatomic,strong) UIColor *color;
+
+@end
+
+/**
+ Simple point we'll convert to a label.
+ */
+@interface MaplyVectorStyleSimplePoint : MaplyVectorStyleSimple
+
+@property (nonatomic,strong) UIFont *font;
+
+@end
+
+/**
+ Simple linear with a random color.
+ */
+@interface MaplyVectorStyleSimpleLinear : MaplyVectorStyleSimple
+
+@property (nonatomic,strong) UIColor *color;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorTileLineStyle.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorTileLineStyle.h
new file mode 100644
index 0000000..f56dd07
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorTileLineStyle.h
@@ -0,0 +1,29 @@
+/* MaplyVectorLineStyle.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 1/3/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyVectorStyle.h>
+#import <WhirlyGlobe/MaplyVectorTileStyle.h>
+
+/**
+ Implementation of the line style symbolizer for Maply Vector Tiles.
+ */
+@interface MaplyVectorTileStyleLine : MaplyVectorTileStyle
+
+- (instancetype)initWithStyleEntry:(NSDictionary *)styleEntry settings:(MaplyVectorStyleSettings *)settings viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorTileMarkerStyle.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorTileMarkerStyle.h
new file mode 100644
index 0000000..994307e
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorTileMarkerStyle.h
@@ -0,0 +1,29 @@
+/* MaplyVectorMarkerStyle.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 1/3/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyVectorStyle.h>
+#import <WhirlyGlobe/MaplyVectorTileStyle.h>
+
+/**
+ Implementation of the marker style symbolizer for Maply Vector Tiles.
+ */
+@interface MaplyVectorTileStyleMarker : MaplyVectorTileStyle
+
+- (instancetype)initWithStyleEntry:(NSDictionary *)styleEntry settings:(MaplyVectorStyleSettings *)settings viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorTilePolygonStyle.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorTilePolygonStyle.h
new file mode 100644
index 0000000..4d9d81f
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorTilePolygonStyle.h
@@ -0,0 +1,29 @@
+/* MaplyVectorPolygonStyle.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 1/3/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyVectorStyle.h>
+#import <WhirlyGlobe/MaplyVectorTileStyle.h>
+
+/**
+ Implementation of the polygon style symbolizer for Maply Vector Tiles.
+ */
+@interface MaplyVectorTileStylePolygon : MaplyVectorTileStyle
+
+- (instancetype)initWithStyleEntry:(NSDictionary *)styleEntry settings:(MaplyVectorStyleSettings *)settings viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorTileStyle.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorTileStyle.h
new file mode 100644
index 0000000..5f4eed2
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorTileStyle.h
@@ -0,0 +1,60 @@
+/* MaplyVectorTileStyle.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 1/3/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyVectorStyle.h>
+
+/** The Maply Vector Tile Style is an internal representation of the style JSON coming out
+ of a Maply Vector Tile database.
+ */
+@interface MaplyVectorTileStyle : NSObject<MaplyVectorStyle>
+
+/**
+ Construct a style entry from an NSDictionary.
+ */
++ (id)styleFromStyleEntry:(NSDictionary *)styleEntry settings:(MaplyVectorStyleSettings *)settings viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+/// Unique Identifier for this style
+@property (nonatomic) long long uuid;
+
+/// Set if this geometry is additive (e.g. sticks around) rather than replacement
+@property (nonatomic) bool geomAdditive;
+
+/// Construct a style entry from an NSDictionary
+- (instancetype)initWithStyleEntry:(NSDictionary *)styleEntry viewC:(NSObject<MaplyRenderControllerProtocol> *)viewC;
+
+/// Turn the min/maxscaledenom into height ranges for minVis/maxVis
+- (void)resolveVisibility:(NSDictionary *)styleEntry settings:(MaplyVectorStyleSettings *)settings desc:(NSMutableDictionary *)desc;
+
+/// parse a mapnik style template string
+- (NSString*)formatText:(NSString*)formatString forObject:(MaplyVectorObject*)vec;
+
+/// The view controller we're constructing objects in
+@property (nonatomic,weak) NSObject<MaplyRenderControllerProtocol> *viewC;
+
+/// If set, we create selectable objects
+/// This controls whether the objects we create are selectable. Off by default.
+@property (nonatomic) bool selectable;
+
+/// Parse the various types of color strings
++ (UIColor *) ParseColor:(NSString *)colorStr;
+
+/// Parse an RGB color and fill in the alpha
++ (UIColor *) ParseColor:(NSString *)colorStr alpha:(CGFloat)alpha;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorTileTextStyle.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorTileTextStyle.h
new file mode 100644
index 0000000..59b53c3
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVectorTileTextStyle.h
@@ -0,0 +1,29 @@
+/* MaplyVectorTextStyle.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 1/3/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyVectorStyle.h>
+#import <WhirlyGlobe/MaplyVectorTileStyle.h>
+
+/**
+ Implementation of the text style symbolizer for Maply Vector Tiles.
+ */
+@interface MaplyVectorTileStyleText : MaplyVectorTileStyle
+
+- (instancetype _Nullable)initWithStyleEntry:(NSDictionary * _Nonnull)styleEntry settings:(MaplyVectorStyleSettings * _Nonnull)settings viewC:(NSObject<MaplyRenderControllerProtocol> * _Nonnull)viewC;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVertexAttribute.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVertexAttribute.h
new file mode 100644
index 0000000..07e220a
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyVertexAttribute.h
@@ -0,0 +1,49 @@
+/*
+ * MaplyVertexAttribute.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 11/29/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+
+/**
+ Vertex Attributes are passed all the way though on objects to shaders.
+
+ If you have your own custom shader, you often need a way to feed it data. The toolkit will set up the standard data, like vertices, texture coordinates and normals, but sometimes you need something custom.
+
+ Vertex attributes are the mechanism you use to pass that custom data all the way down to the shader.
+
+ How the vertex attributes are used depends on the data type, so consult the appropriate object.
+ */
+@interface MaplyVertexAttribute : NSObject
+
+/// Construct a vertex attribute as a single float
+- (nonnull instancetype)initWithName:(NSString * __nonnull)name slot:(int)slot float:(float)val;
+
+/// Construct a vertex attribute as two floats
+- (nonnull instancetype)initWithName:(NSString * __nonnull)name slot:(int)slot floatX:(float)x y:(float)y;
+
+/// Construct a vertex attribute as three flaots
+- (nonnull instancetype)initWithName:(NSString * __nonnull)name slot:(int)slot floatX:(float)x y:(float)y z:(float)z;
+
+/// Construct a vertex attribute as an RGBA value
+- (nonnull instancetype)initWithName:(NSString * __nonnull)name slot:(int)slot color:(UIColor * __nonnull)color;
+
+/// Construct a vertex attribute as an int
+- (nonnull instancetype)initWithName:(NSString * __nonnull)name slot:(int)slot int:(int)val;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyViewController.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyViewController.h
new file mode 100644
index 0000000..c49ae41
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyViewController.h
@@ -0,0 +1,651 @@
+/* MaplyViewController.h
+ * MaplyComponent
+ *
+ * Created by Steve Gifford on 9/6/12.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyScreenMarker.h>
+#import <WhirlyGlobe/MaplyVectorObject.h>
+#import <WhirlyGlobe/MaplyViewTracker.h>
+#import <WhirlyGlobe/MaplyComponentObject.h>
+#import <WhirlyGlobe/MaplySharedAttributes.h>
+#import <WhirlyGlobe/MaplyBaseViewController.h>
+
+@class MaplyControllerLayer;
+@class MaplyViewController;
+
+
+/**
+ Animation State used by the MaplyViewControllerAnimationDelegate.
+
+ You fill out one of these when you're implementing the animation delegate. Return it and the view controller will set the respective values to match.
+ */
+@interface MaplyViewControllerAnimationState : NSObject
+
+/// Heading is calculated from due north
+/// If not set or set to MAXFLOAT, this is ignored
+@property (nonatomic) double heading;
+
+/// Height above the map
+@property (nonatomic) double height;
+
+/// Position to move to on the map
+@property (nonatomic) MaplyCoordinateD pos;
+
+/// If set, this is a point on the screen where pos should be.
+/// By default this is (-1,-1) meaning the screen position is just the middle. Otherwise, this is where the position should wind up on the screen, if it can.
+@property (nonatomic) CGPoint screenPos;
+
+/**
+ Interpolate a new state between the given states A and B.
+
+ This does a simple interpolation (lat/lon, not great circle) between the two animation states.
+ */
++ (nonnull MaplyViewControllerAnimationState *)Interpolate:(double)t from:(MaplyViewControllerAnimationState *__nonnull)stateA to:(MaplyViewControllerAnimationState *__nonnull)stateB;
+
+@end
+
+/**
+ An animation delegate that can be set on a MaplyViewController to control the view over time.
+
+ Filling out these methods will get you animation callbacks at the proper time to control position, heading and height on a frame basis.
+
+ You pass the resulting object in to
+ */
+@protocol MaplyViewControllerAnimationDelegate <NSObject>
+
+/**
+ This method is called when the animation starts.
+
+ At the animation start we collect up the various parameters of the current visual view state and pas them in via the startState. You probably want to keep track of this for later.
+
+ @param viewC The view controller doing the animation.
+
+ @param startState The starting point for the visual view animation. Cache this somewhere for your own interpolation.
+
+ @param startTime When the animation starts (e.g. now)
+
+ @param endTime When the animation ends. This is an absolute value.
+ */
+- (void)mapViewController:(MaplyViewController *__nonnull)viewC startState:(MaplyViewControllerAnimationState *__nonnull)startState startTime:(NSTimeInterval)startTime endTime:(NSTimeInterval)endTime;
+
+/**
+ This method is called at the beginning of every frame draw to position the viewer.
+
+ This is the method that does all the work. You need to fill out the returned MaplyViewControllerAnimationState according to whatever interpolation your'e doing based on the currentTime.
+
+ @param viewC The view controller doing the animation.
+
+ @param currentTime The time for this frame. Use this rather than calculating the time yourself.
+
+ @return The MaplyViewControllerAnimationState expressing where you want the viewer to be and where they are looking.
+ */
+- (nonnull MaplyViewControllerAnimationState *)mapViewController:(MaplyViewController *__nonnull)viewC stateForTime:(NSTimeInterval)currentTime;
+
+@optional
+
+/**
+ This method is called at the end of the animation.
+
+ The map view controller calls this method when the animation is finished. Do your cleanup here if need be.
+
+ @param viewC The map view controller.
+ */
+- (void)mapViewControllerDidFinishAnimation:(MaplyViewController *__nonnull)viewC;
+
+@end
+
+/**
+ A simple animation delegate for moving the map around.
+
+ The animation delegate support provides a lot of flexibility. This version just provides all the standard fields and interpolates from beginning to end.
+ */
+@interface MaplyViewControllerSimpleAnimationDelegate : NSObject <MaplyViewControllerAnimationDelegate>
+
+/// Initialize with an animation state to copy
+- (nonnull instancetype)initWithState:(MaplyViewControllerAnimationState *__nonnull)endState;
+
+/// Location at the end of the animation
+@property (nonatomic) MaplyCoordinateD loc;
+
+/// Heading at the end of the animation
+@property (nonatomic) double heading;
+
+/// Height at the end of the animation
+@property (nonatomic) double height;
+
+/// Custom easing
+@property (readwrite,copy) ZoomEasingBlock _Nullable zoomEasing;
+
+@end
+
+/**
+ A protocol to fill out for selection and tap messages from the MaplyViewController.
+
+ Fill out the protocol when you want to get back selection and tap messages. All the methods are optional.
+ */
+@protocol MaplyViewControllerDelegate <NSObject>
+
+@optional
+
+/**
+ Called when the user taps on or near an object.
+
+ You're given the object you passed in originally, such as a MaplyScreenMarker. You can set a userObject on most of these to put your own data in there for tracking.
+ */
+- (void)maplyViewController:(MaplyViewController *__nonnull)viewC didSelect:(NSObject *__nonnull)selectedObj;
+
+/**
+ User selected a given object and tapped at a given location.
+
+ This is called when the user selects an object. It differs from maplyViewController:didSelect: in that it passes on the location (in the local coordinate system) and the position on screen.
+
+ @param viewC View Controller that saw the selection.
+
+ @param selectedObj The object selected. Probably one of MaplyVectorObject or MaplyScreenLabel or so on.
+
+ @param coord Location in the local coordinate system where the user tapped.
+
+ @param screenPt Location on screen where the user tapped.
+ */
+- (void)maplyViewController:(MaplyViewController *__nonnull)viewC didSelect:(NSObject *__nonnull)selectedObj atLoc:(MaplyCoordinate)coord onScreen:(CGPoint)screenPt;
+
+/**
+ User selected one or more objects at a given location.
+
+ @param viewC View Controller that saw the selection(s).
+
+ @param selectedObjs The object(s) selected. Probably one of MaplyVectorObject or MaplyScreenLabel or so on.
+
+ @param coord Location in the local coordinate system where the user tapped.
+
+ @param screenPt Location on screen where the user tapped.
+ */
+- (void)maplyViewController:(MaplyViewController *__nonnull)viewC allSelect:(NSArray *__nonnull)selectedObjs atLoc:(MaplyCoordinate)coord onScreen:(CGPoint)screenPt;
+
+/**
+ User tapped at a given location.
+
+ This is a tap at a specific location on the map. This won't be called if they tapped and selected, just for taps.
+ */
+- (void)maplyViewController:(MaplyViewController *__nonnull)viewC didTapAt:(MaplyCoordinate)coord;
+
+/**
+ Called when the map starts moving.
+
+ @param viewC The map view controller.
+
+ @param userMotion Set if this is motion being caused by the user, rather than a call to set location.
+
+ This is called when something (probably the user) starts moving the map.
+ */
+- (void)maplyViewControllerDidStartMoving:(MaplyViewController *__nonnull)viewC userMotion:(bool)userMotion;
+
+/**
+ Called when the map stops moving.
+
+ This is called when the map stops moving. It passes in the corners of the current viewspace.
+
+ @param viewC The globe view controller.
+
+ @param userMotion Set if this is motion being caused by the user, rather than a call to set location.
+
+ @param corners An array of length 4 containing the corners of the view space (lower left, lower right, upper right, upper left). If any of those corners does not intersect the map (think zoomed out), its values are set to MAXFLOAT.
+ */
+- (void)maplyViewController:(MaplyViewController *__nonnull)viewC didStopMoving:(MaplyCoordinate *__nonnull)corners userMotion:(bool)userMotion;
+
+/**
+ Called whenever the viewpoint moves.
+
+ This is called whenever the viewpoint moves. That includes user motion as well as animations.
+
+ It may be triggered as often as every frame. If that's a problem, use one of the other variants.
+
+ @param viewC The map view controller.
+
+ @param corners An array of length 4 containing the corners of the view space (lower left, lower right, upper right, upper left). If any of those corners does not intersect the globe (think zoomed out), its values are set to MAXFLOAT.
+ */
+- (void)maplyViewController:(MaplyViewController *__nonnull)viewC didMove:(MaplyCoordinate *__nonnull)corners;
+
+
+/**
+ Called when the user taps on one of your annotations.
+
+ This is called when the user taps on an annotation.
+
+ @param annotation Which annotation they tapped on.
+ */
+- (void)maplyViewController:(MaplyViewController *__nonnull)viewC didTapAnnotation:(MaplyAnnotation*__nonnull)annotation;
+
+/// Old version for compatibility. Use tap instead.
+- (void)maplyViewController:(MaplyViewController *__nonnull)viewC didClickAnnotation:(MaplyAnnotation*__nonnull)annotation __deprecated;
+
+@end
+
+
+typedef NS_ENUM(NSInteger, MaplyMapType) {
+ MaplyMapType3D,
+ MaplyMapTypeFlat,
+};
+
+/**
+ This view controller implements a map.
+
+ This is the main entry point for displaying a 2D or 3D map. Create one of these, fill it with data and let your users mess around with it.
+
+ You can display a variety of features on the map, including tile base maps (MaplyQuadImageTilesLayer), vectors (MaplyVectorObject), shapes (MaplyShape), and others. Check out the add calls in the MaplyBaseViewController for details.
+
+ The Maply View Controller can be initialized in 3D map, 2D map mode. The 2D mode can be tethered to a UIScrollView if you want to handle gestures that way. That mode is very specific at the moment.
+
+ To get selection and tap callbacks, fill out the MaplyViewControllerDelegate and assign the delegate.
+
+ Most of the functionality is shared with MaplyBaseViewController. Be sure to look in there first.
+ */
+@interface MaplyViewController : MaplyBaseViewController
+
+/// Initialize as a flat or 3D map.
+- (nonnull instancetype)initWithMapType:(MaplyMapType)mapType;
+
+/// Initialize as a 2D map.
+- (nonnull instancetype)init;
+
+/// Set the coordinate system to use in display.
+/// The coordinate system needs to be valid in flat mode. The extents, if present, will be used to define the coordinate system origin.
+/// nil is the default and will result in a full web style Spherical Mercator.
+@property(nonatomic,strong) MaplyCoordinateSystem *__nullable coordSys;
+
+/**
+ Set the center of the display coordinate system.
+
+ This is (0,0,0) by default. If you set it to something else all display coordinates will be offset from that origin.
+
+ The option is useful when displaying small maps (of a city, say) at very high resolution.
+ */
+@property(nonatomic) MaplyCoordinate3d displayCenter;
+
+/**
+ Turn the pinch (zoom) gesture recognizer on and off
+
+ On by default.
+ */
+@property(nonatomic,assign) bool pinchGesture;
+
+/**
+ Turn the rotate gesture recognizer on and off
+
+ On by default.
+ */
+@property(nonatomic,assign) bool rotateGesture;
+
+/**
+ Turn the pan gesture on and off
+
+ Pan gesture is on by default
+ */
+@property(nonatomic,assign) bool panGesture;
+
+/**
+ Turn the double tap to zoom gesture recognizer on and off
+
+ On by default.
+ */
+@property(nonatomic,assign) bool doubleTapZoomGesture;
+
+/**
+ Turn the 2 finger tap to zoom out gesture recognizer on and off
+
+ On by default.
+ */
+@property(nonatomic,assign) bool twoFingerTapGesture;
+
+/**
+ Turn on the double tap and drag gesture to zoom in and out.
+
+ On by default.
+ */
+@property(nonatomic,assign) bool doubleTapDragGesture;
+
+/**
+ If set, we use a modified pan gesture recognizer to play nice
+ with the scroll view. For the UIScrollView object, set clipsToBounds,
+ pagingEnabled, and delaysContentTouches to YES, and set scrollEnabled
+ and canCancelContentTouches to NO. Add swipe gesture recognizers
+ to the scroll view to control paging, and call
+ requirePanGestureRecognizerToFailForGesture: for each.
+
+ Off by default.
+ */
+@property(nonatomic,assign) bool inScrollView;
+
+/**
+ turn the touch to cancel animation gesture on and off
+
+ off by default
+ */
+@property(nonatomic,assign) bool cancelAnimationOnTouch;
+
+/**
+ The current rotation away from north.
+ */
+@property(nonatomic,assign) float heading;
+
+/**
+ The minimum angle, in degrees, which a rotate gesture must subtend before rotation begins.
+ i.e., larger values are "stickier"
+ default is zero, causing rotation to begin immediately
+ */
+@property(nonatomic,assign) float rotateGestureThreshold;
+
+/**
+ If set, we'll automatically move to wherever the user tapped.
+
+ When on we'll move the current location to wherever the user tapped if they tapped the globe. That's true for selection as well. On by default.
+ */
+@property(nonatomic,assign) bool autoMoveToTap;
+
+/**
+ Delegate for selection and location tapping.
+
+ Fill in the MaplyViewControllerDelegate and assign it here to get callbacks for object selection and tapping.
+ */
+@property(nonatomic,weak) NSObject<MaplyViewControllerDelegate> *__nullable delegate;
+
+/**
+ Current height above terrain.
+
+ In 3D map mode this is the height from which the user is viewing the map. Maps are usually -PI to +PI along their horizontal edges.
+ */
+@property (nonatomic,assign) float height;
+
+/**
+ 2D visual views can do some simple wrapping. This turns that on and off (off by default).
+
+ On some 2D visual views we're allowed to wrap across the edge of the world. This will attempt to do that.
+ */
+@property (nonatomic,assign) bool viewWrap;
+
+/**
+ The box the view point can be in.
+
+ This is the box the view point is allowed to be within. The view controller will constrain it to be within that box. Coordinates are in geographic (radians).
+ */
+- (MaplyBoundingBox)getViewExtents;
+
+/**
+ The box the view point can be in.
+
+ This is the box the view point is allowed to be within. The view controller will constrain it to be within that box. Coordinates are in geographic (radians).
+ */
+- (void)getViewExtentsLL:(MaplyCoordinate *__nonnull)ll ur:(MaplyCoordinate *__nonnull)ur;
+
+/**
+ The box the view point can be in.
+
+ This is the box the view point is allowed to be within. The view controller will constrain it to be within that box. Coordinates are in geographic (radians).
+ */
+- (void)setViewExtents:(MaplyBoundingBox)box;
+
+/**
+ The box the view point can be in.
+
+ This is the box the view point is allowed to be within. The view controller will constrain it to be within that box. Coordinates are in geographic (radians).
+ */
+- (void)setViewExtentsLL:(MaplyCoordinate)ll ur:(MaplyCoordinate)ur;
+
+/**
+ Animate to the given position over time.
+
+ @param newPos A coordinate in geographic (lon/lat radians)
+
+ @param howLong A time in seconds.
+ */
+- (void)animateToPosition:(MaplyCoordinate)newPos time:(NSTimeInterval)howLong;
+
+/**
+ Animate the given position to the screen position over time.
+
+ This is similar to animateToPosition:time: except that it will attempt to match up the screen position and the geographic position. This is how you offset the location you're looking at.
+
+ If it's impossible to move newPos to loc, then nothing happens.
+
+ @param newPos The geographic position (lon/lat in radians) to move to.
+
+ @param loc The location on the screen where we'd like it to go.
+
+ @param howLong How long in seconds to take getting there.
+ */
+- (bool)animateToPosition:(MaplyCoordinate)newPos onScreen:(CGPoint)loc time:(NSTimeInterval)howLong;
+
+/**
+ Animate the given position and height to the screen position over time.
+
+ This is similar to animateToPosition:time: but it also takes a height paramater
+
+ @param newPos The geographic position (lon/lat in radians) to move to.
+
+ @param newHeight the view point height above the map.
+
+ @param howLong How long in seconds to take getting there.
+ */
+- (void)animateToPosition:(MaplyCoordinate)newPos height:(float)newHeight time:(NSTimeInterval)howLong;
+
+/**
+ Animate to the given position, heading and height over time.
+
+ @param newPos A coordinate in geographic (lon/lat radians)
+
+ @param newHeight New height to animate to.
+
+ @param newHeading New heading to finish on.
+
+ @param howLong A time interval in seconds.
+ */
+- (bool)animateToPosition:(MaplyCoordinate)newPos height:(float)newHeight heading:(float)newHeading time:(NSTimeInterval)howLong;
+
+/**
+ Animate to the given position, heading and height over time.
+
+ @param newPos A coordinate in geographic (lon/lat radians) (double precision)
+
+ @param newHeight New height to animate to. (double)
+
+ @param newHeading New heading to finish on. (double)
+
+ @param howLong A time interval in seconds.
+ */
+- (bool)animateToPositionD:(MaplyCoordinateD)newPos height:(double)newHeight heading:(double)newHeading time:(NSTimeInterval)howLong;
+
+/**
+ Animate to the given position, screen position, heading and height over time.
+
+ If it's impossible to move newPos to loc, then nothing happens.
+
+ @param newPos A coordinate in geographic (lon/lat radians)
+
+ @param loc The location on the screen where we'd like it to go.
+
+ @param newHeight New height to animate to.
+
+ @param newHeading New heading to finish on.
+
+ @param howLong A time interval in seconds.
+ */
+- (bool)animateToPosition:(MaplyCoordinate)newPos onScreen:(CGPoint)loc height:(float)newHeight heading:(float)newHeading time:(NSTimeInterval)howLong;
+
+/**
+ Set the center of the screen to the given position immediately.
+
+ @param newPos The geographic position (lon/lat in radians) to move to.
+ */
+- (void)setPosition:(MaplyCoordinate)newPos;
+
+/**
+ Set the center of the screen and the height offset immediately.
+
+ @param newPos The geographic position (lon/lat in radians) to move to.
+
+ @param height Height the view point above the map.
+ */
+- (void)setPosition:(MaplyCoordinate)newPos height:(float)height;
+
+/**
+ Return the current center position
+ */
+- (MaplyCoordinate)getPosition;
+
+/**
+ Return the current view point's height above the map.
+ */
+- (float)getHeight;
+
+/**
+ Return the current center position and height.
+
+ @param pos The center of the screen in geographic (lon/lat in radians).
+
+ @param height The current view point's height above the map.
+ */
+- (void)getPosition:(MaplyCoordinate *__nonnull)pos height:(float *__nonnull)height;
+
+
+/**
+ Set the viewing state all at once
+
+ This sets the position, height, screen position and heading all at once.
+ */
+- (void)setViewState:(MaplyViewControllerAnimationState *__nonnull)viewState;
+
+/**
+ Make a MaplyViewControllerAnimationState object from the current view state.
+
+ This returns the current view parameters in a single MaplyViewControllerAnimationState.
+ */
+- (nullable MaplyViewControllerAnimationState *)getViewState;
+
+/**
+ Return the closest a viewer is allowed to get to the map surface.
+
+ @return FLT_MIN if there's no pitchDelegate set
+ */
+- (float)getMinZoom;
+
+/**
+ Return the farthest away a viewer is allowed to get from the map surface
+
+ @return FLT_MIN if there's no pitchDelegate set
+ */
+- (float)getMaxZoom;
+
+/**
+ Return the zoom limits for 3D map mode.
+
+ @param minHeight The closest a viewer is allowed to get to the map surface.
+
+ @param maxHeight The farthest away a viewer is allowed to get from the map surface.
+ */
+- (void)getZoomLimitsMin:(float *__nonnull)minHeight max:(float *__nonnull)maxHeight;
+
+/**
+ Set the zoom limits for 3D map mode.
+
+ @param minHeight The closest a viewer is allowed to get to the map surface.
+
+ @param maxHeight The farthest away a viewer is allowed to get from the map surface.
+ */
+- (void)setZoomLimitsMin:(float)minHeight max:(float)maxHeight;
+
+/**
+ Return the geographic (lon/lat radians) coordinate in radians for a given screen point.
+
+ @return Returns the geo coordinate corresponding to a given screen point in radians.
+ */
+- (MaplyCoordinate)geoFromScreenPoint:(CGPoint)point;
+
+/**
+ Find a height that shows the given bounding box.
+
+ This method will search for a height that shows the given bounding box within the view. The search is inefficient, so don't call this a lot.
+
+ @param bbox The bounding box (in radians) we're trying to view.
+
+ @param pos Where the view will be looking.
+ */
+- (float)findHeightToViewBounds:(MaplyBoundingBox)bbox
+ pos:(MaplyCoordinate)pos;
+
+/**
+ Find a height that shows the given bounding box.
+ This method will search for a height that shows the given bounding box within the view. The search is inefficient, so don't call this a lot.
+
+ This version takes a margin to add around the outside of the area. Positive margins increase the screen area considered, making the
+ given area larger. Negative margins make the specified area smaller.
+
+ @param bbox The bounding box (in radians) we're trying to view.
+ @param pos Where the view will be looking.
+ @param marginX Horizontal boundary around the area
+ @param marginY Vertical boundary around the area
+ */
+- (float)findHeightToViewBounds:(MaplyBoundingBox)bbox
+ pos:(MaplyCoordinate)pos
+ marginX:(double)marginX
+ marginY:(double)marginY;
+
+/**
+ Find a height that shows the given bounding box.
+ This method will search for a height that shows the given bounding box within the view. The search is inefficient, so don't call this a lot.
+
+ This version takes a margin to add around the outside of the area. Positive margins increase the screen area considered, making the
+ given area larger. Negative margins make the specified area smaller.
+
+ This version attempts to place the given bounds within a rectangle other than the whole view frame.
+
+ @param bbox The bounding box (in radians) we're trying to view.
+ @param pos Where the view will be looking.
+ @param frame The screen area to consider.
+ @param newPos (out,optional) The center location needed to place \c pos at the center of \c frame
+ @param marginX Horizontal boundary around the area
+ @param marginY Vertical boundary around the area
+ */
+- (float)findHeightToViewBounds:(MaplyBoundingBox)bbox
+ pos:(MaplyCoordinate)pos
+ frame:(CGRect)frame
+ newPos:(MaplyCoordinate *_Nullable)newPos
+ marginX:(double)marginX
+ marginY:(double)marginY;
+
+/**
+
+ Return the extents of the current view
+
+ @return Returns the Bounding Box (in radians) corresponding to the current view
+ */
+- (MaplyBoundingBox)getCurrentExtents;
+
+/**
+
+ Make a gesture recognizer's success depend on the pan gesture
+ recognizer's failure.
+
+ When using the map view within a scroll view, add swipe gesture
+ recognizers to the scroll view to control paging, and call this method
+ for each. See also the inScrollView property and its comment.
+
+ @param other The other, subordinate gesture recognizer.
+ */
+- (void)requirePanGestureRecognizerToFailForGesture:(UIGestureRecognizer *__nullable)other;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyViewTracker.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyViewTracker.h
new file mode 100644
index 0000000..9317c00
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyViewTracker.h
@@ -0,0 +1,68 @@
+/*
+ * WGViewTracker.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 7/26/12.
+ * Copyright 2012-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+/**
+ The View Tracker associates a view with a geographic location.
+
+ The Maply View Tracker will move a UIView around to keep track of a geographic location. This is basically used for popups. The system will move the view around at the end of the frame render. It will hide the UIView if needed or make it reappear. The UIView should be a child of view controller's view.
+ */
+@interface MaplyViewTracker : NSObject
+
+/**
+ The UIView we want moved around.
+
+ This is the UIView we'll tie to the geographic location. If you want to center it, use offsets within the UIView.
+ */
+@property (nonatomic,strong) UIView *__nullable view;
+
+/**
+ The geographic location where we want to place the UIView.
+
+ This is the location (lon/lat in radians) where we want to stick the UIView. The location on screen will be updated as the user manipulates the map or globe.
+ */
+@property (nonatomic,assign) MaplyCoordinate loc;
+
+/**
+ An offset in screen space for the view tracker.
+
+ This offset is added to the location after it's projected into screen space.
+ */
+@property (nonatomic, assign) CGPoint offset;
+
+/**
+ The lowest height at which we'll see the view tracker.
+
+ This value is in display coordinates.
+ */
+@property (nonatomic,assign) float minVis;
+
+/**
+ the maximum height at which we'll see the view being tracked.
+
+ This value is in display coordinates.
+ */
+@property (nonatomic,assign) float maxVis;
+
+@end
+
+typedef MaplyViewTracker WGViewTracker;
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyWMSTileSource.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyWMSTileSource.h
new file mode 100644
index 0000000..4b9d317
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyWMSTileSource.h
@@ -0,0 +1,183 @@
+/* MaplyWMSTileSource.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 7/25/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+
+/** A bounding box for a specific CRS in that coordinate
+ system. This is part of the Web Map Server parser.
+ */
+@interface MaplyWMSLayerBoundingBox : NSObject
+
+/// Coordinate Reference System
+@property (nonatomic,strong,nullable) NSString *crs;
+
+/// Left side of the bounding box
+@property (nonatomic) double minx;
+/// Bottom of the bounding box
+@property (nonatomic) double miny;
+/// Right side of the bounding box
+@property (nonatomic) double maxx;
+/// Top of the bounding box
+@property (nonatomic) double maxy;
+
+/// Generate the coordinate system, if we can
+- (nullable MaplyCoordinateSystem *)buildCoordinateSystem;
+
+@end
+
+/** Style of a WMS layer as returned by GetCapabilities.
+ This is part of the Web Map Service parser.
+ */
+@interface MaplyWMSStyle : NSObject
+
+/// The name as returned by the service
+@property (nonatomic,strong,nullable) NSString *name;
+/// The title as returned by the service
+@property (nonatomic,strong,nullable) NSString *title;
+
+@end
+
+/** Description of a WMS layer as returned by a GetCapabilities call.
+ This is part of the Web Map Service parser.
+ */
+@interface MaplyWMSLayer : NSObject
+
+/// The name as returned by the service
+@property (nonatomic,strong,nullable) NSString *name;
+/// The title as returned by the service
+@property (nonatomic,strong,nullable) NSString *title;
+/// The abstract as returned by the service
+@property (nonatomic,strong,nullable) NSString *abstract;
+
+/// Coordinate reference systems supported by the layer
+@property (nonatomic,strong,nullable) NSArray *coordRefSystems;
+
+/// Styles we can choose
+@property (nonatomic,strong,nullable) NSArray *styles;
+
+/// Bounding boxes for zero or more of the CRS'
+@property (nonatomic,strong,nullable) NSArray *boundingBoxes;
+
+/// Lower left corner in longitude/latitude
+@property (nonatomic) MaplyCoordinate ll;
+/// Upper right corner in longitude/latitude
+@property (nonatomic) MaplyCoordinate ur;
+
+/// Try to build a coordinate system we understand
+- (nullable MaplyCoordinateSystem *)buildCoordSystem;
+
+/// Find the style with the given name
+- (nullable MaplyWMSStyle *)findStyle:(NSString *__nonnull)styleName;
+
+@end
+
+@class DDXMLDocument;
+
+/** Encapsulates the capabilities coming back from a WMS server.
+ We can query this to see what layers and coordinate systems are available.
+ Part of the Web Map Service parser.
+ */
+@interface MaplyWMSCapabilities : NSObject
+
+/// We can fetch the capabilities from this URL
++ (nonnull NSString *)CapabilitiesURLFor:(NSString *__nonnull)baseURL;
+
+/// The name as returned by the service
+@property (nonatomic,strong,nullable) NSString *name;
+/// The title as returned by the service
+@property (nonatomic,strong,nullable) NSString *title;
+
+/// Available formats (strings)
+@property (nonatomic,strong,nullable) NSArray *formats;
+
+/// Layers we can fetch from
+@property (nonatomic,strong,nullable) NSArray *layers;
+
+/// This constructor will initialize with an XML document that
+/// we've fetched from the server, presumably.
+- (nullable instancetype)initWithXML:(DDXMLDocument *__nonnull)xmlDoc;
+
+/// Look for a layer with the given name.
+- (nullable MaplyWMSLayer *)findLayer:(NSString *__nonnull)name;
+
+@end
+
+/** This is a MaplyTileSource that works with a remote
+ Web Map Service implementation. WMS is not the most
+ efficient way to access remote image data, but there
+ are still a few places that use it.
+ */
+@interface MaplyWMSTileSource : NSObject<MaplyTileInfoNew>
+
+/// Base URL for the Map Service
+@property (nonatomic,strong,nullable) NSString *baseURL;
+
+/// Capabilities describing the service
+@property (nonatomic,strong,nullable) MaplyWMSCapabilities *capabilities;
+
+/// Image type to request
+@property (nonatomic,strong,nullable) NSString *imageType;
+
+/// Layer we're grabbing
+@property (nonatomic,strong,nonnull) MaplyWMSLayer *layer;
+
+/// Optional style we're using
+@property (nonatomic,strong,nonnull) MaplyWMSStyle *style;
+
+/// Minimum zoom level we'll expect
+@property (nonatomic,readonly) int minZoom;
+/// Maximum zoom level we'll expect
+@property (nonatomic,readonly) int maxZoom;
+
+/// Tile size provided to caller
+@property (nonatomic,readonly) int tileSize;
+
+/// If set we'll ask for a transparent background from the server
+@property (nonatomic) bool transparent;
+
+/// Coordinate system (used to build URLs)
+@property (nonatomic,readonly,nonnull) MaplyCoordinateSystem *coordSys;
+
+/// If set, we'll cache the images locally (a good idea with WMS)
+@property (nonatomic,strong,nullable) NSString *cacheDir;
+
+/** Initialize with the parameters the WMS server is going to want.
+
+ @param baseURL The main URL we'll use to construct queries.
+
+ @param cap The capabilities as parsed from the service.
+
+ @param layer The layer we'll access. There can be multiple and it's
+ up to you to pick one.
+
+ @param style The style variant of the layer we want. Again there can
+ be multiple and it's up to you to pick.
+
+ @param coordSys The coordinate system we're expecting to work in.
+
+ @param minZoom The min zoom level we want. Note that WMS doesn't handle
+ this directly. Our tile source just controls what areas it
+ asks for based on the overall extents and the zoom levels.
+
+ @param maxZoom The max zoom level we'll query.
+ */
+- (nullable instancetype)initWithBaseURL:(NSString *__nonnull)baseURL capabilities:(MaplyWMSCapabilities *__nullable)cap layer:(MaplyWMSLayer *__nonnull)layer style:(MaplyWMSStyle *__nonnull)style coordSys:(MaplyCoordinateSystem *__nonnull)coordSys minZoom:(int)minZoom maxZoom:(int)maxZoom tileSize:(int)tileSize;
+
+@end
+
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyZoomGestureDelegate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyZoomGestureDelegate.h
new file mode 100644
index 0000000..442a976
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MaplyZoomGestureDelegate.h
@@ -0,0 +1,31 @@
+/* MaplyZoomGestureDelegate.h
+ *
+ * Created by Jesse Crocker on 2/4/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <UIKit/UIKit.h>
+
+@interface MaplyZoomGestureDelegate : NSObject <UIGestureRecognizerDelegate>
+
+/// Minimum allowable zoom level
+@property (nonatomic,assign) float minZoom;
+/// Maximum allowable zoom level
+
+@property (nonatomic,assign) float maxZoom;
+
+//The gesture recognizer
+@property (nonatomic,strong) UIGestureRecognizer *gestureRecognizer;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapnikStyle.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapnikStyle.h
new file mode 100644
index 0000000..22e4cf0
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapnikStyle.h
@@ -0,0 +1,33 @@
+/*
+ * MapnikStyle.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Jesse Crocker, Trailbehind inc. on 3/31/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+#import <WhirlyGlobe/MapnikStyleRule.h>
+
+@interface MapnikStyle : NSObject
+
+@property (nonatomic, readonly) NSMutableArray *rules;
+@property (nonatomic, strong) NSString *name;
+@property (nonatomic, assign) BOOL filterModeFirst;
+@property (nonatomic, assign) float opacity;
+
+- (void)addRule:(MapnikStyleRule*)rule;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapnikStyleRule.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapnikStyleRule.h
new file mode 100644
index 0000000..f462857
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapnikStyleRule.h
@@ -0,0 +1,36 @@
+/*
+ * MapnikStyleRule.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Jesse Crocker, Trailbehind inc. on 3/31/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+@interface MapnikStyleRule : NSObject
+
+@property (nonatomic, strong) NSPredicate *filterPredicate;
+
+@property (nonatomic, assign) NSUInteger minScaleDenominator;
+@property (nonatomic, assign) NSUInteger maxScaleDenomitator;
+@property (nonatomic, assign) NSUInteger minZoom;
+@property (nonatomic, assign) NSUInteger maxZoom;
+
+@property (nonatomic, readonly) NSMutableArray *symbolizers;
+
+- (void)setFilter:(NSString*)filterExpression;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapnikStyleSet.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapnikStyleSet.h
new file mode 100644
index 0000000..86c54e7
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/MapnikStyleSet.h
@@ -0,0 +1,47 @@
+/*
+ * MapnikXmlStyle.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Jesse Crocker, Trailbehind inc. on 3/31/14.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#import <Foundation/Foundation.h>
+#import <WhirlyGlobe/MapboxVectorTiles.h>
+
+@class MaplyVectorStyleSettings;
+
+@interface MapnikStyleSet : NSObject <NSXMLParserDelegate, MaplyVectorStyleDelegate>
+
+@property (nonatomic, strong, nullable) MaplyVectorStyleSettings *tileStyleSettings;
+@property (nonatomic, strong, nullable) NSMutableDictionary *styleDictionary;
+@property (nonatomic, weak, nullable) NSObject<MaplyRenderControllerProtocol> *viewC;
+@property (nonatomic, readonly) BOOL parsing;
+@property (nonatomic, strong, nullable) UIColor *backgroundColor;
+@property (nonatomic, assign) NSInteger tileMaxZoom;
+@property (nonatomic, assign) NSInteger drawPriorityOffset;
+@property (nonatomic, assign) CGFloat alpha;
+
+- (nonnull instancetype)initForViewC:(NSObject<MaplyRenderControllerProtocol> *__nonnull)viewC;
+
+- (void)loadXmlFile:(NSString *__nonnull)filePath;
+- (void)loadXmlData:(NSData *__nonnull)docData;
+- (void)loadJsonData:(NSData *__nonnull)jsonData;
+- (void)loadJsonFile:(NSString*__nonnull)filePath;
+- (void)saveAsJSON:(NSString *__nonnull)filePath;
+- (void)generateStyles;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/NSData+Zlib.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/NSData+Zlib.h
new file mode 100644
index 0000000..4a28f18
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/NSData+Zlib.h
@@ -0,0 +1,37 @@
+/*
+ * NSData+Zlib.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 9/7/13.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+/** The NSData zlib category adds compress and uncompress methods to
+ NSData.
+ */
+@interface NSData(zlib)
+
+/// Return a compressed version of the data.
+- (NSData *) compressData;
+
+/// Return an uncompressed verison of the given data
+- (NSData *) uncompressGZip;
+
+/// Returns true if the data is zlib compressed
+- (BOOL)isCompressed;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/NSDictionary+StyleRules.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/NSDictionary+StyleRules.h
new file mode 100644
index 0000000..9c4ab96
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/NSDictionary+StyleRules.h
@@ -0,0 +1,33 @@
+//
+// NSDictionary+StyleRules.h
+// WhirlyGlobe-MaplyComponent
+//
+// Created by Jesse Crocker on 4/9/14.
+//
+//
+
+#import <Foundation/Foundation.h>
+
+@interface NSMutableDictionary (StyleRules)
+
+- (NSMutableArray*)styles;
+- (NSMutableArray*)rules;
+- (NSMutableArray*)symbolizers;
+- (NSMutableArray*)layers;
+- (NSString*)filter;
+- (void)setFilter:(NSString*)filter;
+- (NSString*)name;
+
+- (NSNumber*)minScaleDenom;
+- (void)setMinScaleDenom:(NSNumber*)num;
+- (NSNumber*)maxScaleDenom;
+- (void)setMaxScaleDenom:(NSNumber*)num;
+- (NSMutableDictionary*)parameters;
+
+@end
+
+// A function we can call to force the linker to bring in categories
+#ifdef __cplusplus
+extern "C"
+#endif
+void NSDictionaryStyleDummyFunc(void);
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/SLDExpressions.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/SLDExpressions.h
new file mode 100644
index 0000000..43a042d
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/SLDExpressions.h
@@ -0,0 +1,55 @@
+//
+// SLDExpressions.h
+// SLDTest
+//
+// Created by Ranen Ghosh on 2016-08-12.
+// Copyright 2016-2019 mousebird consulting.
+//
+
+#import <Foundation/Foundation.h>
+@class DDXMLNode;
+@class DDXMLElement;
+
+/** @brief Base class for elements derived from the ogc:expression abstract element.
+ @see http://schemas.opengis.net/filter/1.1.0/expr.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/filter/1.0.0/expr.xsd for SLD v1.0.0
+ */
+@interface SLDExpression : NSObject
+@property (nonatomic, strong) NSExpression * _Nonnull expression;
++ (BOOL)matchesElementNamed:(NSString * _Nonnull)elementName;
++ (SLDExpression * _Nullable)expressionForNode:(DDXMLNode * _Nonnull )node;
+@end
+
+
+/** @brief Class corresponding to the ogc:PropertyName element
+ @see http://schemas.opengis.net/filter/1.1.0/expr.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/filter/1.0.0/expr.xsd for SLD v1.0.0
+ */
+@interface SLDPropertyNameExpression : SLDExpression
+@property (nonatomic, strong) NSString * _Nonnull propertyName;
+- (_Nullable id)initWithElement:(DDXMLElement * _Nonnull)element;
+@end
+
+/** @brief Class corresponding to the ogc:Literal element
+ @see http://schemas.opengis.net/filter/1.1.0/expr.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/filter/1.0.0/expr.xsd for SLD v1.0.0
+ */
+@interface SLDLiteralExpression : SLDExpression
+@property (nonatomic, strong) id _Nonnull literal;
+- (_Nullable id)initWithElement:(DDXMLElement * _Nonnull)element;
+@end
+
+/** @brief Class corresponding to the ogc:BinaryOperatorType elements
+ @see http://schemas.opengis.net/filter/1.1.0/expr.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/filter/1.0.0/expr.xsd for SLD v1.0.0
+ */
+@interface SLDBinaryOperatorExpression : SLDExpression
+
+@property (nonatomic, strong) NSString * _Nonnull elementName;
+
+@property (nonatomic, strong) SLDExpression * _Nonnull leftExpression;
+@property (nonatomic, strong) SLDExpression * _Nonnull rightExpression;
+
+- (_Nullable id)initWithElement:(DDXMLElement * _Nonnull)element;
+@end
+
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/SLDOperators.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/SLDOperators.h
new file mode 100644
index 0000000..746695e
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/SLDOperators.h
@@ -0,0 +1,101 @@
+//
+// SLDOperators.h
+// SLDTest
+//
+// Created by Ranen Ghosh on 2016-08-12.
+// Copyright 2016-2019 mousebird consulting.
+//
+
+#import <Foundation/Foundation.h>
+#import <WhirlyGlobe/SLDExpressions.h>
+
+/** @brief Base class for elements of ogc:comparisonOps or ogc:logicOps.
+
+ Elements of ogc:spatialOps are not supported.
+ @see http://schemas.opengis.net/filter/1.1.0/filter.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/filter/1.0.0/filter.xsd for SLD v1.0.0
+ */
+@interface SLDOperator : NSObject
+@property (nonatomic, strong) NSPredicate * _Nonnull predicate;
++ (BOOL)matchesElementNamed:(NSString * _Nonnull)elementName;
++ (SLDOperator * _Nullable)operatorForNode:(DDXMLNode * _Nonnull )node;
+@end
+
+
+/** @brief Class corresponding to the ogc:BinaryComparisonOpType elements
+ @see http://schemas.opengis.net/filter/1.1.0/expr.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/filter/1.0.0/expr.xsd for SLD v1.0.0
+ */
+@interface SLDBinaryComparisonOperator : SLDOperator
+
+@property (nonatomic, assign) BOOL matchCase;
+@property (nonatomic, strong) NSString * _Nonnull elementName;
+
+@property (nonatomic, strong) SLDExpression * _Nonnull leftExpression;
+@property (nonatomic, strong) SLDExpression * _Nonnull rightExpression;
+
+
+- (_Nullable id)initWithElement:(DDXMLElement * _Nonnull)element;
+
+@end
+
+
+@interface SLDIsNullOperator : SLDOperator
+
+@property (nonatomic, strong) SLDExpression * _Nonnull subExpression;
+
+- (_Nullable id)initWithElement:(DDXMLElement * _Nonnull)element;
+
+@end
+
+
+@interface SLDIsLikeOperator : SLDOperator
+
+@property (nonatomic, strong, nullable) NSString *wildCardStr;
+@property (nonatomic, strong, nullable) NSString *singleCharStr;
+@property (nonatomic, strong, nullable) NSString *escapeCharStr;
+@property (nonatomic, assign) BOOL matchCase;
+@property (nonatomic, strong) SLDPropertyNameExpression * _Nonnull propertyExpression;
+@property (nonatomic, strong) SLDLiteralExpression * _Nonnull literalExpression;
+
+- (_Nullable id)initWithElement:(DDXMLElement * _Nonnull)element;
+
+@end
+
+@interface SLDIsBetweenOperator : SLDOperator
+
+@property (nonatomic, strong) SLDExpression * _Nonnull subExpression;
+@property (nonatomic, strong) SLDExpression * _Nonnull lowerBoundaryExpression;
+@property (nonatomic, strong) SLDExpression * _Nonnull upperBoundaryExpression;
+
+- (_Nullable id)initWithElement:(DDXMLElement * _Nonnull)element;
+
+@end
+
+
+
+/** @brief Class corresponding to the ogc:Not element
+ @see http://schemas.opengis.net/filter/1.1.0/expr.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/filter/1.0.0/expr.xsd for SLD v1.0.0
+ */
+@interface SLDNotOperator : SLDOperator
+
+@property (nonatomic, strong) SLDOperator * _Nonnull subOperator;
+
+- (_Nullable id)initWithElement:(DDXMLElement * _Nonnull)element;
+
+@end
+
+/** @brief Class corresponding to the ogc:BinaryLogicOpType elements
+ @see http://schemas.opengis.net/filter/1.1.0/expr.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/filter/1.0.0/expr.xsd for SLD v1.0.0
+ */
+@interface SLDLogicalOperator : SLDOperator
+
+@property (nonatomic, strong) NSString * _Nonnull elementName;
+@property (nonatomic, strong) NSArray<SLDOperator *> * _Nonnull subOperators;
+
+- (_Nullable id)initWithElement:(DDXMLElement * _Nonnull)element;
+
+@end
+
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/SLDStyleSet.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/SLDStyleSet.h
new file mode 100644
index 0000000..4e705cf
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/SLDStyleSet.h
@@ -0,0 +1,119 @@
+//
+// SLDStyleSet.h
+// SLDTest
+//
+// Created by Ranen Ghosh on 2016-08-12.
+// Copyright 2016-2019 mousebird consulting.
+//
+
+#import <Foundation/Foundation.h>
+#import <WhirlyGlobe/MapboxVectorTiles.h>
+
+/** @brief Class corresponding to the sld:NamedLayer element
+ @see http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+ */
+@interface SLDNamedLayer : NSObject
+
+@property (nonatomic, strong) NSString * _Nullable name;
+@property (nonatomic, strong) NSArray * _Nullable userStyles;
+
+@end
+
+/** @brief Class corresponding to the sld:UserStyle element
+ @see http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+ */
+@interface SLDUserStyle : NSObject
+
+@property (nonatomic, strong) NSString * _Nullable name;
+@property (nonatomic, strong) NSArray * _Nullable featureTypeStyles;
+
+@end
+
+/** @brief Class corresponding to the se:FeatureTypeStyle element
+ @see http://schemas.opengis.net/se/1.1.0/FeatureStyle.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+ */
+@interface SLDFeatureTypeStyle : NSObject
+
+@property (nonatomic, strong) NSArray * _Nullable rules;
+
+@end
+
+/** @brief Class corresponding to the se:Rule element
+ @see http://schemas.opengis.net/se/1.1.0/FeatureStyle.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+ */
+@interface SLDRule : NSObject
+
+@property (nonatomic, strong) NSArray * _Nullable filters;
+@property (nonatomic, strong) NSArray * _Nullable elseFilters;
+
+@property (nonatomic, strong) NSNumber * _Nullable minScaleDenominator;
+@property (nonatomic, strong) NSNumber * _Nullable maxScaleDenominator;
+@property (nonatomic, strong) NSNumber * _Nullable relativeDrawPriority;
+
+@property (nonatomic, strong) NSMutableArray * _Nullable symbolizers;
+
+@end
+
+
+
+@class SLDOperator;
+@class SLDExpression;
+
+/** @brief Class corresponding to the ogc:Filter element
+ @see http://schemas.opengis.net/filter/1.1.0/filter.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/filter/1.0.0/filter.xsd for SLD v1.0.0
+ */
+@interface SLDFilter : NSObject
+
+@property (nonatomic, strong) SLDOperator * _Nonnull sldOperator;
+
+@end
+
+/** @brief Class corresponding to the sld:StyledLayerDescriptor element
+
+ The sld:StyledLayerDescriptor element is the root element of the Styled Layer Descriptor document.
+
+ Implements the MaplyVectorStyleDelegate protocol for matching and applying styles to vector objects.
+ @see http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+ @see MaplyVectorStyleDelegate
+ */
+@interface SLDStyleSet : NSObject <MaplyVectorStyleDelegate>
+
+@property (nonatomic, assign) BOOL useLayerNames;
+@property (nonatomic, weak, nullable) NSObject<MaplyRenderControllerProtocol> *viewC;
+@property (nonatomic, strong, nullable) MaplyVectorStyleSettings *tileStyleSettings;
+
+/**
+ Constructs a SLDStyleSet object.
+
+ After constructing the SLDStyleSet object, call loadSldURL: or loadSldData:baseURL: to parse the desired SLD document tree and create the corresponding symbolizers.
+
+ @param viewC The map or globe view controller.
+
+ @param useLayerNames Whether to use names of NamedLayer elements as a criteria in matching styles.
+
+ @param relativeDrawPriority The z-order relative to other vector features. This will be incremented internally for each style rule, so if you have multiple SLDStyleSets, leave some space between the relativeDrawPriority of each.
+ */
+- (id _Nullable)initWithViewC:(NSObject<MaplyRenderControllerProtocol> * _Nonnull)viewC useLayerNames:(BOOL)useLayerNames relativeDrawPriority:(int)relativeDrawPriority;
+
+- (void)loadSldURL:(NSURL *__nullable)url;
+- (void)loadSldData:(NSData *__nonnull)sldData baseURL:(NSURL *__nonnull)baseURL;
+
+@end
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/SLDSymbolizers.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/SLDSymbolizers.h
new file mode 100644
index 0000000..78e2acb
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/SLDSymbolizers.h
@@ -0,0 +1,82 @@
+//
+// SLDSymbolizers.h
+// SLDTest
+//
+// Created by Ranen Ghosh on 2016-08-12.
+// Copyright 2016-2019 mousebird consulting.
+//
+
+#import <Foundation/Foundation.h>
+@class DDXMLNode;
+@class DDXMLElement;
+#import <WhirlyGlobe/MaplyVectorTileStyle.h>
+
+/** @brief Base class for Symbolizer elements
+ @see http://schemas.opengis.net/se/1.1.0/Symbolizer.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+ */
+@interface SLDSymbolizer : NSObject
+
+/**
+ Returns whether this class can parse the symbolizer corresponding to the provided element name.
+
+ Each subclass matches different symbolizer elements.
+ */
++ (BOOL)matchesSymbolizerNamed:(NSString * _Nonnull)symbolizerName;
+
+/**
+ Produces MaplyVectorTileStyle objects for an SLD Symbolizer element
+
+ Parses the XML subtree and returns an array of corresponding MaplyVectorTileStyle objects.
+
+ @param element The XML element corresponding to a symbolizer
+
+ @param tileStyleSettings The base MaplyVectorStyleSettings settings to apply.
+
+ @param viewC The map or globe view controller.
+
+ @param minScaleDenom If non-null, the minimum map scale at which to apply any constructed symbolizer.
+
+ @param maxScaleDenom If non-null, the maximum map scale at which to apply any constructed symbolizer.
+
+ @param relativeDrawPriority The z-order relative to other vector features.
+
+ @param baseURL The base URL from which external resources (e.g. images) will be located.
+
+ @return An array of MaplyVectorTileStyle objects corresponding to the particular XML element.
+ @see MaplyVectorTileStyle
+ @see MaplyVectorStyleSettings
+ */
++ (NSArray<MaplyVectorTileStyle *> * _Nullable) maplyVectorTileStyleWithElement:(DDXMLElement * _Nonnull)element tileStyleSettings:(MaplyVectorStyleSettings * _Nonnull)tileStyleSettings viewC:(NSObject<MaplyRenderControllerProtocol> * _Nonnull)viewC minScaleDenom:(NSNumber * _Nonnull)minScaleDenom maxScaleDenom:(NSNumber * _Nonnull)maxScaleDenom relativeDrawPriority:(int)relativeDrawPriority crossSymbolizerParams:(NSMutableDictionary * _Nonnull)crossSymbolizerParams baseURL:(NSURL * _Nonnull)baseURL;
+@end
+
+/** @brief Class corresponding to the LineSymbolizer element
+ @see http://schemas.opengis.net/se/1.1.0/Symbolizer.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+ */
+@interface SLDLineSymbolizer : SLDSymbolizer
+@end
+
+/** @brief Class corresponding to the PolygonSymbolizer element
+ @see http://schemas.opengis.net/se/1.1.0/Symbolizer.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+ */
+@interface SLDPolygonSymbolizer : SLDSymbolizer
+@end
+
+/** @brief Class corresponding to the PointSymbolizer element
+ @see http://schemas.opengis.net/se/1.1.0/Symbolizer.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+ */
+@interface SLDPointSymbolizer : SLDSymbolizer
+@end
+
+/** @brief Class corresponding to the TextSymbolizer element
+ @see http://schemas.opengis.net/se/1.1.0/Symbolizer.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+ */
+@interface SLDTextSymbolizer : SLDSymbolizer
+@end
+
+
+
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/SLDWellKnownMarkers.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/SLDWellKnownMarkers.h
new file mode 100644
index 0000000..cdb4cc8
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/SLDWellKnownMarkers.h
@@ -0,0 +1,23 @@
+//
+// SLDWellKnownMarkers.h
+// SLDTest
+//
+// Created by Ranen Ghosh on 2016-08-23.
+// Copyright 2016-2019 mousebird consulting.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+/**
+ Class for generating images corresponding to WellKnownName elements.
+
+ Each static method uses low-level Core Graphics calls to generate an appropriate UIImage object.
+ @see http://schemas.opengis.net/se/1.1.0/Symbolizer.xsd for SLD v1.1.0
+ @see http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd for SLD v1.0.0
+*/
+@interface SLDWellKnownMarkers : NSObject
+
++ (UIImage *)imageWithName:(NSString *)wellKnownName strokeColor:(UIColor *)strokeColor fillColor:(UIColor *)fillColor size:(int)size;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/WGCoordinate.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/WGCoordinate.h
new file mode 100644
index 0000000..8b79f7b
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/WGCoordinate.h
@@ -0,0 +1,34 @@
+/*
+ * WGCoordinate.h
+ * WhirlyGlobe-MaplyComponent
+ *
+ * Created by Steve Gifford on 9/17/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyCoordinate.h>
+
+/// WhirlyGlobe just takes geo coordinates.
+/// This contains lon and lat values in the x and y fields.
+typedef MaplyCoordinate WGCoordinate;
+
+/// Construct a WGCoordinate with longitude and latitude values in degrees
+#if __cplusplus
+extern "C" {
+#endif
+ WGCoordinate WGCoordinateMakeWithDegrees(float degLon,float degLat);
+#if __cplusplus
+}
+#endif
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/WhirlyGlobe.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/WhirlyGlobe.h
new file mode 100644
index 0000000..4fc8123
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/WhirlyGlobe.h
@@ -0,0 +1,121 @@
+//
+// WhirlyGlobeMaplyComponent.h
+// WhirlyGlobeMaplyComponent
+//
+// Created by Steve Gifford on 6/29/16.
+// Copyright © 2016-2019 mousebird consulting.
+//
+
+#import <UIKit/UIKit.h>
+
+//! Project version number for WhirlyGlobeMaplyComponent.
+FOUNDATION_EXPORT double WhirlyGlobeMaplyComponentVersionNumber;
+
+//! Project version string for WhirlyGlobeMaplyComponent.
+FOUNDATION_EXPORT const unsigned char WhirlyGlobeMaplyComponentVersionString[];
+
+// In this header, you should import all the public headers of your framework using statements like #import <WhirlyGlobeMaplyComponent/PublicHeader.h>
+
+#import <WhirlyGlobe/GeographicLib_ObjC.h>
+#import <WhirlyGlobe/GeoJSONSource.h>
+#import <WhirlyGlobe/GlobeDoubleTapDelegate.h>
+#import <WhirlyGlobe/GlobeDoubleTapDragDelegate.h>
+#import <WhirlyGlobe/GlobePanDelegate.h>
+#import <WhirlyGlobe/GlobePinchDelegate.h>
+#import <WhirlyGlobe/GlobeRotateDelegate.h>
+#import <WhirlyGlobe/GlobeTapDelegate.h>
+#import <WhirlyGlobe/GlobeTiltDelegate.h>
+#import <WhirlyGlobe/GlobeTwoFingerTapDelegate.h>
+#import <WhirlyGlobe/MapboxVectorInterpreter.h>
+#import <WhirlyGlobe/MapboxVectorStyleSet.h>
+#import <WhirlyGlobe/MapboxVectorTiles.h>
+#import <WhirlyGlobe/Maply3DTouchPreviewDatasource.h>
+#import <WhirlyGlobe/Maply3dTouchPreviewDelegate.h>
+#import <WhirlyGlobe/MaplyActiveObject.h>
+#import <WhirlyGlobe/MaplyAnnotation.h>
+#import <WhirlyGlobe/MaplyAtmosphere.h>
+#import <WhirlyGlobe/MaplyBaseViewController.h>
+#import <WhirlyGlobe/MaplyBillboard.h>
+#import <WhirlyGlobe/MaplyBridge.h>
+#import <WhirlyGlobe/MaplyBridge.h>
+#import <WhirlyGlobe/MaplyCluster.h>
+#import <WhirlyGlobe/MaplyColorRampGenerator.h>
+#import <WhirlyGlobe/MaplyComponent.h>
+#import <WhirlyGlobe/MaplyComponent.h>
+#import <WhirlyGlobe/MaplyComponentObject.h>
+#import <WhirlyGlobe/MaplyControllerLayer.h>
+#import <WhirlyGlobe/MaplyCoordinate.h>
+#import <WhirlyGlobe/MaplyCoordinateSystem.h>
+#import <WhirlyGlobe/MaplyDoubleTapDelegate.h>
+#import <WhirlyGlobe/MaplyDoubleTapDragDelegate.h>
+#import <WhirlyGlobe/MaplyGeomBuilder.h>
+#import <WhirlyGlobe/MaplyGeomModel.h>
+#import <WhirlyGlobe/MaplyGlobeRenderController.h>
+#import <WhirlyGlobe/MaplyIconManager.h>
+#import <WhirlyGlobe/MaplyImageTile.h>
+#import <WhirlyGlobe/MaplyLabel.h>
+#import <WhirlyGlobe/MaplyLight.h>
+#import <WhirlyGlobe/MaplyLocationTracker.h>
+#import <WhirlyGlobe/MaplyMarker.h>
+#import <WhirlyGlobe/MaplyMatrix.h>
+#import <WhirlyGlobe/MaplyMBTileFetcher.h>
+#import <WhirlyGlobe/MaplyMoon.h>
+#import <WhirlyGlobe/MaplyPanDelegate.h>
+#import <WhirlyGlobe/MaplyParticleSystem.h>
+#import <WhirlyGlobe/MaplyPinchDelegate.h>
+#import <WhirlyGlobe/MaplyPoints.h>
+#import <WhirlyGlobe/MaplyQuadImageFrameLoader.h>
+#import <WhirlyGlobe/MaplyQuadImageLoader.h>
+#import <WhirlyGlobe/MaplyQuadLoader.h>
+#import <WhirlyGlobe/MaplyQuadPagingLoader.h>
+#import <WhirlyGlobe/MaplyQuadSampler.h>
+#import <WhirlyGlobe/MaplyRemoteTileFetcher.h>
+#import <WhirlyGlobe/MaplyRenderController.h>
+#import <WhirlyGlobe/MaplyRenderTarget.h>
+#import <WhirlyGlobe/MaplyRotateDelegate.h>
+#import <WhirlyGlobe/MaplyScreenLabel.h>
+#import <WhirlyGlobe/MaplyScreenMarker.h>
+#import <WhirlyGlobe/MaplyScreenObject.h>
+#import <WhirlyGlobe/MaplyShader.h>
+#import <WhirlyGlobe/MaplyShape.h>
+#import <WhirlyGlobe/MaplySharedAttributes.h>
+#import <WhirlyGlobe/MaplySimpleTileFetcher.h>
+#import <WhirlyGlobe/MaplyStarsModel.h>
+#import <WhirlyGlobe/MaplySticker.h>
+#import <WhirlyGlobe/MaplySun.h>
+#import <WhirlyGlobe/MaplyTapDelegate.h>
+#import <WhirlyGlobe/MaplyTapMessage.h>
+#import <WhirlyGlobe/MaplyTexture.h>
+#import <WhirlyGlobe/MaplyTextureBuilder.h>
+#import <WhirlyGlobe/MaplyTileSourceNew.h>
+#import <WhirlyGlobe/MaplyTouchCancelAnimationDelegate.h>
+#import <WhirlyGlobe/MaplyTwoFingerTapDelegate.h>
+#import <WhirlyGlobe/MaplyUpdateLayer.h>
+#import <WhirlyGlobe/MaplyVariableTarget.h>
+#import <WhirlyGlobe/MaplyVectorObject.h>
+#import <WhirlyGlobe/MaplyVectorStyle.h>
+#import <WhirlyGlobe/MaplyVectorStyleSimple.h>
+#import <WhirlyGlobe/MaplyVectorTileLineStyle.h>
+#import <WhirlyGlobe/MaplyVectorTileMarkerStyle.h>
+#import <WhirlyGlobe/MaplyVectorTilePolygonStyle.h>
+#import <WhirlyGlobe/MaplyVectorTileStyle.h>
+#import <WhirlyGlobe/MaplyVectorTileTextStyle.h>
+#import <WhirlyGlobe/MaplyVertexAttribute.h>
+#import <WhirlyGlobe/MaplyViewController.h>
+#import <WhirlyGlobe/MaplyViewTracker.h>
+#import <WhirlyGlobe/MaplyWMSTileSource.h>
+#import <WhirlyGlobe/MaplyZoomGestureDelegate.h>
+#import <WhirlyGlobe/MapnikStyle.h>
+#import <WhirlyGlobe/MapnikStyleRule.h>
+#import <WhirlyGlobe/MapnikStyleSet.h>
+#import <WhirlyGlobe/NSData+Zlib.h>
+#import <WhirlyGlobe/NSDictionary+StyleRules.h>
+#import <WhirlyGlobe/SLDExpressions.h>
+#import <WhirlyGlobe/SLDOperators.h>
+#import <WhirlyGlobe/SLDStyleSet.h>
+#import <WhirlyGlobe/SLDSymbolizers.h>
+#import <WhirlyGlobe/SLDWellKnownMarkers.h>
+#import <WhirlyGlobe/WGCoordinate.h>
+#import <WhirlyGlobe/WhirlyGlobeComponent.h>
+#import <WhirlyGlobe/WhirlyGlobeComponent.h>
+#import <WhirlyGlobe/WhirlyGlobeViewController.h>
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/WhirlyGlobeComponent.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/WhirlyGlobeComponent.h
new file mode 100644
index 0000000..babfdf7
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/WhirlyGlobeComponent.h
@@ -0,0 +1,23 @@
+/*
+ * WhirlyGlobeComponent.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 7/21/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <WhirlyGlobe/MaplyComponent.h>
+#import <WhirlyGlobe/MaplyGlobeRenderController.h>
+#import <WhirlyGlobe/WhirlyGlobeViewController.h>
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/WhirlyGlobeViewController.h b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/WhirlyGlobeViewController.h
new file mode 100644
index 0000000..f2e3b82
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Headers/WhirlyGlobeViewController.h
@@ -0,0 +1,809 @@
+/*
+ * WhirlyGlobeViewController.h
+ * WhirlyGlobeComponent
+ *
+ * Created by Steve Gifford on 7/21/12.
+ * Copyright 2011-2022 mousebird consulting
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <WhirlyGlobe/MaplyGlobeRenderController.h>
+#import <WhirlyGlobe/MaplyBaseViewController.h>
+
+@class WGViewControllerLayer;
+@class WhirlyGlobeViewController;
+
+/**
+ An animation delegate that can be set on a WhirlyGlobeViewController to control the view over time.
+
+ Filling out these methods will get you animation callbacks at the proper time to control position, heading, tilt, and height on a frame basis.
+
+ You pass the resulting object in to
+ */
+@protocol WhirlyGlobeViewControllerAnimationDelegate <NSObject>
+
+/**
+ This method is called when the animation starts.
+
+ At the animation start we collect up the various parameters of the current visual view state and pas them in via the startState. You probably want to keep track of this for later.
+
+ @param viewC The view controller doing the animation.
+
+ @param startState The starting point for the visual view animation. Cache this somewhere for your own interpolation.
+
+ @param startTime When the animation starts (e.g. now)
+
+ @param endTime When the animation ends. This is an absolute value.
+ */
+- (void)globeViewController:(WhirlyGlobeViewController *__nonnull)viewC startState:(WhirlyGlobeViewControllerAnimationState *__nonnull)startState startTime:(NSTimeInterval)startTime endTime:(NSTimeInterval)endTime;
+
+/**
+ This method is called at the beginning of every frame draw to position the viewer.
+
+ This is the method that does all the work. You need to fill out the returned WhirlyGlobeViewControllerAnimationState according to whatever interpolation your'e doing based on the currentTime.
+
+ @param viewC The view controller doing the animation.
+
+ @param currentTime The time for this frame. Use this rather than calculating the time yourself.
+
+ @return The WhirlyGlobeViewControllerAnimationState expressing where you want the viewer to be and where they are looking.
+ */
+- (nonnull WhirlyGlobeViewControllerAnimationState *)globeViewController:(WhirlyGlobeViewController *__nonnull)viewC stateForTime:(NSTimeInterval)currentTime;
+
+@optional
+
+/**
+ This method is called at the end of the animation.
+
+ The globe view controller calls this method when the animation is finished. Do your cleanup here if need be.
+
+ @param viewC The globe view controller.
+ */
+- (void)globeViewControllerDidFinishAnimation:(WhirlyGlobeViewController *__nonnull)viewC;
+
+@end
+
+/**
+ A simple animation delegate for moving the globe around.
+
+ The animation delegate support provides a lot of flexibility. This version just provides all the standard fields and interpolates from beginning to end.
+ */
+@interface WhirlyGlobeViewControllerSimpleAnimationDelegate : NSObject <WhirlyGlobeViewControllerAnimationDelegate>
+
+/// Initialize with an animation state to copy
+- (nonnull instancetype)initWithState:(WhirlyGlobeViewControllerAnimationState *__nonnull)endState;
+
+/// Location at the end of the animation
+@property (nonatomic) MaplyCoordinateD loc;
+
+/// Heading at the end of the animation
+@property (nonatomic) double heading;
+
+/// Height at the end of the animation
+@property (nonatomic) double height;
+
+/// Tilt at the end of the animation
+@property (nonatomic) double tilt;
+
+/// Roll at the end of the animation
+@property (nonatomic) double roll;
+
+/// Globe center at the end of the animation
+@property (nonatomic) CGPoint globeCenter;
+
+/// Custom easing
+@property (readwrite,copy) ZoomEasingBlock _Nullable zoomEasing;
+
+@end
+
+/**
+ Globe View Controller Delegate protocol for getting back selection and tap events.
+
+ Fill out the methods in this protocol and assign yourself as a delegate in the WhirlyGlobeViewController to get selection and tap events.
+ */
+@protocol WhirlyGlobeViewControllerDelegate <NSObject>
+
+@optional
+/**
+ Called when the user taps on or near an object.
+
+ You're given the object you passed in originally, such as a MaplyScreenMarker. Most of those objects have userObject properties, which is a good place to stash your own data.
+
+ @param viewC The view controller where the user selected something.
+
+ @param selectedObj The Maply object they selected.
+ */
+- (void)globeViewController:(WhirlyGlobeViewController *__nonnull)viewC didSelect:(NSObject *__nonnull)selectedObj;
+
+/**
+ Called when the user taps on or near an object.
+
+ This will call back with the closest object it finds near (or on) where the user tapped.
+
+ You're given the object you passed in originally, such as a MaplyScreenMarker.
+
+ This version is called preferentially if it exists. Otherwise globeViewController:didSelect: is called if it exists.
+
+ @param viewC The view controller where the user selected something.
+
+ @param selectedObj The Maply object they selected.
+
+ @param coord The location (geographic lon/lat in radians) where the user tapped.
+
+ @param screenPt The location on screen where the user tapped.
+ */
+- (void)globeViewController:(WhirlyGlobeViewController *__nonnull)viewC didSelect:(NSObject *__nonnull)selectedObj atLoc:(MaplyCoordinate)coord onScreen:(CGPoint)screenPt;
+
+/**
+ Called when the user taps on or near one or more objects. Returns them all.
+
+ This method is called when the
+
+ @param viewC The view controller where the user selected something.
+
+ @param selectedObjs A list of
+
+ @param coord The location (geographic lon/lat in radians) where the user tapped.
+
+ @param screenPt The location on screen where the user tapped.
+ */
+- (void)globeViewController:(WhirlyGlobeViewController *__nonnull)viewC allSelect:(NSArray *__nonnull)selectedObjs atLoc:(MaplyCoordinate)coord onScreen:(CGPoint)screenPt;
+
+/**
+ Called when the user taps outside the globe.
+ */
+- (void)globeViewControllerDidTapOutside:(WhirlyGlobeViewController *__nonnull)viewC;
+
+/**
+ Called when the user taps the globe but doesn't select anything.
+
+ @param viewC The view controller where the user selected something.
+
+ @param coord The location (geographic lon/lat in radians) where the user tapped.
+ */
+- (void)globeViewController:(WhirlyGlobeViewController *__nonnull)viewC didTapAt:(MaplyCoordinate)coord;
+
+/**
+ This is an older method called when some layers load.
+
+ Certain image layers call this method when they finish loading. More modern layers don't, so don't rely on this.
+ */
+- (void)globeViewController:(WhirlyGlobeViewController *__nonnull)viewC layerDidLoad:(WGViewControllerLayer *__nonnull)layer;
+
+/**
+ Called when the globe starts moving.
+
+ @param viewC The globe view controller.
+
+ @param userMotion Set if this is motion being caused by the user, rather than a call to set location.
+
+ This is called when something (probably the user) starts moving the globe.
+ */
+- (void)globeViewControllerDidStartMoving:(WhirlyGlobeViewController *__nonnull)viewC userMotion:(bool)userMotion;
+
+/**
+ Called when the globe stops moving.
+
+ This is called when the globe stops moving. It passes in the corners of the current viewspace.
+
+ @param viewC The globe view controller.
+
+ @param userMotion Set if this is motion being caused by the user, rather than a call to set location.
+
+ @param corners An array of length 4 containing the corners of the view space (lower left, lower right, upper right, upper left). If any of those corners does not intersect the globe (think zoomed out), its values are set to MAXFLOAT.
+ */
+- (void)globeViewController:(WhirlyGlobeViewController *__nonnull)viewC didStopMoving:(MaplyCoordinate *__nonnull)corners userMotion:(bool)userMotion;
+
+/**
+ Called when an animation that knows where it's going to stop start ups.
+
+ This is called when we know where the globe will stop. It passes in the corners of that future viewspace.
+
+ @param viewC The globe view controller.
+
+ @param corners An array of length 4 containing the corners of the view space (lower left, lower right, upper right, upper left). If any of those corners does not intersect the globe (think zoomed out), its values are set to MAXFLOAT.
+
+ @param userMotion Set if this is motion being caused by the user, rather than a call to set location.
+ */
+- (void)globeViewController:(WhirlyGlobeViewController *__nonnull)viewC willStopMoving:(MaplyCoordinate *__nonnull)corners userMotion:(bool)userMotion;
+
+/**
+ Called whenever the viewpoint moves.
+
+ This is called whenever the viewpoint moves. That includes user motion as well as animations.
+
+ It may be triggered as often as every frame. If that's a problem, use the globeViewController:didStopMoving:userMotion: or globeViewController:willStopMoving:userMotion: calls.
+
+ @param viewC The globe view controller.
+
+ @param corners An array of length 4 containing the corners of the view space (lower left, lower right, upper right, upper left). If any of those corners does not intersect the globe (think zoomed out), its values are set to MAXFLOAT.
+ */
+- (void)globeViewController:(WhirlyGlobeViewController *__nonnull)viewC didMove:(MaplyCoordinate *__nonnull)corners;
+
+@end
+
+/**
+ This view controller implements a 3D interactive globe.
+
+ This is the main entry point for displaying a globe. Create one of these, fill it with data and let your users mess around with it.
+
+ You can display a variety of features on the globe, including tiled base maps (MaplyQuadImageTilesLayer), vectors (MaplyVectorObject), shapes (MaplyShape), and others. Check out the add calls in the MaplyBaseViewController for details.
+
+ To get selection and tap callbacks, fill out the WhirlyGlobeViewControllerDelegate and assign the delegate.
+
+ Most of the functionality is shared with MaplyBaseViewController. Be sure to look in there first.
+ */
+@interface WhirlyGlobeViewController : MaplyBaseViewController
+
+/**
+ If set, keep north facing upward on the screen as the user moves around.
+
+ Off by default.
+ */
+@property(nonatomic,assign) bool keepNorthUp;
+
+/**
+ Turn the pan gesture recognizer on and off
+
+ On by default.
+ */
+@property(nonatomic,assign) bool panGesture;
+
+/**
+ Turn the pinch (zoom) gesture recognizer on and off
+
+ On by default.
+ */
+@property(nonatomic,assign) bool pinchGesture;
+
+/**
+ Turn the rotate globe functionality for pinch gesture gesture recognizer on and off
+
+ On by default.
+ */
+@property(nonatomic,assign) bool zoomAroundPinch;
+
+/**
+ Turn the rotate gesture recognizer on and off
+
+ On by default.
+ */
+@property(nonatomic,assign) bool rotateGesture;
+
+/**
+ Turn the tilt gesture recognizer on and off
+
+ Off by default.
+ */
+@property(nonatomic,assign) bool tiltGesture;
+
+/**
+ Turn the double tap to zoom gesture recognizer on and off
+
+ On by default.
+ */
+@property(nonatomic,assign) bool doubleTapZoomGesture;
+
+/**
+ Turn the 2 finger tap to zoom out gesture recognizer on and off
+
+ On by default.
+ */
+@property(nonatomic,assign) bool twoFingerTapGesture;
+
+/**
+ Turn on the double tap and drag gesture to zoom in and out.
+
+ On by default.
+ */
+@property(nonatomic,assign) bool doubleTapDragGesture;
+
+/**
+ If set, we use a modified pan gesture recognizer to play nice
+ with the scroll view. For the UIScrollView object, set clipsToBounds,
+ pagingEnabled, and delaysContentTouches to YES, and set scrollEnabled
+ and canCancelContentTouches to NO. Add swipe gesture recognizers
+ to the scroll view to control paging, and call
+ requirePanGestureRecognizerToFailForGesture: for each.
+
+ Off by default.
+ */
+@property(nonatomic,assign) bool inScrollView;
+
+
+/**
+ If set, we'll automatically move to wherever the user tapped.
+
+ When on we'll move the current location to wherever the user tapped if they tapped the globe. That's true for selection as well. On by default.
+ */
+@property(nonatomic,assign) bool autoMoveToTap;
+
+/**
+ Delegate for the selection and tap events.
+
+ Fill in the WhirlyGlobeViewControllerDelegate protocol, assign the object here and you'll get selection and tap events.
+ */
+@property(nonatomic,weak,nullable) NSObject<WhirlyGlobeViewControllerDelegate> *delegate;
+
+/**
+ Current viewer height above terrain.
+
+ This is the height from with the viewer is viewing the globe. Values range from minHeight to maxHeight. Smaller is closer. See getZoomLimitsMin:max: for values. The display units are based on a globe with a radius of 1.0.
+ */
+@property (nonatomic,assign) float height;
+
+/**
+ Tilt in radians. 0 is looking straight down (the default). PI/2 is looking toward the horizon.
+ */
+@property(nonatomic,assign) float tilt;
+
+/**
+ If set, the globe will be centered to this point on the screen.
+ */
+@property(nonatomic,assign) CGPoint globeCenter;
+
+/**
+ The current rotation away from north.
+
+ If keepNorthUp is set this is always 0.
+ */
+@property(nonatomic,assign) float heading;
+
+/**
+ The current roll around the axis pointed out of the user's nose.
+ */
+@property (nonatomic,assign) double roll;
+
+/**
+ Returns the closest a viewer is allowed to get to the map surface.
+
+ @return FLT_MIN if there's no pinchDelegate set
+ */
+- (float)getZoomLimitsMin;
+
+/**
+ Returns the farthest away a viewer is allowed to get from the map surface
+
+ @return FLT_MIN if there's no pinchDelegate set
+ */
+- (float)getZoomLimitsMax;
+
+/**
+ Return the zoom limits for the globe.
+
+ @param minHeight The closest a viewer is allowed to get to the globe surface.
+
+ @param maxHeight The farthest away a viewer is allowed to get from the globe surface.
+ */
+- (void)getZoomLimitsMin:(float *__nonnull)minHeight max:(float *__nonnull)maxHeight;
+
+/**
+ Set the zoom limits for the globe.
+
+ @param minHeight The closest a viewer is allowed to get to the globe surface.
+
+ @param maxHeight The farthest away a viewer is allowed to get from the globe surface.
+ */
+- (void)setZoomLimitsMin:(float)minHeight max:(float)maxHeight;
+
+/**
+ How much we zoom in or out by when the user double taps or two finger taps.
+
+ This sets the factor we'll use to zoom in by (e.g. *2.0) when the user double taps. It also sets how much we zoom out by when the user two finger taps. This will only have an effect if those gestures are active.
+ */
+@property (nonatomic) float zoomTapFactor;
+
+/**
+ How long we take to zoom in or out when the user double taps or two finger taps.
+
+ This controls the duration of the zoom animation. You can set it to zero to avoid the animation entirely.
+ */
+@property (nonatomic) float zoomTapAnimationDuration;
+
+/**
+ Reset the far clipping plane.
+
+ This is advanced functionality. Make sure you actually need to do this before you do it.
+
+ The far clipping plane is usually set to something like 4.0.
+ */
+- (void)setFarClipPlane:(double)farClipPlane;
+
+/**
+ Set the simplified tilt mode. We'll tilt toward the horizon as the user gets closer to the ground.
+
+ This implements a simplified mode for tilting. As the user gets closer to the ground we tilt more toward the horizon.
+
+ @param minHeight The minimum height corresponding to minTilt.
+
+ @param maxHeight The height at which to start interoplating tilt.
+
+ @param minTilt The most tilt toward the horizon. Invoked when the user is at minHeight or below.
+
+ @param maxTilt The tilt at the maximum height and over. The tilt will never be less than this, so typically 0.
+ */
+- (void)setTiltMinHeight:(float)minHeight maxHeight:(float)maxHeight minTilt:(float)minTilt maxTilt:(float)maxTilt;
+
+/// Turn off the varying tilt set up by setTiltMinHeight:maxHeight:minTilt:maxTilt:
+- (void)clearTiltHeight;
+
+/**
+ Turn on autorotate to rotate by the given amount every second.
+
+ This turns on an auto-rotate mode. The globe will start rotating after a delay by the given number of degrees per second. Very pleasant.
+
+ @param autoRotateInterval Wait this number of seconds after user interaction to auto rotate.
+
+ @param autoRotateDegrees Rotate this number of degrees (not radians) per second.
+ */
+- (void)setAutoRotateInterval:(float)autoRotateInterval degrees:(float)autoRotateDegrees;
+
+/**
+ Animate to the given position over time.
+
+ @param newPos A coordinate in geographic (lon/lat radians)
+
+ @param howLong A time interval in seconds.
+ */
+- (void)animateToPosition:(MaplyCoordinate)newPos time:(NSTimeInterval)howLong;
+
+/**
+ Animate the given position to the screen position over time.
+
+ This is similar to animateToPosition:time: except that it will attempt to match up the screen position and the geographic position. This is how you offset the location you're looking at.
+
+ If it's impossible to move newPos to loc, then nothing happens.
+
+ @param newPos The geographic position (lon/lat in radians) to move to.
+
+ @param loc The location on the screen where we'd like it to go.
+
+ @param howLong How long in seconds to take getting there.
+ */
+- (bool)animateToPosition:(MaplyCoordinate)newPos onScreen:(CGPoint)loc time:(NSTimeInterval)howLong;
+
+/**
+ Animate to the given position, heading and height over time.
+
+ @param newPos A coordinate in geographic (lon/lat radians)
+
+ @param newHeight New height to animate to.
+
+ @param newHeading New heading to finish on.
+
+ @param howLong A time interval in seconds.
+ */
+- (bool)animateToPosition:(MaplyCoordinate)newPos height:(float)newHeight heading:(float)newHeading time:(NSTimeInterval)howLong;
+
+/**
+ Animate to the given position, heading and height over time.
+
+ @param newPos A coordinate in geographic (lon/lat radians) (double precision)
+
+ @param newHeight New height to animate to. (double)
+
+ @param newHeading New heading to finish on. (double)
+
+ @param howLong A time interval in seconds.
+ */
+- (bool)animateToPositionD:(MaplyCoordinateD)newPos height:(double)newHeight heading:(double)newHeading time:(NSTimeInterval)howLong;
+
+/**
+ Animate to the given position, screen position, heading and height over time.
+
+ If it's impossible to move newPos to loc, then nothing happens.
+
+ @param newPos A coordinate in geographic (lon/lat radians)
+
+ @param loc The location on the screen where we'd like it to go.
+
+ @param newHeight New height to animate to.
+
+ @param newHeading New heading to finish on.
+
+ @param howLong A time interval in seconds.
+ */
+- (bool)animateToPosition:(MaplyCoordinate)newPos onScreen:(CGPoint)loc height:(float)newHeight heading:(float)newHeading time:(NSTimeInterval)howLong;
+
+/**
+ Animate with a delegate over time.
+
+ Fill in the WhirlyGlobeViewControllerAnimationDelegate and you can control the visual view on a frame by frame basis. You'll get called back at the appropriate time on the main thread over the time period.
+
+ You'll also be called one at the end of the animation to establish the final position.
+
+ @param animationDelegate The objects that implements the WhirlyGlobeViewControllerAnimationDelegate protocol.
+
+ @param howLong How long the animation will run from the present time.
+ */
+- (void)animateWithDelegate:(NSObject<WhirlyGlobeViewControllerAnimationDelegate> *__nonnull)animationDelegate time:(NSTimeInterval)howLong;
+
+/**
+ Set the center of the screen to the given position immediately.
+
+ @param newPos The geographic position (lon/lat in radians) to move to.
+ */
+- (void)setPosition:(MaplyCoordinate)newPos;
+
+/**
+ Set the center of the screen and the height offset immediately.
+
+ @param newPos The geographic position (lon/lat in radians) to move to.
+
+ @param height Height the view point above the globe.
+ */
+- (void)setPosition:(MaplyCoordinate)newPos height:(float)height;
+
+/**
+ Returns the center of the screen in geographic (lon/lat in radians).
+ */
+- (MaplyCoordinate)getPosition;
+
+/**
+ Returns the center of the screen in geographic (lon/lat in radians as doubles).
+ */
+- (MaplyCoordinateD)getPositionD;
+
+/**
+ Returns the current view point's height above the globe.
+ */
+- (double)getHeight;
+
+/**
+ Set the center of the screen and the height offset immediately.
+
+ Set the center and height using double.s
+
+ @param newPos The geographic position (lon/lat in radians) to move to.
+
+ @param height Height the view point above the globe.
+ */
+- (void)setPositionD:(MaplyCoordinateD)newPos height:(double)height;
+
+/**
+ Return the current center position and height.
+
+ @param pos The center of the screen in geographic (lon/lat in radians).
+
+ @param height The current view point's height above the globe.
+ */
+- (void)getPosition:(MaplyCoordinate *__nonnull)pos height:(float *__nonnull)height;
+
+/**
+ Return the current center position and height in doubles.
+
+ @param pos The center of the screen in geographic (lon/lat in radians).
+
+ @param height The current view point's height above the globe.
+ */
+- (void)getPositionD:(MaplyCoordinateD *__nonnull)pos height:(double *__nonnull)height;
+
+/**
+ Set the viewing state all at once
+
+ This sets the position, tilt, height, screen position and heading all at once.
+ */
+- (void)setViewState:(WhirlyGlobeViewControllerAnimationState *__nonnull)viewState;
+
+/**
+ Make a WhirlyGlobeViewControllerAnimationState object from the current view state.
+
+ This returns the current view parameters in a single WhirlyGlobeViewControllerAnimationState.
+ */
+- (nullable WhirlyGlobeViewControllerAnimationState *)getViewState;
+
+/**
+ Return a view state looking at the given location.
+
+ Creates a view state that looks at the given location, taking tilt and heading into account.
+
+ @param coord The location the user will be looking at.
+
+ @param tilt Tilt off of vertical.
+
+ @param heading Heading calculated from due north.
+
+ @param alt Altitude of the point the user will be looking at (0, is a good value).
+
+ @param range How far the user will be from the location they're looking at.
+
+ @return The view state encapsulating the user location. Will be nil if the parameters weren't valid.
+ */
+- (nullable WhirlyGlobeViewControllerAnimationState *)viewStateForLookAt:(MaplyCoordinate)coord tilt:(float)tilt heading:(float)heading altitude:(float)alt range:(float)range;
+
+/**
+ Apply viewing constraints to the given view state.
+
+ This applies active viewing constraints, such as min and max height and calculated tilt, if it's on to the given view state. This is particularly useful when controlled tilt is on.
+ */
+- (void)applyConstraintsToViewState:(WhirlyGlobeViewControllerAnimationState *__nonnull)viewState;
+
+/**
+ Find a selectable object at or near the given location.
+
+ This runs immediately and looks for a Maply object at the given location. It differs from the WhirlyGlobeViewControllerDelegate in that it doesn't require user interaction.
+
+ @param screenPt The location on screen where we're looking for an object.
+
+ @return Returns a Maply object such as MaplyScreenLabel or MaplyShape or nil if it failed to find anything.
+ */
+- (nullable id)findObjectAtLocation:(CGPoint)screenPt;
+
+/**
+ Return a location on the screen for a given geographic coordinate or CGPointZero if it's not on the screen.
+
+ @param geoCoord Point on the earth in lat/lon radians you want a screen position for.
+
+ @return the point or CGPointZero
+ */
+- (CGPoint)screenPointFromGeo:(MaplyCoordinate)geoCoord;
+
+/**
+ Return a location on the screen for a given geographic coordinate or false if it's not on the screen.
+
+ @param geoCoord Point on the earth in lat/lon radians you want a screen position for.
+
+ @param screenPt Location on the screen.
+
+ @return True if the geo coord was on the screen, false otherwise.
+ */
+- (bool)screenPointFromGeo:(MaplyCoordinate)geoCoord screenPt:(CGPoint *__nonnull)screenPt;
+
+/**
+ Calculate a geo coordinate from a point on the screen.
+
+ @param screenPt Location on the screen.
+
+ @param geoCoord Point on the earth in lat/lon radians.
+
+ @return True if the point was on the globe, false otherwise.
+ */
+- (bool)geoPointFromScreen:(CGPoint)screenPt geoCoord:(MaplyCoordinate *__nonnull)geoCoord;
+
+/**
+ Calculate a geo coordinate from a point on the screen.
+
+ @param screenPt Location on the screen.
+
+ @return The corresponding MaplyCoordinate wrapped in an NSValue if the point was on the globe, nil otherwise.
+ */
+- (nullable NSValue *)geoPointFromScreen:(CGPoint)screenPt;
+
+/**
+ Calculate a geocentric coordinate from a point on the screen.
+
+ @param screenPt Location on the screen.
+
+ @return An array of 3 NSNumber (with doubles). If the point wasn't on the globe, returns nil
+ */
+- (nullable NSArray *)geocPointFromScreen:(CGPoint)screenPt;
+
+/**
+ Calculate a geocentric coordinate from a point on the screen.
+
+ @param screenPt Location on the screen.
+
+ @param retCoords An array of 3 doubles. The geocentric coordinate will be returned here.
+
+ @return True if the point was on the globe, false otherwise.
+ */
+- (bool)geocPointFromScreen:(CGPoint)screenPt geocCoord:(double *__nonnull)retCoords;
+
+/**
+ Calculate a size in meters by projecting the two screen points onto the globe.
+ Return -1, -1 if the points weren't on the globe.
+ */
+- (CGSize)realWorldSizeFromScreenPt0:(CGPoint)pt0 pt1:(CGPoint)pt1;
+
+/**
+ Find a height that shows the given bounding box.
+
+ This method will search for a height that shows the given bounding box within the view. The search is inefficient, so don't call this a lot.
+
+ @param bbox The bounding box (in radians) we're trying to view.
+
+ @param pos The position the viewer will be at.
+ */
+- (float)findHeightToViewBounds:(MaplyBoundingBox)bbox pos:(MaplyCoordinate)pos;
+
+/**
+ Find a height that shows the given bounding box.
+ This method will search for a height that shows the given bounding box within the view. The search is inefficient, so don't call this a lot.
+
+ This version takes a margin to add around the outside of the area. Positive margins increase the screen area considered, making the
+ given area larger. Negative margins make the specified area smaller.
+
+ @param bbox The bounding box (in radians) we're trying to view.
+ @param pos Where the view will be looking.
+ @param marginX Horizontal boundary around the area
+ @param marginY Vertical boundary around the area
+ */
+- (float)findHeightToViewBounds:(MaplyBoundingBox)bbox
+ pos:(MaplyCoordinate)pos
+ marginX:(double)marginX
+ marginY:(double)marginY;
+
+/**
+ Find a height that shows the given bounding box.
+ This method will search for a height that shows the given bounding box within the view. The search is inefficient, so don't call this a lot.
+
+ This version takes a margin to add around the outside of the area. Positive margins increase the screen area considered, making the
+ given area larger. Negative margins make the specified area smaller.
+
+ This version attempts to place the given bounds within a rectangle other than the whole view frame.
+ Note that this doesn't work well when the bounds are very large.
+
+ @param bbox The bounding box (in radians) we're trying to view.
+ @param pos Where the view will be looking.
+ @param frame The screen area to consider.
+ @param newPos (out,optional) The center location needed to place \c pos at the center of \c frame
+ @param marginX Horizontal boundary around the area
+ @param marginY Vertical boundary around the area
+ */
+- (float)findHeightToViewBounds:(MaplyBoundingBox)bbox
+ pos:(MaplyCoordinate)pos
+ frame:(CGRect)frame
+ newPos:(MaplyCoordinate *_Nullable)newPos
+ marginX:(double)marginX
+ marginY:(double)marginY;
+
+/**
+
+ Return the extents of the current view.
+
+ When we're dealing with a globe the corners could be outside of the globe, in this case kMaplyNullBoundingBox is returned.
+
+ @return Returns the bounding box if exists a bounding bbox for the current view, otherwise returns kMaplyNullBoundingBox.
+ */
+- (MaplyBoundingBox)getCurrentExtents;
+
+/**
+
+ Return the extents of the current view.
+
+ When we're dealing with a globe the corners could be outside of the globe, in this case false is returned.
+
+ @param bbox The bbox will be returned here.
+
+ @return Returns true if exists a bounding bbox for the current view, otherwise returns false
+ */
+- (bool)getCurrentExtents:(MaplyBoundingBox *__nonnull)bbox;
+
+/**
+
+ From the current view figure out a usable geo bounding box.
+
+ This is similar to the WhirlyGlobeViewControllerDelegate methods and getCurrentExtents except that it goes a little deeper. It starts with the four corners of the screen and then tries to take tilt and orientation into account. Ideally it produces a bounding box that covers everything the user is looking at as opposed to where the four corners are.
+
+ @param bboxes The bounding boxes to fill in. Pass in two.
+
+ @param visualBoxes If set, we'll build bounding boxes you can display. If not set, we'll build a single bounding box usable for math.
+ */
+- (int)getUsableGeoBoundsForView:(MaplyBoundingBox *__nonnull)bboxes visual:(bool)visualBoxes;
+
+/**
+
+ Make a gesture recognizer's success depend on the pan gesture
+ recognizer's failure.
+
+ When using the globe view within a scroll view, add swipe gesture
+ recognizers to the scroll view to control paging, and call this method
+ for each. See also the inScrollView property and its comment.
+
+ @param other The other, subordinate gesture recognizer.
+ */
+- (void)requirePanGestureRecognizerToFailForGesture:(UIGestureRecognizer *__nullable)other;
+
+@end
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Info.plist b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Info.plist
new file mode 100644
index 0000000..ea42d3d
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Info.plist
Binary files differ
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Modules/module.modulemap b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Modules/module.modulemap
new file mode 100644
index 0000000..2e32255
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/Modules/module.modulemap
@@ -0,0 +1,6 @@
+framework module WhirlyGlobe {
+ umbrella header "WhirlyGlobe.h"
+
+ export *
+ module * { export * }
+}
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/WhirlyGlobe b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/WhirlyGlobe
new file mode 100755
index 0000000..fa83d49
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/WhirlyGlobe
Binary files differ
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/_CodeSignature/CodeResources b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/_CodeSignature/CodeResources
new file mode 100644
index 0000000..f543d38
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/_CodeSignature/CodeResources
@@ -0,0 +1,1246 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>files</key>
+ <dict>
+ <key>Config-ac.h.in</key>
+ <data>
+ 9/EeTy4NmqD1NMmDBmUoAMtipP0=
+ </data>
+ <key>Headers/GeoJSONSource.h</key>
+ <data>
+ LgA8/zXMMeKdKW3zxzpAUNas5Pg=
+ </data>
+ <key>Headers/GeographicLib_ObjC.h</key>
+ <data>
+ vvYiKYxDtAiMYN/u/YEXcBQHIkU=
+ </data>
+ <key>Headers/GlobeDoubleTapDelegate.h</key>
+ <data>
+ QqBi2N/9Est7YCV+CXBPcmISEhc=
+ </data>
+ <key>Headers/GlobeDoubleTapDragDelegate.h</key>
+ <data>
+ aGn3LTkOY2QQkvkYARVnfBDJCd0=
+ </data>
+ <key>Headers/GlobePanDelegate.h</key>
+ <data>
+ 8oYBkNU3Rf4sDMQ/W5KXDOcIEpI=
+ </data>
+ <key>Headers/GlobePinchDelegate.h</key>
+ <data>
+ CSQu/RleIn4NHh8kR5q3JAR8TaI=
+ </data>
+ <key>Headers/GlobeRotateDelegate.h</key>
+ <data>
+ EOdhuii8DgQkjPidSZkVgoZceIk=
+ </data>
+ <key>Headers/GlobeTapDelegate.h</key>
+ <data>
+ A06RyXkRGCQN5Bp80B6Nq3YmpRQ=
+ </data>
+ <key>Headers/GlobeTiltDelegate.h</key>
+ <data>
+ DKcqjI/lagwYouaR3oFSvSnW7NI=
+ </data>
+ <key>Headers/GlobeTwoFingerTapDelegate.h</key>
+ <data>
+ 5XYlbJGAVtXGXoEUiEfK9+BYI7A=
+ </data>
+ <key>Headers/MapboxVectorInterpreter.h</key>
+ <data>
+ vqYj/dA84E9CS5m13xGveqcTihE=
+ </data>
+ <key>Headers/MapboxVectorStyleSet.h</key>
+ <data>
+ 1e0IoJI7mdOAXbVZEHwI1834IN8=
+ </data>
+ <key>Headers/MapboxVectorTiles.h</key>
+ <data>
+ T03CMKrst3X19A5JRguOHbbxzHY=
+ </data>
+ <key>Headers/Maply3DTouchPreviewDatasource.h</key>
+ <data>
+ veOjOMM7qE1UtogzjI8DRrsuNPg=
+ </data>
+ <key>Headers/Maply3dTouchPreviewDelegate.h</key>
+ <data>
+ COf8NPwTN++qEtYf5HoN+YynbAA=
+ </data>
+ <key>Headers/MaplyActiveObject.h</key>
+ <data>
+ gv2jeu6hqWC1symP6lBUg6lNenI=
+ </data>
+ <key>Headers/MaplyAnnotation.h</key>
+ <data>
+ DENhMxzyMrdyA3rmD4wxhHQXZUc=
+ </data>
+ <key>Headers/MaplyAtmosphere.h</key>
+ <data>
+ 0Wh7aJqUst7dEnKtUQiRzBaOm8c=
+ </data>
+ <key>Headers/MaplyBaseViewController.h</key>
+ <data>
+ fycHRK4lcY7Gqr/XIxQ+QK6pQ3o=
+ </data>
+ <key>Headers/MaplyBillboard.h</key>
+ <data>
+ foaM36UndN6ktQSWEGXbSlSnHP4=
+ </data>
+ <key>Headers/MaplyBridge.h</key>
+ <data>
+ IQisyU6tFk5AxBYO5uvguFbOGTM=
+ </data>
+ <key>Headers/MaplyCluster.h</key>
+ <data>
+ NgHOFpEXCmyIx1I5yCIZjm4x3lQ=
+ </data>
+ <key>Headers/MaplyColorRampGenerator.h</key>
+ <data>
+ HyRswbCNLClgGqPfaDayUgMi1Ik=
+ </data>
+ <key>Headers/MaplyComponent.h</key>
+ <data>
+ aTrskuGy0HsfToFdc7Q/PBn5BHk=
+ </data>
+ <key>Headers/MaplyComponentObject.h</key>
+ <data>
+ 4eS1jK32SUcD1rVC97OVvfnNKPw=
+ </data>
+ <key>Headers/MaplyControllerLayer.h</key>
+ <data>
+ szeESgaZW8ohSXXfimPwp9CVkb4=
+ </data>
+ <key>Headers/MaplyCoordinate.h</key>
+ <data>
+ jwXLto2HZh6WTVXeQN8HF29cUkE=
+ </data>
+ <key>Headers/MaplyCoordinateSystem.h</key>
+ <data>
+ fryDolWUeDFPAiVqwclbd+G99NA=
+ </data>
+ <key>Headers/MaplyDoubleTapDelegate.h</key>
+ <data>
+ DP2Jlf+groPWvm/FC9CAimL/Xus=
+ </data>
+ <key>Headers/MaplyDoubleTapDragDelegate.h</key>
+ <data>
+ gVO+/8DLhGszf41vqwMjGQ6aNrc=
+ </data>
+ <key>Headers/MaplyGeomBuilder.h</key>
+ <data>
+ lfWLOY9Dch+FIkUgV9Jq/oNbmRM=
+ </data>
+ <key>Headers/MaplyGeomModel.h</key>
+ <data>
+ EMNoj8u9ya0ghQ3kd7x+0BPuAOQ=
+ </data>
+ <key>Headers/MaplyGlobeRenderController.h</key>
+ <data>
+ g8xwuLHA4KXSYVeXnEkTfiQjUs4=
+ </data>
+ <key>Headers/MaplyIconManager.h</key>
+ <data>
+ bZjq3dGY5Dn7A2ARUSAzfKs1qAI=
+ </data>
+ <key>Headers/MaplyImageTile.h</key>
+ <data>
+ bOolPRB/KV2Fc3MR99sE3N8Iu44=
+ </data>
+ <key>Headers/MaplyLabel.h</key>
+ <data>
+ SxR2NNygJPXHjZPINZqwYamEKNk=
+ </data>
+ <key>Headers/MaplyLight.h</key>
+ <data>
+ T175ocnZF0SZCIQgB34uYPtSBFo=
+ </data>
+ <key>Headers/MaplyLocationTracker.h</key>
+ <data>
+ Njq0LDl+OZDMyTmvOUHW7D1X81w=
+ </data>
+ <key>Headers/MaplyMBTileFetcher.h</key>
+ <data>
+ zx8wfOSfZn4OavqGJopn17JTBJ0=
+ </data>
+ <key>Headers/MaplyMarker.h</key>
+ <data>
+ 3EWsdjno1Qp1WC9GIcpGZ39Gie0=
+ </data>
+ <key>Headers/MaplyMatrix.h</key>
+ <data>
+ N35AfRn0T614wk3FcINbEQtWF0o=
+ </data>
+ <key>Headers/MaplyMoon.h</key>
+ <data>
+ Ao/E3lTrwLZNVqnSP2qmuNlh4fo=
+ </data>
+ <key>Headers/MaplyPanDelegate.h</key>
+ <data>
+ +XRT+yzcf/oUIrFc6DM07ft0PII=
+ </data>
+ <key>Headers/MaplyParticleSystem.h</key>
+ <data>
+ rH7ITb14S/5rOPHnij+LSaNtqUs=
+ </data>
+ <key>Headers/MaplyPinchDelegate.h</key>
+ <data>
+ 5pDDYHdu0j+0wy6VnUThMUxqFT8=
+ </data>
+ <key>Headers/MaplyPoints.h</key>
+ <data>
+ YUlvzKWD3RoLEUoyCZZSamPfOxg=
+ </data>
+ <key>Headers/MaplyQuadImageFrameLoader.h</key>
+ <data>
+ Xq9E0sG9SsG2/8JO1fipJDHDV8k=
+ </data>
+ <key>Headers/MaplyQuadImageLoader.h</key>
+ <data>
+ RIywCYQo15UMAGMDBuEryjmZICU=
+ </data>
+ <key>Headers/MaplyQuadLoader.h</key>
+ <data>
+ wi4+vRVhbtrly5zz+YnDudR5Mis=
+ </data>
+ <key>Headers/MaplyQuadPagingLoader.h</key>
+ <data>
+ J1S5i1QCUBfiqSlu4znrLgAVz3s=
+ </data>
+ <key>Headers/MaplyQuadSampler.h</key>
+ <data>
+ 1u6Yr5wNRtezpTL82Jb/3G9MXqc=
+ </data>
+ <key>Headers/MaplyRemoteTileFetcher.h</key>
+ <data>
+ 4wbuMKUEnSxKFxeWtPViezCMOfQ=
+ </data>
+ <key>Headers/MaplyRenderController.h</key>
+ <data>
+ QhabKAk+zzoKcpc9NnNf68cUAH4=
+ </data>
+ <key>Headers/MaplyRenderTarget.h</key>
+ <data>
+ nw0Ry0ObhrOAoz7mBw8uKtV6DAc=
+ </data>
+ <key>Headers/MaplyRotateDelegate.h</key>
+ <data>
+ 78P45X/02M5h7ZiarlD7QnPrXnQ=
+ </data>
+ <key>Headers/MaplyScreenLabel.h</key>
+ <data>
+ D7nyk9jPnSrhyW8kkVuHpgxANBc=
+ </data>
+ <key>Headers/MaplyScreenMarker.h</key>
+ <data>
+ EvPoYfsHB6ALZksm2y57+fDyFtY=
+ </data>
+ <key>Headers/MaplyScreenObject.h</key>
+ <data>
+ Z9CjZejNveRMBNNoNVZOCiwr2W8=
+ </data>
+ <key>Headers/MaplyShader.h</key>
+ <data>
+ vZZ1SSdaLFATZPOIm03Ps1SVtfI=
+ </data>
+ <key>Headers/MaplyShape.h</key>
+ <data>
+ LwJ8z7LXdAg5X7vkQiveVy1fd0M=
+ </data>
+ <key>Headers/MaplySharedAttributes.h</key>
+ <data>
+ Lg9QAnH7ddyZ9yw9rU1iB6chs9A=
+ </data>
+ <key>Headers/MaplySimpleTileFetcher.h</key>
+ <data>
+ OGik7ZgAStfwiikE4GZgVLprI5o=
+ </data>
+ <key>Headers/MaplyStarsModel.h</key>
+ <data>
+ lcOVa3whA5Gqi1wPiJ/HqX6l+PI=
+ </data>
+ <key>Headers/MaplySticker.h</key>
+ <data>
+ GQeKonzo/SCpnKgsrXMxQ/9QGmM=
+ </data>
+ <key>Headers/MaplySun.h</key>
+ <data>
+ g1ZGNWMtQjeK+3njt9PacWK+Fhw=
+ </data>
+ <key>Headers/MaplyTapDelegate.h</key>
+ <data>
+ h/rF9s44ynPv89d1t83fMeTcjrg=
+ </data>
+ <key>Headers/MaplyTapMessage.h</key>
+ <data>
+ iNQtsyXu26IXU7Vix6utQOoK7gg=
+ </data>
+ <key>Headers/MaplyTexture.h</key>
+ <data>
+ y0AHjS3maNppktArt/dwY1ijKFI=
+ </data>
+ <key>Headers/MaplyTextureBuilder.h</key>
+ <data>
+ m4xwlqmFemTDO+66mIsnemnInyM=
+ </data>
+ <key>Headers/MaplyTileSourceNew.h</key>
+ <data>
+ G6AlGHWA6Nk6iFeb0r/vEynXSP4=
+ </data>
+ <key>Headers/MaplyTouchCancelAnimationDelegate.h</key>
+ <data>
+ UDKJWRB0ugd+lkP5bvunOpYD+V4=
+ </data>
+ <key>Headers/MaplyTwoFingerTapDelegate.h</key>
+ <data>
+ D80ilgRdvPdLKrEFkozNMaKj4SM=
+ </data>
+ <key>Headers/MaplyUpdateLayer.h</key>
+ <data>
+ 9knK1FIs87qq1yVUun9xaztS6QY=
+ </data>
+ <key>Headers/MaplyVariableTarget.h</key>
+ <data>
+ /61immMlIupRvzfJWz1tYxcraZM=
+ </data>
+ <key>Headers/MaplyVectorObject.h</key>
+ <data>
+ bAAZbcyvau9qA82J8RCwVHGV2Gw=
+ </data>
+ <key>Headers/MaplyVectorStyle.h</key>
+ <data>
+ IAvxdja11PthV+JxVVTMpAr8c8Q=
+ </data>
+ <key>Headers/MaplyVectorStyleSimple.h</key>
+ <data>
+ eGMCXQr7MA71oViOYZS4pJJXLEU=
+ </data>
+ <key>Headers/MaplyVectorTileLineStyle.h</key>
+ <data>
+ ihYSW3diBLxmwZFHYXGxJ1M93Yg=
+ </data>
+ <key>Headers/MaplyVectorTileMarkerStyle.h</key>
+ <data>
+ 6AJPn0IqWnHEweqrXqcea1rGqIY=
+ </data>
+ <key>Headers/MaplyVectorTilePolygonStyle.h</key>
+ <data>
+ c82UUTbYlwWqfcc2GCI/k0DngS0=
+ </data>
+ <key>Headers/MaplyVectorTileStyle.h</key>
+ <data>
+ AseQkQ3U2ms/h2CzR2KKcuBAbUY=
+ </data>
+ <key>Headers/MaplyVectorTileTextStyle.h</key>
+ <data>
+ JdZodkdB5PNYXBBPdfhlKB9fj6E=
+ </data>
+ <key>Headers/MaplyVertexAttribute.h</key>
+ <data>
+ cgeR0Lm2OkTO04MtaFIYUR4uHFY=
+ </data>
+ <key>Headers/MaplyViewController.h</key>
+ <data>
+ BwnVhW9NBG3bHDbXZu+AEnsVi+0=
+ </data>
+ <key>Headers/MaplyViewTracker.h</key>
+ <data>
+ HHZm4YOW7/LfCwJDw6WllCvNeRc=
+ </data>
+ <key>Headers/MaplyWMSTileSource.h</key>
+ <data>
+ ZEfPCMDXDA9eLRL/E8iH26d7UQg=
+ </data>
+ <key>Headers/MaplyZoomGestureDelegate.h</key>
+ <data>
+ vjYe7vTevTdOagktXppng/iT8+Q=
+ </data>
+ <key>Headers/MapnikStyle.h</key>
+ <data>
+ eglIp84Ak1EJ5oqzTozufYKBXM8=
+ </data>
+ <key>Headers/MapnikStyleRule.h</key>
+ <data>
+ DEgwkhgj+VyJ6GR+B26aCQ1GIeM=
+ </data>
+ <key>Headers/MapnikStyleSet.h</key>
+ <data>
+ S3CCf2O8Qry0Opa3HHSCzLBmQYs=
+ </data>
+ <key>Headers/NSData+Zlib.h</key>
+ <data>
+ Gsek7/5n4OLrTwAU/RBpfk5rcf4=
+ </data>
+ <key>Headers/NSDictionary+StyleRules.h</key>
+ <data>
+ uphDMxI5vMG/TqKHx4diLyAwLjM=
+ </data>
+ <key>Headers/SLDExpressions.h</key>
+ <data>
+ njrUuR9+9OJ016pPutGDMIvn4T4=
+ </data>
+ <key>Headers/SLDOperators.h</key>
+ <data>
+ fjKIOK81kTGZHa7D77bJdH6aP/M=
+ </data>
+ <key>Headers/SLDStyleSet.h</key>
+ <data>
+ YdtAyFFfZ9oaA1r50cMoJOanb60=
+ </data>
+ <key>Headers/SLDSymbolizers.h</key>
+ <data>
+ pY3xXv3c5oQpXQRHiQa/o7OG1Vk=
+ </data>
+ <key>Headers/SLDWellKnownMarkers.h</key>
+ <data>
+ 4rJuYX7cc7wpnDKXRFwKoZLaIFE=
+ </data>
+ <key>Headers/WGCoordinate.h</key>
+ <data>
+ suZCi5mh+PDAMlznHA04sKs4sVA=
+ </data>
+ <key>Headers/WhirlyGlobe.h</key>
+ <data>
+ 0OfglihgL9viXMmHGPcNRj86Iqg=
+ </data>
+ <key>Headers/WhirlyGlobeComponent.h</key>
+ <data>
+ upSrdYysRKk9xfsCOg/H9rkAkU4=
+ </data>
+ <key>Headers/WhirlyGlobeViewController.h</key>
+ <data>
+ 1rW/PC30PuhdaWDhbv/kntO/B/c=
+ </data>
+ <key>Info.plist</key>
+ <data>
+ uw22+UUExVfPrZSQBgmmjH6HLes=
+ </data>
+ <key>Modules/module.modulemap</key>
+ <data>
+ QstvNn+FqXqasRFV481t/Rqtdag=
+ </data>
+ <key>default.metallib</key>
+ <data>
+ h/kQT5dH50b8/G0qP9YHYt8GCrs=
+ </data>
+ </dict>
+ <key>files2</key>
+ <dict>
+ <key>Config-ac.h.in</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ BrnjgI9i/RJ2l/sj2GvqsuKk1qYLLdJ/xeCm8SyKeMI=
+ </data>
+ </dict>
+ <key>Headers/GeoJSONSource.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ +xDbQmKdukZ8fMLAVCt9EZrpMGHcBUUhyFTjw5WfYLs=
+ </data>
+ </dict>
+ <key>Headers/GeographicLib_ObjC.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ TEjfMnsQh4CV4Et4ABEQdZUzanLIQosur/A5tmzbIR8=
+ </data>
+ </dict>
+ <key>Headers/GlobeDoubleTapDelegate.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ Tetu4dRav5CC4HKuckECAsIB3tS2TnFikAHEqxROayg=
+ </data>
+ </dict>
+ <key>Headers/GlobeDoubleTapDragDelegate.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ CO4E4+LubyAH34Y4tUCaCUcCUCZ9w5DMmWfxSxvkh00=
+ </data>
+ </dict>
+ <key>Headers/GlobePanDelegate.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ hlHwsT4O/RascLHvBrN6RBi49usoTsaFP8FSwhSCDNg=
+ </data>
+ </dict>
+ <key>Headers/GlobePinchDelegate.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ ggsyNl86MZTZjTt3Rr+GIawY/MxqcJ4/d7MlbD6woVU=
+ </data>
+ </dict>
+ <key>Headers/GlobeRotateDelegate.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ FFGYRwjFuun3b7QFcxhYOrL2Pl/bwpowfZxIf+2E9sU=
+ </data>
+ </dict>
+ <key>Headers/GlobeTapDelegate.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ lgaeoilq/MXWbVKVLLzbkEW2hbvmbrekJy40rDjF6MA=
+ </data>
+ </dict>
+ <key>Headers/GlobeTiltDelegate.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ YBN3ftV/G/fWkKbzOZsN/vC2oCx+Ss4QtlzGeOe34q0=
+ </data>
+ </dict>
+ <key>Headers/GlobeTwoFingerTapDelegate.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ LZs/tyEygzHGahueGTihkbzrdwFZg8ZCT7j6fS2n540=
+ </data>
+ </dict>
+ <key>Headers/MapboxVectorInterpreter.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ pFGtyh7a3qeJtzLstJo6UeaJhMa6d7wGXo7FMJxcC88=
+ </data>
+ </dict>
+ <key>Headers/MapboxVectorStyleSet.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ lIW34sd4+c0YN4BGIpRDxYsdw9/ErHT2HrfHfNJTAkE=
+ </data>
+ </dict>
+ <key>Headers/MapboxVectorTiles.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ 7IwCtF+38RXYOr+pFY8JoFQU9pTVECyBuRqyXfnNBwI=
+ </data>
+ </dict>
+ <key>Headers/Maply3DTouchPreviewDatasource.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ SGA2k3ZgFOs8HBrttWY0WwS98S6zvA/tIQA6TnMOOBA=
+ </data>
+ </dict>
+ <key>Headers/Maply3dTouchPreviewDelegate.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ hXq/vx/4Bysz1mLKAXkEkmgJBbB5tQfDoZ8F0byUqAE=
+ </data>
+ </dict>
+ <key>Headers/MaplyActiveObject.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ gZGmPb+XxM76ChWjwxT4pJRIlyuyrPozC8pt24ZhZAo=
+ </data>
+ </dict>
+ <key>Headers/MaplyAnnotation.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ /CQWYQp3oWtD4lm1C1yLCKlYipz8Getlh0Agtmc4ktM=
+ </data>
+ </dict>
+ <key>Headers/MaplyAtmosphere.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ 3kc12oK9rBbUWvwZrMznOlq9uvxAo45njGZPrd/R3ns=
+ </data>
+ </dict>
+ <key>Headers/MaplyBaseViewController.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ 51fqXP150XKzoTDzMlckAt9snbwwrk43yl0yQCfFSX8=
+ </data>
+ </dict>
+ <key>Headers/MaplyBillboard.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ h7EwZij2VsXcI9voAnbTRMYulPIL8KgKV5cANs74KOM=
+ </data>
+ </dict>
+ <key>Headers/MaplyBridge.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ xGcf6VmwfQ2mxcsxU378LnHSM/Zj8WCCmtiPgJhqQs4=
+ </data>
+ </dict>
+ <key>Headers/MaplyCluster.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ 5dhp3ZAReYOBDANb5/COTzOs+FhJFtyH6T+QNcY+xV4=
+ </data>
+ </dict>
+ <key>Headers/MaplyColorRampGenerator.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ V0KmZBBhDdsgXVuQk5nd1Q++c4SnwnXGGaA9N07w8bY=
+ </data>
+ </dict>
+ <key>Headers/MaplyComponent.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ VBsBepQblE0wrg1Ey5tUW0FmwSEEMPeecKCs/+k3+J0=
+ </data>
+ </dict>
+ <key>Headers/MaplyComponentObject.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ ENmgvhH1Tvo+faJ5SReD3/z/PoC7UPzw5HXEGrav45c=
+ </data>
+ </dict>
+ <key>Headers/MaplyControllerLayer.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ e8v5br8s6oiZ3j37KlA55aN/6JKzQp+/aEceVId5xUk=
+ </data>
+ </dict>
+ <key>Headers/MaplyCoordinate.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ 1IKJWN5QZKHfbANvk9Y8cm3J6e8JvSPpQCAU86IhUHk=
+ </data>
+ </dict>
+ <key>Headers/MaplyCoordinateSystem.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ O/A7VOAx9X3c0LSCQrneukaA+g7P69/z7H3ThdyH+lA=
+ </data>
+ </dict>
+ <key>Headers/MaplyDoubleTapDelegate.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ PUs6aAebADMMG8wRujLE79AwDitmYtoMDrCf4oPXjD4=
+ </data>
+ </dict>
+ <key>Headers/MaplyDoubleTapDragDelegate.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ EvgCT13fuVnAswk1h+e/4i3/Y4TPFAct9uM/V6rn+gA=
+ </data>
+ </dict>
+ <key>Headers/MaplyGeomBuilder.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ gX5c3WKTpuKupJLJbER1MaHeEUG2GAHkF9/OjMdfda8=
+ </data>
+ </dict>
+ <key>Headers/MaplyGeomModel.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ y/x8fUQPo6cQsZcWQJz+T8r6Iz3hGiwGY01oO4K4Hc0=
+ </data>
+ </dict>
+ <key>Headers/MaplyGlobeRenderController.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ mlMRbr00SoH4QlV86vGbTYEr7qNaxWYZCMBAJ9hPuLw=
+ </data>
+ </dict>
+ <key>Headers/MaplyIconManager.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ oRcUygcc2v50zd1Evw7X+ycBgUPaJq5HsO6ogVbDhWU=
+ </data>
+ </dict>
+ <key>Headers/MaplyImageTile.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ zYlOLFnFHjDVNFeKNiFu1vqB/kXkrWMTbGdGGYYBlM8=
+ </data>
+ </dict>
+ <key>Headers/MaplyLabel.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ J3hneVCxIJpDmxWsRnMujBN39WL/9FIizbNfOQrIvsI=
+ </data>
+ </dict>
+ <key>Headers/MaplyLight.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ ViyKqxfQyux0YhTTv3+fnycW/mh8bZHIBVCcDTskUk8=
+ </data>
+ </dict>
+ <key>Headers/MaplyLocationTracker.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ cLIyps4X+fD1gq3mzM/zt2mGmiNkAxy6rLsWTQQmbRY=
+ </data>
+ </dict>
+ <key>Headers/MaplyMBTileFetcher.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ OWHw9MB+aF2JaYf9Es9weeU+amWN64wHDJLX6BWxAeU=
+ </data>
+ </dict>
+ <key>Headers/MaplyMarker.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ x51Fh8QdDHYDJAmOlF5/UbYO1hYLM/nKv0LVcDqxE/A=
+ </data>
+ </dict>
+ <key>Headers/MaplyMatrix.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ SJw/BHcbrI2SCNMwFaVT2C3pTxUITcLWhXEejTxu14c=
+ </data>
+ </dict>
+ <key>Headers/MaplyMoon.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ IUc/HkR/PdA+OluPdFCd2J6Rg5hCJvsD0MyM4o9U3/A=
+ </data>
+ </dict>
+ <key>Headers/MaplyPanDelegate.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ E3pdxgV/fdV2EaFsvRV7Ze5/2jjSdPEAoNdLbth2Cbc=
+ </data>
+ </dict>
+ <key>Headers/MaplyParticleSystem.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ ibXQsPvrWYgg81034GXnoNH+KAHPWQfE87ffwdVYqwA=
+ </data>
+ </dict>
+ <key>Headers/MaplyPinchDelegate.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ 7+KuGC4yiRdG8G8kKVqid7gLPClzry0J4HHj+Oigm94=
+ </data>
+ </dict>
+ <key>Headers/MaplyPoints.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ me3/3IvJiSqw51bNG7SdV7DiIZzK5hT4j6jz7JAxTHY=
+ </data>
+ </dict>
+ <key>Headers/MaplyQuadImageFrameLoader.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ /lrDXF/sVJi+NLGWXOJLqZy2xAT2YsXSUIAfab44TkU=
+ </data>
+ </dict>
+ <key>Headers/MaplyQuadImageLoader.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ eM1278XKgcx9WSKj+0CZnfTTUssKkwD8sLItfl4VOcY=
+ </data>
+ </dict>
+ <key>Headers/MaplyQuadLoader.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ ArLI5Rb+dISvBYw+2SeEZSOzeKXDo02yYziMbwA0L2s=
+ </data>
+ </dict>
+ <key>Headers/MaplyQuadPagingLoader.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ zvi9WA26Tpt5Dfm348aCF+hhw9y5qpyy+/Cb8xSAUqk=
+ </data>
+ </dict>
+ <key>Headers/MaplyQuadSampler.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ Uk0RbKCZ0YqfEIAhegrWIOngNtT5vTDmUdQYoU7Ydms=
+ </data>
+ </dict>
+ <key>Headers/MaplyRemoteTileFetcher.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ xP5txG+d59lH20dpklzMvkI+JnXX0bVz96dnPlyC2es=
+ </data>
+ </dict>
+ <key>Headers/MaplyRenderController.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ jkV7AZst7ZiI+lCh5ouLsBI4ny0OLGiNeqKE1eXUxn4=
+ </data>
+ </dict>
+ <key>Headers/MaplyRenderTarget.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ Cgr3oig2a3Juk/ai+1NY7XDqZ8rnZbVoh5NDRqulw7k=
+ </data>
+ </dict>
+ <key>Headers/MaplyRotateDelegate.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ sy/fP0+ocjA34p1NDXlzlKM/kt8y0uFUHQAFPrts6xU=
+ </data>
+ </dict>
+ <key>Headers/MaplyScreenLabel.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ 8TEpV1UopSMfbi89/Xv62k/79UfKXhN3hDirzEIDAlc=
+ </data>
+ </dict>
+ <key>Headers/MaplyScreenMarker.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ KMCPtRy0D2mRlhcMPW9iGmesxoU1nDR82m4lnIYIf5g=
+ </data>
+ </dict>
+ <key>Headers/MaplyScreenObject.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ SNhtIDv/e8IH009nAEhKXlCtx2w/r9sIAZduGR0tI+Q=
+ </data>
+ </dict>
+ <key>Headers/MaplyShader.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ JnQZpUzF+ciGb8/7mLmTEJVdXW9fojwVl8zorpYnohU=
+ </data>
+ </dict>
+ <key>Headers/MaplyShape.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ Fr5L83AFUeWLyPY/vbE97kNmKfiJvG1eH89gktBkslM=
+ </data>
+ </dict>
+ <key>Headers/MaplySharedAttributes.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ DOiqgZLQzTKzX5Kj5SxhzZSApIIRN0W2yr/rbKPp/I8=
+ </data>
+ </dict>
+ <key>Headers/MaplySimpleTileFetcher.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ vwjVgn6r3uLu00ja20QpIEDNElsGnM4ovDoezO924/E=
+ </data>
+ </dict>
+ <key>Headers/MaplyStarsModel.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ s61IdFjZ0C25zpNBdIizcay6olAFBqU8HEaf+1Rw9iI=
+ </data>
+ </dict>
+ <key>Headers/MaplySticker.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ wTcOPPrbW8iYuQoCYVMFq/E3tqpIghxpBNpmbIIeGGE=
+ </data>
+ </dict>
+ <key>Headers/MaplySun.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ yhCRhcLjCAhbQRKphWqwwKFv4xJgysH3B2pk6wOvRkE=
+ </data>
+ </dict>
+ <key>Headers/MaplyTapDelegate.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ fiToltTYJEErdgxaENC0n4e6styYjUGfH9jekubsES0=
+ </data>
+ </dict>
+ <key>Headers/MaplyTapMessage.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ vTEQDVmjnN0KKUkNr/txcbqHR3P2vJso3QyVC+RPZJY=
+ </data>
+ </dict>
+ <key>Headers/MaplyTexture.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ KOQpK7ZV2Nh8Kd1qdVPPEJf3yTmpm5Wnx1T0ji8yfFA=
+ </data>
+ </dict>
+ <key>Headers/MaplyTextureBuilder.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ AEmO3A/esFMpTNQkEfWEusCS6JtWpoOVYB3opZ9QbMU=
+ </data>
+ </dict>
+ <key>Headers/MaplyTileSourceNew.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ CcMpZuSo/ak4RrdETcxW16KBI6Scdlf7ZKtCmlI0U4M=
+ </data>
+ </dict>
+ <key>Headers/MaplyTouchCancelAnimationDelegate.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ 4t6DqxTvF4wtsbOFGGfcYUjx2gY+47ogeyMZlSUq+e0=
+ </data>
+ </dict>
+ <key>Headers/MaplyTwoFingerTapDelegate.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ LwnGTZwbfM20W2h5OcSLUqeo5Wb9Ksnmp0ZpXG72xrs=
+ </data>
+ </dict>
+ <key>Headers/MaplyUpdateLayer.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ sc/LtxXRK5DPxT7oYeU2M3YSRdJDg4qi/HRbayYS/8Y=
+ </data>
+ </dict>
+ <key>Headers/MaplyVariableTarget.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ P6s8ax4O2fB3vXZB0RPXzpfWkQW/5eRrBEcU0q+emc0=
+ </data>
+ </dict>
+ <key>Headers/MaplyVectorObject.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ HD7ZqOoKvpz+ydIyi5hIhW50YV3k8fzmzLVjF6e5U6Y=
+ </data>
+ </dict>
+ <key>Headers/MaplyVectorStyle.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ RfCyYLq+OxOhby18gzpv+9Oso4IqCVTwxjE/dsfTiVo=
+ </data>
+ </dict>
+ <key>Headers/MaplyVectorStyleSimple.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ 0Tr50lVWpWhMg2sjl1neg6SEv3IQMxR3Pth4xSkDobE=
+ </data>
+ </dict>
+ <key>Headers/MaplyVectorTileLineStyle.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ eGY4B5TAGK4xfrhyeIyt0gNcLEjTl2WLv52GZG2Kb+c=
+ </data>
+ </dict>
+ <key>Headers/MaplyVectorTileMarkerStyle.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ QhWjTRIfdTC+HIF0Fga5ar4y8DGEfoDRKoegrzoH2vs=
+ </data>
+ </dict>
+ <key>Headers/MaplyVectorTilePolygonStyle.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ J0BcN9AiqOE++O/9CmU9fIh7ybdohL6FndPxn2YoBQU=
+ </data>
+ </dict>
+ <key>Headers/MaplyVectorTileStyle.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ rdXUdNpaSiFxvujEjocQU1FnqTEGlTWxhLHc0HrLlVM=
+ </data>
+ </dict>
+ <key>Headers/MaplyVectorTileTextStyle.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ tZ/5NtWQUlaIBwKt8NcZ54lemt8bhwK1QXt26G/Azco=
+ </data>
+ </dict>
+ <key>Headers/MaplyVertexAttribute.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ mmmrVh838rtoKuUVUc6xuFO4Eyl1bOoWH+4J050FAp4=
+ </data>
+ </dict>
+ <key>Headers/MaplyViewController.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ Saqrl8nkXSrB8lH518Hkn2jfjBM1k8TOYPPPwm/9+kQ=
+ </data>
+ </dict>
+ <key>Headers/MaplyViewTracker.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ Nl9YJvmsP9hWNbtq/a9klfxjpFaR7SKZgL8B/rmHcLk=
+ </data>
+ </dict>
+ <key>Headers/MaplyWMSTileSource.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ ajYRUf7mBmI5tDQT6owqu+eI2XAZ9LxP75NknRnz8O4=
+ </data>
+ </dict>
+ <key>Headers/MaplyZoomGestureDelegate.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ XRwdLyjEKAuT0SI73DIw2boCO9eGkBBVsonhJEynv1c=
+ </data>
+ </dict>
+ <key>Headers/MapnikStyle.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ PiZpoDV6VXvof6njrzxwOnHhWxbdgdmBwd/Zdub07jM=
+ </data>
+ </dict>
+ <key>Headers/MapnikStyleRule.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ Aq6950RPbjL+d3OMmPyqu/F/8z1Losl6i1AO3p78k24=
+ </data>
+ </dict>
+ <key>Headers/MapnikStyleSet.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ 2VwRhwHcVwd5t6ZeFIMktdKk9e1TQMv7CoQWI3gCxtk=
+ </data>
+ </dict>
+ <key>Headers/NSData+Zlib.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ JQbrnrN+lNyruOEnF+WouqBXzAO+SgWmAKZFYSx5xbA=
+ </data>
+ </dict>
+ <key>Headers/NSDictionary+StyleRules.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ Q036mSm6ONEvutWOdPKRgh/nlmpUM+qVv2fIgEB3w20=
+ </data>
+ </dict>
+ <key>Headers/SLDExpressions.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ VnWjxKgmbETPsaM844p7Zh4icc4gGRCtZ3+OyGRqRM4=
+ </data>
+ </dict>
+ <key>Headers/SLDOperators.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ CVZVkqI8F95vU0q5Qg6HVXE7aBLBSNEotEYarsE82Ic=
+ </data>
+ </dict>
+ <key>Headers/SLDStyleSet.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ C+vXyX33RLYODYJvGz1sLH8hlN/XeO0xCJhAdQrdRjw=
+ </data>
+ </dict>
+ <key>Headers/SLDSymbolizers.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ +b9hFQFx3vasBtTpxOvJ4SovnrnBL18JBziRWLt6vyo=
+ </data>
+ </dict>
+ <key>Headers/SLDWellKnownMarkers.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ c1ldci6hgzLyJc5KwxoLZCleo8pHO/5R28mdJJu+LhE=
+ </data>
+ </dict>
+ <key>Headers/WGCoordinate.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ bhCCO7BoVhqlxGESHz9ODX/kNirEJ/7wjSCK09q2nwA=
+ </data>
+ </dict>
+ <key>Headers/WhirlyGlobe.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ MfSeR4N6wWUxK13sZie8AEzxCJUd6XBefFBkgffous8=
+ </data>
+ </dict>
+ <key>Headers/WhirlyGlobeComponent.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ AF84tc7f51e97Zyi2KKgkFmgkxRJwGxdFjv6V73biak=
+ </data>
+ </dict>
+ <key>Headers/WhirlyGlobeViewController.h</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ MJNKHq8MCDUb7/jgXJkb35WzrOpE5mPNJsT+9RVBHXA=
+ </data>
+ </dict>
+ <key>Modules/module.modulemap</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ W4RtgQMRvmRp5PtONuef68cOyp4dSlBf+laTyIyU2j4=
+ </data>
+ </dict>
+ <key>default.metallib</key>
+ <dict>
+ <key>hash2</key>
+ <data>
+ QVj3R4tZ+fgGhFVAPnXf7idXqZHndGb/awDKvAoep0I=
+ </data>
+ </dict>
+ </dict>
+ <key>rules</key>
+ <dict>
+ <key>^.*</key>
+ <true/>
+ <key>^.*\.lproj/</key>
+ <dict>
+ <key>optional</key>
+ <true/>
+ <key>weight</key>
+ <real>1000</real>
+ </dict>
+ <key>^.*\.lproj/locversion.plist$</key>
+ <dict>
+ <key>omit</key>
+ <true/>
+ <key>weight</key>
+ <real>1100</real>
+ </dict>
+ <key>^Base\.lproj/</key>
+ <dict>
+ <key>weight</key>
+ <real>1010</real>
+ </dict>
+ <key>^version.plist$</key>
+ <true/>
+ </dict>
+ <key>rules2</key>
+ <dict>
+ <key>.*\.dSYM($|/)</key>
+ <dict>
+ <key>weight</key>
+ <real>11</real>
+ </dict>
+ <key>^(.*/)?\.DS_Store$</key>
+ <dict>
+ <key>omit</key>
+ <true/>
+ <key>weight</key>
+ <real>2000</real>
+ </dict>
+ <key>^.*</key>
+ <true/>
+ <key>^.*\.lproj/</key>
+ <dict>
+ <key>optional</key>
+ <true/>
+ <key>weight</key>
+ <real>1000</real>
+ </dict>
+ <key>^.*\.lproj/locversion.plist$</key>
+ <dict>
+ <key>omit</key>
+ <true/>
+ <key>weight</key>
+ <real>1100</real>
+ </dict>
+ <key>^Base\.lproj/</key>
+ <dict>
+ <key>weight</key>
+ <real>1010</real>
+ </dict>
+ <key>^Info\.plist$</key>
+ <dict>
+ <key>omit</key>
+ <true/>
+ <key>weight</key>
+ <real>20</real>
+ </dict>
+ <key>^PkgInfo$</key>
+ <dict>
+ <key>omit</key>
+ <true/>
+ <key>weight</key>
+ <real>20</real>
+ </dict>
+ <key>^embedded\.provisionprofile$</key>
+ <dict>
+ <key>weight</key>
+ <real>20</real>
+ </dict>
+ <key>^version\.plist$</key>
+ <dict>
+ <key>weight</key>
+ <real>20</real>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/default.metallib b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/default.metallib
new file mode 100644
index 0000000..3f65869
--- /dev/null
+++ b/iosApp/WhirlyGlobe.xcframework/ios-arm64_x86_64-simulator/WhirlyGlobe.framework/default.metallib
Binary files differ
diff --git a/iosApp/iosApp.xcodeproj/project.pbxproj b/iosApp/iosApp.xcodeproj/project.pbxproj
index daef2d1..9bd7b9a 100644
--- a/iosApp/iosApp.xcodeproj/project.pbxproj
+++ b/iosApp/iosApp.xcodeproj/project.pbxproj
@@ -3,25 +3,58 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 50;
+ objectVersion = 52;
objects = {
/* Begin PBXBuildFile section */
058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557BA273AAA24004C7B11 /* Assets.xcassets */; };
058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */; };
2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2152FB032600AC8F00CF470E /* iOSApp.swift */; };
- 7555FF83242A565900829871 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF82242A565900829871 /* LoginView.swift */; };
- E3E77EDF279D2B5A00150070 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E3E77EDE279D2B5A00150070 /* Localizable.strings */; };
- E3E77EE3279D44E200150070 /* Koin.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3E77EE2279D44E200150070 /* Koin.swift */; };
+ 7555FF83242A565900829871 /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF82242A565900829871 /* RootView.swift */; };
+ E312E74F27B366060018C5DE /* DevicesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E312E74E27B366060018C5DE /* DevicesViewModel.swift */; };
+ E3385A4F27B0D8A10025311C /* UnitCommandsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3385A4E27B0D8A10025311C /* UnitCommandsViewModel.swift */; };
+ E33A236027A4FD2C00DD647F /* UnitMapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E33A235F27A4FD2C00DD647F /* UnitMapView.swift */; };
+ E33A236527A530F300DD647F /* SmallLabelStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = E33A236427A530F300DD647F /* SmallLabelStyle.swift */; };
+ E33A236727A64E4500DD647F /* MarkerTransformations.swift in Sources */ = {isa = PBXBuildFile; fileRef = E33A236627A64E4500DD647F /* MarkerTransformations.swift */; };
+ E33A236A27A6898700DD647F /* SwiftUIX in Frameworks */ = {isa = PBXBuildFile; productRef = E33A236927A6898700DD647F /* SwiftUIX */; };
+ E33A237127A7553500DD647F /* MapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E33A237027A7553500DD647F /* MapView.swift */; };
+ E33A237327A7581A00DD647F /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E33A237227A7581A00DD647F /* Utils.swift */; };
+ E34A2F4827A7878200AD8AEB /* HyperlinkText.swift in Sources */ = {isa = PBXBuildFile; fileRef = E34A2F4727A7878200AD8AEB /* HyperlinkText.swift */; };
+ E360251527BCA3AD00958B21 /* UserInformationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E360251427BCA3AD00958B21 /* UserInformationView.swift */; };
+ E360251727BCA83300958B21 /* AccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E360251627BCA83300958B21 /* AccountView.swift */; };
+ E360251927BCA84000958B21 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E360251827BCA84000958B21 /* AboutView.swift */; };
+ E360251B27BCA8A600958B21 /* AccountViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E360251A27BCA8A600958B21 /* AccountViewModel.swift */; };
+ E360251C27BCC97000958B21 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E360251E27BCC97000958B21 /* Localizable.strings */; };
+ E36A5A8627B4BFC40070DED5 /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = E36A5A8527B4BFC40070DED5 /* FirebaseMessaging */; };
+ E36DF77B27AB740C003C561C /* MapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E36DF77927AB740C003C561C /* MapViewController.swift */; };
+ E36DF77C27AB740C003C561C /* MapViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = E36DF77A27AB740C003C561C /* MapViewController.xib */; };
+ E38F241527A242870069FC45 /* Inject.swift in Sources */ = {isa = PBXBuildFile; fileRef = E38F241427A242870069FC45 /* Inject.swift */; };
+ E38F241727A242C70069FC45 /* Resolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = E38F241627A242C70069FC45 /* Resolver.swift */; };
+ E38F241C27A26DD70069FC45 /* RootViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E38F241B27A26DD70069FC45 /* RootViewModel.swift */; };
+ E38F241E27A270D50069FC45 /* UnitsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E38F241D27A270D50069FC45 /* UnitsView.swift */; };
+ E38F242027A27B550069FC45 /* LoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E38F241F27A27B550069FC45 /* LoadingView.swift */; };
+ E392BE1727B77B7E002698F3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E392BE1627B77B7E002698F3 /* AppDelegate.swift */; };
+ E392BE1927B791F0002698F3 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = E392BE1827B791F0002698F3 /* GoogleService-Info.plist */; };
+ E396281D27AF5723005D070E /* WhirlyGlobe.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = E396281B27AF56BA005D070E /* WhirlyGlobe.xcframework */; };
+ E396281E27AF5723005D070E /* WhirlyGlobe.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E396281B27AF56BA005D070E /* WhirlyGlobe.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ E396282027AF59F2005D070E /* DetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E396281F27AF59F2005D070E /* DetailsView.swift */; };
+ E396282427AFBD3D005D070E /* UnitInformationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E396282327AFBD3D005D070E /* UnitInformationView.swift */; };
+ E396282627AFBD4E005D070E /* UnitReportsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E396282527AFBD4E005D070E /* UnitReportsView.swift */; };
+ E396282827AFBD72005D070E /* UnitCommandsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E396282727AFBD72005D070E /* UnitCommandsView.swift */; };
+ E39ABC4327A4E88C00965D05 /* UnitsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E39ABC4227A4E88C00965D05 /* UnitsViewModel.swift */; };
+ E39ABC4627A4EBD500965D05 /* DevicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E39ABC4527A4EBD500965D05 /* DevicesView.swift */; };
+ E39ABC4827A4EDEC00965D05 /* DeviceRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E39ABC4727A4EDEC00965D05 /* DeviceRow.swift */; };
+ E3E77EE6279E6CE400150070 /* FlowCollector.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3E77EE5279E6CE400150070 /* FlowCollector.swift */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
- 7555FFB4242A642300829871 /* Embed Frameworks */ = {
+ E33A236F27A7545500DD647F /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
+ E396281E27AF5723005D070E /* WhirlyGlobe.xcframework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
@@ -33,10 +66,41 @@
058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
2152FB032600AC8F00CF470E /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = "<group>"; };
7555FF7B242A565900829871 /* iosApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iosApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
- 7555FF82242A565900829871 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; };
+ 7555FF82242A565900829871 /* RootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootView.swift; sourceTree = "<group>"; };
7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
- E3E77EDE279D2B5A00150070 /* Localizable.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = "<group>"; };
- E3E77EE2279D44E200150070 /* Koin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Koin.swift; sourceTree = "<group>"; };
+ E312E74E27B366060018C5DE /* DevicesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevicesViewModel.swift; sourceTree = "<group>"; };
+ E3385A4E27B0D8A10025311C /* UnitCommandsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitCommandsViewModel.swift; sourceTree = "<group>"; };
+ E33A235F27A4FD2C00DD647F /* UnitMapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitMapView.swift; sourceTree = "<group>"; };
+ E33A236427A530F300DD647F /* SmallLabelStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmallLabelStyle.swift; sourceTree = "<group>"; };
+ E33A236627A64E4500DD647F /* MarkerTransformations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkerTransformations.swift; sourceTree = "<group>"; };
+ E33A237027A7553500DD647F /* MapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapView.swift; sourceTree = "<group>"; };
+ E33A237227A7581A00DD647F /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = "<group>"; };
+ E34A2F4727A7878200AD8AEB /* HyperlinkText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HyperlinkText.swift; sourceTree = "<group>"; };
+ E360251427BCA3AD00958B21 /* UserInformationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInformationView.swift; sourceTree = "<group>"; };
+ E360251627BCA83300958B21 /* AccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountView.swift; sourceTree = "<group>"; };
+ E360251827BCA84000958B21 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = "<group>"; };
+ E360251A27BCA8A600958B21 /* AccountViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountViewModel.swift; sourceTree = "<group>"; };
+ E360251D27BCC97000958B21 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
+ E360251F27BCC97300958B21 /* es-419 */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-419"; path = "es-419.lproj/Localizable.strings"; sourceTree = "<group>"; };
+ E36A5A8927B4C8BB0070DED5 /* iosApp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = iosApp.entitlements; sourceTree = "<group>"; };
+ E36DF77927AB740C003C561C /* MapViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewController.swift; sourceTree = "<group>"; };
+ E36DF77A27AB740C003C561C /* MapViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MapViewController.xib; sourceTree = "<group>"; };
+ E38F241427A242870069FC45 /* Inject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Inject.swift; sourceTree = "<group>"; };
+ E38F241627A242C70069FC45 /* Resolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Resolver.swift; sourceTree = "<group>"; };
+ E38F241B27A26DD70069FC45 /* RootViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootViewModel.swift; sourceTree = "<group>"; };
+ E38F241D27A270D50069FC45 /* UnitsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitsView.swift; sourceTree = "<group>"; };
+ E38F241F27A27B550069FC45 /* LoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingView.swift; sourceTree = "<group>"; };
+ E392BE1627B77B7E002698F3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
+ E392BE1827B791F0002698F3 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
+ E396281B27AF56BA005D070E /* WhirlyGlobe.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = WhirlyGlobe.xcframework; sourceTree = "<group>"; };
+ E396281F27AF59F2005D070E /* DetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailsView.swift; sourceTree = "<group>"; };
+ E396282327AFBD3D005D070E /* UnitInformationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitInformationView.swift; sourceTree = "<group>"; };
+ E396282527AFBD4E005D070E /* UnitReportsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitReportsView.swift; sourceTree = "<group>"; };
+ E396282727AFBD72005D070E /* UnitCommandsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitCommandsView.swift; sourceTree = "<group>"; };
+ E39ABC4227A4E88C00965D05 /* UnitsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitsViewModel.swift; sourceTree = "<group>"; };
+ E39ABC4527A4EBD500965D05 /* DevicesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevicesView.swift; sourceTree = "<group>"; };
+ E39ABC4727A4EDEC00965D05 /* DeviceRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceRow.swift; sourceTree = "<group>"; };
+ E3E77EE5279E6CE400150070 /* FlowCollector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlowCollector.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -44,6 +108,9 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ E36A5A8627B4BFC40070DED5 /* FirebaseMessaging in Frameworks */,
+ E33A236A27A6898700DD647F /* SwiftUIX in Frameworks */,
+ E396281D27AF5723005D070E /* WhirlyGlobe.xcframework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -61,7 +128,6 @@
7555FF72242A565900829871 = {
isa = PBXGroup;
children = (
- E3E77EDE279D2B5A00150070 /* Localizable.strings */,
7555FF7D242A565900829871 /* iosApp */,
7555FF7C242A565900829871 /* Products */,
7555FFB0242A642200829871 /* Frameworks */,
@@ -79,13 +145,20 @@
7555FF7D242A565900829871 /* iosApp */ = {
isa = PBXGroup;
children = (
+ E392BE1827B791F0002698F3 /* GoogleService-Info.plist */,
+ E36A5A8927B4C8BB0070DED5 /* iosApp.entitlements */,
+ E360251E27BCC97000958B21 /* Localizable.strings */,
+ E33A235E27A4FD1C00DD647F /* Map */,
+ E35A078427AB615F00F24D71 /* Details */,
+ E39ABC4427A4EBB000965D05 /* Devices */,
+ E38F241A27A2659C0069FC45 /* Units */,
E3E77EE1279D43C000150070 /* Shared */,
058557BA273AAA24004C7B11 /* Assets.xcassets */,
- E3E77EE0279D43B400150070 /* Authentication */,
+ E3E77EE0279D43B400150070 /* Session */,
7555FF8C242A565B00829871 /* Info.plist */,
2152FB032600AC8F00CF470E /* iOSApp.swift */,
+ E392BE1627B77B7E002698F3 /* AppDelegate.swift */,
058557D7273AAEEB004C7B11 /* Preview Content */,
- E3E77EE2279D44E200150070 /* Koin.swift */,
);
path = iosApp;
sourceTree = "<group>";
@@ -93,21 +166,101 @@
7555FFB0242A642200829871 /* Frameworks */ = {
isa = PBXGroup;
children = (
+ E396281B27AF56BA005D070E /* WhirlyGlobe.xcframework */,
);
name = Frameworks;
sourceTree = "<group>";
};
- E3E77EE0279D43B400150070 /* Authentication */ = {
+ E33A235E27A4FD1C00DD647F /* Map */ = {
isa = PBXGroup;
children = (
- 7555FF82242A565900829871 /* LoginView.swift */,
+ E33A235F27A4FD2C00DD647F /* UnitMapView.swift */,
+ E33A237027A7553500DD647F /* MapView.swift */,
+ E36DF77927AB740C003C561C /* MapViewController.swift */,
+ E36DF77A27AB740C003C561C /* MapViewController.xib */,
);
- path = Authentication;
+ path = Map;
+ sourceTree = "<group>";
+ };
+ E35A078427AB615F00F24D71 /* Details */ = {
+ isa = PBXGroup;
+ children = (
+ E35A078727AB619700F24D71 /* Reports */,
+ E35A078627AB619000F24D71 /* Information */,
+ E35A078527AB618700F24D71 /* Commands */,
+ E396281F27AF59F2005D070E /* DetailsView.swift */,
+ );
+ path = Details;
+ sourceTree = "<group>";
+ };
+ E35A078527AB618700F24D71 /* Commands */ = {
+ isa = PBXGroup;
+ children = (
+ E396282727AFBD72005D070E /* UnitCommandsView.swift */,
+ E3385A4E27B0D8A10025311C /* UnitCommandsViewModel.swift */,
+ );
+ path = Commands;
+ sourceTree = "<group>";
+ };
+ E35A078627AB619000F24D71 /* Information */ = {
+ isa = PBXGroup;
+ children = (
+ E396282327AFBD3D005D070E /* UnitInformationView.swift */,
+ );
+ path = Information;
+ sourceTree = "<group>";
+ };
+ E35A078727AB619700F24D71 /* Reports */ = {
+ isa = PBXGroup;
+ children = (
+ E396282527AFBD4E005D070E /* UnitReportsView.swift */,
+ );
+ path = Reports;
+ sourceTree = "<group>";
+ };
+ E38F241A27A2659C0069FC45 /* Units */ = {
+ isa = PBXGroup;
+ children = (
+ E38F241D27A270D50069FC45 /* UnitsView.swift */,
+ E39ABC4227A4E88C00965D05 /* UnitsViewModel.swift */,
+ );
+ path = Units;
+ sourceTree = "<group>";
+ };
+ E39ABC4427A4EBB000965D05 /* Devices */ = {
+ isa = PBXGroup;
+ children = (
+ E39ABC4527A4EBD500965D05 /* DevicesView.swift */,
+ E39ABC4727A4EDEC00965D05 /* DeviceRow.swift */,
+ E312E74E27B366060018C5DE /* DevicesViewModel.swift */,
+ );
+ path = Devices;
+ sourceTree = "<group>";
+ };
+ E3E77EE0279D43B400150070 /* Session */ = {
+ isa = PBXGroup;
+ children = (
+ 7555FF82242A565900829871 /* RootView.swift */,
+ E38F241B27A26DD70069FC45 /* RootViewModel.swift */,
+ E360251427BCA3AD00958B21 /* UserInformationView.swift */,
+ E360251627BCA83300958B21 /* AccountView.swift */,
+ E360251827BCA84000958B21 /* AboutView.swift */,
+ E360251A27BCA8A600958B21 /* AccountViewModel.swift */,
+ );
+ path = Session;
sourceTree = "<group>";
};
E3E77EE1279D43C000150070 /* Shared */ = {
isa = PBXGroup;
children = (
+ E3E77EE5279E6CE400150070 /* FlowCollector.swift */,
+ E38F241427A242870069FC45 /* Inject.swift */,
+ E38F241627A242C70069FC45 /* Resolver.swift */,
+ E38F241F27A27B550069FC45 /* LoadingView.swift */,
+ E33A236427A530F300DD647F /* SmallLabelStyle.swift */,
+ E33A236627A64E4500DD647F /* MarkerTransformations.swift */,
+ E33A237227A7581A00DD647F /* Utils.swift */,
+ E34A2F4727A7878200AD8AEB /* HyperlinkText.swift */,
);
path = Shared;
sourceTree = "<group>";
@@ -123,13 +276,17 @@
7555FF77242A565900829871 /* Sources */,
7555FF78242A565900829871 /* Frameworks */,
7555FF79242A565900829871 /* Resources */,
- 7555FFB4242A642300829871 /* Embed Frameworks */,
+ E33A236F27A7545500DD647F /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = iosApp;
+ packageProductDependencies = (
+ E33A236927A6898700DD647F /* SwiftUIX */,
+ E36A5A8527B4BFC40070DED5 /* FirebaseMessaging */,
+ );
productName = iosApp;
productReference = 7555FF7B242A565900829871 /* iosApp.app */;
productType = "com.apple.product-type.application";
@@ -146,6 +303,7 @@
TargetAttributes = {
7555FF7A242A565900829871 = {
CreatedOnToolsVersion = 11.3.1;
+ LastSwiftMigration = 1320;
};
};
};
@@ -159,6 +317,10 @@
"es-419",
);
mainGroup = 7555FF72242A565900829871;
+ packageReferences = (
+ E33A236827A6898700DD647F /* XCRemoteSwiftPackageReference "SwiftUIX" */,
+ E36A5A8427B4BFC40070DED5 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */,
+ );
productRefGroup = 7555FF7C242A565900829871 /* Products */;
projectDirPath = "";
projectRoot = "";
@@ -174,8 +336,10 @@
buildActionMask = 2147483647;
files = (
058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */,
- E3E77EDF279D2B5A00150070 /* Localizable.strings in Resources */,
+ E360251C27BCC97000958B21 /* Localizable.strings in Resources */,
+ E392BE1927B791F0002698F3 /* GoogleService-Info.plist in Resources */,
058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */,
+ E36DF77C27AB740C003C561C /* MapViewController.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -206,14 +370,52 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- E3E77EE3279D44E200150070 /* Koin.swift in Sources */,
+ E396282627AFBD4E005D070E /* UnitReportsView.swift in Sources */,
+ E33A237127A7553500DD647F /* MapView.swift in Sources */,
+ E396282027AF59F2005D070E /* DetailsView.swift in Sources */,
+ E38F241727A242C70069FC45 /* Resolver.swift in Sources */,
+ E33A236027A4FD2C00DD647F /* UnitMapView.swift in Sources */,
+ E396282427AFBD3D005D070E /* UnitInformationView.swift in Sources */,
+ E360251727BCA83300958B21 /* AccountView.swift in Sources */,
+ E360251527BCA3AD00958B21 /* UserInformationView.swift in Sources */,
+ E360251927BCA84000958B21 /* AboutView.swift in Sources */,
+ E312E74F27B366060018C5DE /* DevicesViewModel.swift in Sources */,
+ E33A236727A64E4500DD647F /* MarkerTransformations.swift in Sources */,
+ E38F241527A242870069FC45 /* Inject.swift in Sources */,
+ E39ABC4827A4EDEC00965D05 /* DeviceRow.swift in Sources */,
+ E396282827AFBD72005D070E /* UnitCommandsView.swift in Sources */,
+ E38F241C27A26DD70069FC45 /* RootViewModel.swift in Sources */,
+ E3385A4F27B0D8A10025311C /* UnitCommandsViewModel.swift in Sources */,
+ E392BE1727B77B7E002698F3 /* AppDelegate.swift in Sources */,
+ E36DF77B27AB740C003C561C /* MapViewController.swift in Sources */,
+ E33A237327A7581A00DD647F /* Utils.swift in Sources */,
+ E3E77EE6279E6CE400150070 /* FlowCollector.swift in Sources */,
+ E33A236527A530F300DD647F /* SmallLabelStyle.swift in Sources */,
+ E39ABC4327A4E88C00965D05 /* UnitsViewModel.swift in Sources */,
+ E360251B27BCA8A600958B21 /* AccountViewModel.swift in Sources */,
+ E34A2F4827A7878200AD8AEB /* HyperlinkText.swift in Sources */,
2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */,
- 7555FF83242A565900829871 /* LoginView.swift in Sources */,
+ E39ABC4627A4EBD500965D05 /* DevicesView.swift in Sources */,
+ E38F242027A27B550069FC45 /* LoadingView.swift in Sources */,
+ E38F241E27A270D50069FC45 /* UnitsView.swift in Sources */,
+ 7555FF83242A565900829871 /* RootView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
+/* Begin PBXVariantGroup section */
+ E360251E27BCC97000958B21 /* Localizable.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ E360251D27BCC97000958B21 /* en */,
+ E360251F27BCC97300958B21 /* es-419 */,
+ );
+ name = Localizable.strings;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
/* Begin XCBuildConfiguration section */
7555FFA3242A565B00829871 /* Debug */ = {
isa = XCBuildConfiguration;
@@ -335,11 +537,18 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_ENTITLEMENTS = iosApp/iosApp.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
DEVELOPMENT_TEAM = 358YRZ9P3L;
ENABLE_PREVIEWS = YES;
- FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)";
+ EXCLUDED_ARCHS = "";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)",
+ "$(PROJECT_DIR)",
+ );
INFOPLIST_FILE = iosApp/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@@ -350,8 +559,11 @@
"-framework",
shared,
);
- PRODUCT_BUNDLE_IDENTIFIER = mx.trackermap.TrackerMap;
+ PRODUCT_BUNDLE_IDENTIFIER = mx.trackermap.trackermap.ios;
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SWIFT_OBJC_BRIDGING_HEADER = "";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
@@ -361,11 +573,18 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_ENTITLEMENTS = iosApp/iosApp.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
DEVELOPMENT_TEAM = 358YRZ9P3L;
ENABLE_PREVIEWS = YES;
- FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)";
+ EXCLUDED_ARCHS = "";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)",
+ "$(PROJECT_DIR)",
+ );
INFOPLIST_FILE = iosApp/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@@ -376,8 +595,10 @@
"-framework",
shared,
);
- PRODUCT_BUNDLE_IDENTIFIER = mx.trackermap.TrackerMap;
+ PRODUCT_BUNDLE_IDENTIFIER = mx.trackermap.trackermap.ios;
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
@@ -405,6 +626,38 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
+
+/* Begin XCRemoteSwiftPackageReference section */
+ E33A236827A6898700DD647F /* XCRemoteSwiftPackageReference "SwiftUIX" */ = {
+ isa = XCRemoteSwiftPackageReference;
+ repositoryURL = "https://github.com/ivan-avalos/SwiftUIX";
+ requirement = {
+ branch = master;
+ kind = branch;
+ };
+ };
+ E36A5A8427B4BFC40070DED5 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = {
+ isa = XCRemoteSwiftPackageReference;
+ repositoryURL = "https://github.com/firebase/firebase-ios-sdk.git";
+ requirement = {
+ kind = upToNextMajorVersion;
+ minimumVersion = 8.0.0;
+ };
+ };
+/* End XCRemoteSwiftPackageReference section */
+
+/* Begin XCSwiftPackageProductDependency section */
+ E33A236927A6898700DD647F /* SwiftUIX */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = E33A236827A6898700DD647F /* XCRemoteSwiftPackageReference "SwiftUIX" */;
+ productName = SwiftUIX;
+ };
+ E36A5A8527B4BFC40070DED5 /* FirebaseMessaging */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = E36A5A8427B4BFC40070DED5 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
+ productName = FirebaseMessaging;
+ };
+/* End XCSwiftPackageProductDependency section */
};
rootObject = 7555FF73242A565900829871 /* Project object */;
}
diff --git a/iosApp/iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/iosApp/iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/iosApp/iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:">
+ </FileRef>
+</Workspace>
diff --git a/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IDEDidComputeMac32BitWarning</key>
+ <true/>
+</dict>
+</plist>
diff --git a/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
new file mode 100644
index 0000000..7032494
--- /dev/null
+++ b/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -0,0 +1,124 @@
+{
+ "object": {
+ "pins": [
+ {
+ "package": "abseil",
+ "repositoryURL": "https://github.com/firebase/abseil-cpp-SwiftPM.git",
+ "state": {
+ "branch": null,
+ "revision": "fffc3c2729be5747390ad02d5100291a0d9ad26a",
+ "version": "0.20200225.4"
+ }
+ },
+ {
+ "package": "BoringSSL-GRPC",
+ "repositoryURL": "https://github.com/firebase/boringssl-SwiftPM.git",
+ "state": {
+ "branch": null,
+ "revision": "734a8247442fde37df4364c21f6a0085b6a36728",
+ "version": "0.7.2"
+ }
+ },
+ {
+ "package": "Firebase",
+ "repositoryURL": "https://github.com/firebase/firebase-ios-sdk.git",
+ "state": {
+ "branch": null,
+ "revision": "78f7087fd5d48eb7c36e299f330b6dddccd647b2",
+ "version": "8.12.1"
+ }
+ },
+ {
+ "package": "GoogleAppMeasurement",
+ "repositoryURL": "https://github.com/google/GoogleAppMeasurement.git",
+ "state": {
+ "branch": null,
+ "revision": "6cc2991c11872510a5314bc112cc7558dd9d046a",
+ "version": "8.12.0"
+ }
+ },
+ {
+ "package": "GoogleDataTransport",
+ "repositoryURL": "https://github.com/google/GoogleDataTransport.git",
+ "state": {
+ "branch": null,
+ "revision": "15ccdfd25ac55b9239b82809531ff26605e7556e",
+ "version": "9.1.2"
+ }
+ },
+ {
+ "package": "GoogleUtilities",
+ "repositoryURL": "https://github.com/google/GoogleUtilities.git",
+ "state": {
+ "branch": null,
+ "revision": "b3bb0c5551fb3f80ca939829639ab5b093edd14f",
+ "version": "7.7.0"
+ }
+ },
+ {
+ "package": "gRPC",
+ "repositoryURL": "https://github.com/firebase/grpc-SwiftPM.git",
+ "state": {
+ "branch": null,
+ "revision": "fb405dd2c7901485f7e158b24e3a0a47e4efd8b5",
+ "version": "1.28.4"
+ }
+ },
+ {
+ "package": "GTMSessionFetcher",
+ "repositoryURL": "https://github.com/google/gtm-session-fetcher.git",
+ "state": {
+ "branch": null,
+ "revision": "bc6a19702ac76ac4e488b68148710eb815f9bc56",
+ "version": "1.7.0"
+ }
+ },
+ {
+ "package": "leveldb",
+ "repositoryURL": "https://github.com/firebase/leveldb.git",
+ "state": {
+ "branch": null,
+ "revision": "0706abcc6b0bd9cedfbb015ba840e4a780b5159b",
+ "version": "1.22.2"
+ }
+ },
+ {
+ "package": "nanopb",
+ "repositoryURL": "https://github.com/firebase/nanopb.git",
+ "state": {
+ "branch": null,
+ "revision": "7ee9ef9f627d85cbe1b8c4f49a3ed26eed216c77",
+ "version": "2.30908.0"
+ }
+ },
+ {
+ "package": "Promises",
+ "repositoryURL": "https://github.com/google/promises.git",
+ "state": {
+ "branch": null,
+ "revision": "611337c330350c9c1823ad6d671e7f936af5ee13",
+ "version": "2.0.0"
+ }
+ },
+ {
+ "package": "SwiftProtobuf",
+ "repositoryURL": "https://github.com/apple/swift-protobuf.git",
+ "state": {
+ "branch": null,
+ "revision": "7e2c5f3cbbeea68e004915e3a8961e20bd11d824",
+ "version": "1.18.0"
+ }
+ },
+ {
+ "package": "SwiftUIX",
+ "repositoryURL": "https://github.com/ivan-avalos/SwiftUIX",
+ "state": {
+ "branch": "master",
+ "revision": "9b02351a947aa5ac1d2b3a5d576f9591960a89fc",
+ "version": null
+ }
+ }
+ ]
+ },
+ "version": 1
+}
diff --git a/iosApp/iosApp.xcodeproj/xcshareddata/xcschemes/iosApp.xcscheme b/iosApp/iosApp.xcodeproj/xcshareddata/xcschemes/iosApp.xcscheme
new file mode 100644
index 0000000..5b29c0a
--- /dev/null
+++ b/iosApp/iosApp.xcodeproj/xcshareddata/xcschemes/iosApp.xcscheme
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "1320"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "7555FF7A242A565900829871"
+ BuildableName = "iosApp.app"
+ BlueprintName = "iosApp"
+ ReferencedContainer = "container:iosApp.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ </Testables>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "7555FF7A242A565900829871"
+ BuildableName = "iosApp.app"
+ BlueprintName = "iosApp"
+ ReferencedContainer = "container:iosApp.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "7555FF7A242A565900829871"
+ BuildableName = "iosApp.app"
+ BlueprintName = "iosApp"
+ ReferencedContainer = "container:iosApp.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
diff --git a/iosApp/iosApp.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/iosApp/iosApp.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/iosApp/iosApp.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IDEDidComputeMac32BitWarning</key>
+ <true/>
+</dict>
+</plist>
diff --git a/iosApp/iosApp/AppDelegate.swift b/iosApp/iosApp/AppDelegate.swift
new file mode 100644
index 0000000..4233910
--- /dev/null
+++ b/iosApp/iosApp/AppDelegate.swift
@@ -0,0 +1,62 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import Foundation
+import UIKit
+import Firebase
+import FirebaseMessaging
+
+class AppDelegate: NSObject, UIApplicationDelegate {
+ func application(_ application: UIApplication,
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
+ FirebaseApp.configure()
+ Messaging.messaging().delegate = self
+
+ UNUserNotificationCenter.current().delegate = self
+ let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
+ UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { _, _ in }
+
+ application.registerForRemoteNotifications()
+
+ return true
+ }
+
+ func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) async -> UIBackgroundFetchResult {
+ print(userInfo)
+ return UIBackgroundFetchResult.newData
+ }
+}
+
+extension AppDelegate: UNUserNotificationCenterDelegate {
+ func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification) async -> UNNotificationPresentationOptions {
+ let userInfo = notification.request.content.userInfo
+ print(userInfo)
+ return [.banner, .badge, .sound]
+ }
+
+ func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async {
+ let userInfo = response.notification.request.content.userInfo
+ print(userInfo)
+ }
+}
+
+extension AppDelegate: MessagingDelegate {
+ func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
+ print ("didReceiveRegistrationToken fcmToken:\(String(describing: fcmToken))")
+ UserDefaults.standard.set(fcmToken, forKey: "fcmtoken")
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapAnimal.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapAnimal.imageset/Contents.json
new file mode 100644
index 0000000..52185f2
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapAnimal.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "animal.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapAnimal.imageset/animal.svg b/iosApp/iosApp/Assets.xcassets/MapAnimal.imageset/animal.svg
new file mode 100644
index 0000000..a077029
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapAnimal.imageset/animal.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1">
+ <path id="background" d="m20.002 3.6816l-1.131 3.3907a12.374 12.374 0 0 1 1.131 -0.0625 12.374 12.374 0 0 1 1.129 0.0566l-1.129-3.3848zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke="#333" stroke-width="1.9" fill="#008000"/>
+ <path id="icon" d="m19.525 15.802q0 0.5865-0.17372 1.1144-0.17372 0.51808-0.57602 0.8993t-0.96004 0.38122q-0.69489 0-1.2618-0.55718-0.56688-0.56695-0.84118-1.3294t-0.2743-1.476q0-0.5865 0.17372-1.1046 0.17372-0.52785 0.57602-0.90908 0.4023-0.38122 0.96004-0.38122 0.70403 0 1.2618 0.56695 0.56688 0.55718 0.84118 1.3196 0.2743 0.75268 0.2743 1.476zm-3.127 4.7213q0 0.782-0.38402 1.3587-0.38402 0.57672-1.088 0.57672-0.69489 0-1.2983-0.53763-0.59431-0.5474-0.91432-1.3099-0.32001-0.76245-0.32001-1.4858 0-0.782 0.38402-1.3587 0.38402-0.5865 1.088-0.5865 0.69488 0 1.2892 0.5474 0.60345 0.53763 0.92347 1.3099 0.32001 0.76245 0.32001 1.4858zm3.602-0.264q1.0789 0 2.3315 0.95795 1.2526 0.94818 2.0938 2.3167 0.84118 1.3587 0.84118 2.4829 0 0.44965-0.15544 0.7429-0.15544 0.30302-0.44802 0.43988-0.28344 0.14662-0.58517 0.1955-0.30173 0.05865-0.69489 0.05865-0.62174 0-1.7189-0.43988-1.088-0.44-1.664-0.44-0.60345 0-1.7646 0.4301-1.152 0.43988-1.8286 0.43988-1.6732 0-1.6732-1.4272 0-0.84065 0.51202-1.867 0.51202-1.0362 1.2709-1.8866 0.76803-0.85043 1.7189-1.4272 0.951-0.577 1.765-0.577zm2.1852-2.0625q-0.55774 0-0.96004-0.38122t-0.57602-0.8993q-0.17372-0.52785-0.17372-1.1144 0-0.72335 0.2743-1.476 0.2743-0.76245 0.83204-1.3196 0.56688-0.56695 1.2709-0.56695 0.55774 0 0.96004 0.38122t0.57602 0.90908q0.17372 0.51808 0.17372 1.1046 0 0.71358-0.2743 1.476-0.2743 0.76245-0.84118 1.3294-0.56688 0.55718-1.2618 0.55718zm3.9499-1.0166q0.70403 0 1.088 0.5865 0.38402 0.57673 0.38402 1.3587 0 0.72335-0.32001 1.4858t-0.92347 1.3099q-0.59431 0.53763-1.2892 0.53763-0.70403 0-1.088-0.57672-0.38402-0.57673-0.38402-1.3587 0-0.72335 0.32001-1.4858 0.32001-0.77222 0.91432-1.3099 0.60345-0.5474 1.2983-0.5474z"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapArrow.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapArrow.imageset/Contents.json
new file mode 100644
index 0000000..58372bf
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapArrow.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "arrow.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapArrow.imageset/arrow.svg b/iosApp/iosApp/Assets.xcassets/MapArrow.imageset/arrow.svg
new file mode 100644
index 0000000..1aed6e0
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapArrow.imageset/arrow.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg3369" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="26" viewBox="0 0 26 26" width="26" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <polygon id="arrow" stroke="#000" points="19 22 13 19 7 22 13 4" stroke-width="1px" fill="#008000"/>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapBicycle.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapBicycle.imageset/Contents.json
new file mode 100644
index 0000000..c2c34bb
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapBicycle.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "bicycle.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapBicycle.imageset/bicycle.svg b/iosApp/iosApp/Assets.xcassets/MapBicycle.imageset/bicycle.svg
new file mode 100644
index 0000000..4eb82ea
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapBicycle.imageset/bicycle.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1">
+ <path id="background" d="m20.002 3.6816l-1.131 3.3907a12.374 12.374 0 0 1 1.131 -0.0625 12.374 12.374 0 0 1 1.129 0.0566l-1.129-3.3848zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke="#333" stroke-width="1.9" fill="#008000"/>
+ <path id="icon" d="m16.793 22.105h-2.5821q-0.32893 0-0.47695-0.28781-0.1398-0.28782 0.05757-0.55096l1.546-2.064q-0.53451-0.25492-1.1266-0.25492-1.0855 0-1.8585 0.77299-0.77299 0.77299-0.77299 1.8585t0.77299 1.8585q0.77299 0.77299 1.8585 0.77299 0.94568 0 1.6693-0.59208 0.72365-0.6003 0.91278-1.5131zm-1.5295-1.0526h1.5295q-0.14802-0.69898-0.61674-1.217l-0.91278 1.217zm3.9472 0 2.3683-3.1577h-3.9472l-0.8141 1.0855q0.86344 0.847 1.0361 2.0723h1.3568zm8.4371 2.3848q0.77299-0.77299 0.77299-1.8585t-0.77299-1.8585q-0.77299-0.77299-1.8585-0.77299-0.4934 0-0.99502 0.19736l1.4308 2.1381q0.12335 0.18914 0.08224 0.40294-0.04112 0.2138-0.22203 0.32893-0.12335 0.09046-0.29604 0.09046-0.28781 0-0.43583-0.23847l-1.4308-2.1381q-0.76476 0.78121-0.76476 1.8502 0 1.0855 0.77299 1.8585 0.77299 0.77299 1.8585 0.77299t1.8585-0.77299zm0.74009-4.457q1.0855 1.0772 1.0855 2.5986 0 1.5213-1.0855 2.6068-1.0772 1.0772-2.5986 1.0772-1.5213 0-2.6068-1.0772-1.0772-1.0855-1.0772-2.6068 0-0.79766 0.32071-1.5049 0.32893-0.71542 0.90456-1.2335l-0.53451-0.80588-2.9028 3.8567q-0.14802 0.2138-0.41939 0.2138h-1.62q-0.18914 1.3486-1.2253 2.2532-1.0361 0.90456-2.4176 0.90456-1.5213 0-2.6068-1.0772-1.0772-1.0855-1.0772-2.6068t1.0772-2.5986q1.0855-1.0855 2.6068-1.0855 0.93745 0 1.768 0.45228l1.1266-1.5049h-1.842q-0.21381 0-0.37005-0.15624t-0.15624-0.37005q0-0.2138 0.15624-0.37005 0.15624-0.15624 0.37005-0.15624h3.1577v1.0526h3.5771l-0.69898-1.0526h-1.8256q-0.21381 0-0.37005-0.15624t-0.15624-0.37005 0.15624-0.37005 0.37005-0.15624h2.1052q0.27137 0 0.43583 0.23025l2.1956 3.2893q0.74832-0.36182 1.5789-0.36182 1.5213 0 2.5986 1.0855z"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapBoat.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapBoat.imageset/Contents.json
new file mode 100644
index 0000000..7638406
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapBoat.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "boat.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapBoat.imageset/boat.svg b/iosApp/iosApp/Assets.xcassets/MapBoat.imageset/boat.svg
new file mode 100644
index 0000000..f1620ca
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapBoat.imageset/boat.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1">
+ <path id="background" d="m20.002 3.6816-1.1309 3.3906a12.374 12.374 0 0 1 1.1309 -0.0625 12.374 12.374 0 0 1 1.1289 0.056641l-1.129-3.3847zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke="#333" stroke-width="1.9" fill="#008000"/>
+ <path id="icon" stroke-width=".78953" d="m20 11.146c-2.1317 5.5267-6.3162 6.785-6.3162 6.785l6.316 1.9v-8.685zm0 8.6848h-6.711v0.64149c0 0.93043 0.77808 1.7633 1.8011 2.3686-0.36215 0.12387-0.72989 0.14804-1.0116 0.14804-0.55267 0-1.4212-0.15791-1.9738-0.78953v1.5791c0.55267 0.63162 1.4212 0.78953 1.9738 0.78953 0.55267 0 1.4212-0.15791 1.9738-0.78953 0.55267 0.63162 1.4212 0.78953 1.9738 0.78953 0.55267 0 1.4212-0.15791 1.9738-0.78953 0.55267 0.63162 1.4212 0.78953 1.9738 0.78953 0.55267 0 1.4212-0.15791 1.9738-0.78953 0.55267 0.63162 1.4212 0.78953 1.9738 0.78953 0.55267 0 1.4212-0.15791 1.9738-0.78953v-1.5791c-0.55267 0.63162-1.4212 0.78953-1.9738 0.78953-0.39586 0-0.94322-0.09201-1.431-0.37009 1.0794-0.59227 2.1544-1.4653 2.9361-2.788h-2.6893-4.7372zm4.7372 0s0.0099-4.0167-3.3062-7.2538c0.63162 4.3424-0.64149 5.9215-0.64149 5.9215l3.9476 1.3323zm-12.632 4.7372v1.5791c0.55267 0.63162 1.4212 0.78953 1.9738 0.78953 0.55267 0 1.4212-0.1579 1.9738-0.78953 0.55267 0.63162 1.4212 0.78953 1.9738 0.78953 0.55267 0 1.4212-0.1579 1.9738-0.78953 0.55267 0.63162 1.4212 0.78953 1.9738 0.78953 0.55267 0 1.4212-0.1579 1.9738-0.78953 0.55267 0.63162 1.4212 0.78953 1.9738 0.78953 0.55267 0 1.4212-0.1579 1.9738-0.78953v-1.5791c-0.55267 0.63162-1.4212 0.78953-1.9738 0.78953-0.55267 0-1.4212-0.1579-1.9738-0.78953-0.55267 0.63162-1.4212 0.78953-1.9738 0.78953-0.55267 0-1.4212-0.1579-1.9738-0.78953-0.55267 0.63162-1.4212 0.78953-1.9738 0.78953-0.55267 0-1.4212-0.1579-1.9738-0.78953-0.55267 0.63162-1.4212 0.78953-1.9738 0.78953-0.55267 0-1.4212-0.1579-1.9738-0.78953z"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapBus.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapBus.imageset/Contents.json
new file mode 100644
index 0000000..08eac12
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapBus.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "bus.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapBus.imageset/bus.svg b/iosApp/iosApp/Assets.xcassets/MapBus.imageset/bus.svg
new file mode 100644
index 0000000..2f3b923
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapBus.imageset/bus.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1">
+ <path id="background" d="m20.002 3.6816l-1.131 3.3907a12.374 12.374 0 0 1 1.131 -0.0625 12.374 12.374 0 0 1 1.129 0.0566l-1.129-3.3848zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke="#333" stroke-width="1.9" fill="#008000"/>
+ <path id="icon" d="m16.144 23.756q0.34724-0.34724 0.34724-0.83154t-0.34724-0.8224q-0.3381-0.34724-0.8224-0.34724-0.48431 0-0.83154 0.34724-0.3381 0.3381-0.3381 0.8224 0 0.48431 0.3381 0.83154 0.34724 0.3381 0.83154 0.3381t0.8224-0.3381zm9.3571 0q0.34724-0.34724 0.34724-0.83154t-0.34724-0.8224q-0.3381-0.34724-0.8224-0.34724-0.48431 0-0.83154 0.34724-0.3381 0.3381-0.3381 0.8224 0 0.48431 0.3381 0.83154 0.34724 0.3381 0.83154 0.3381t0.8224-0.3381zm-0.0731-4.4501-0.65793-3.5089q-0.04569-0.21017-0.21017-0.3381-0.15534-0.13707-0.36551-0.13707h-8.3885q-0.21017 0-0.37465 0.13707-0.15534 0.12793-0.20103 0.3381l-0.65792 3.5089q-0.046 0.274 0.128 0.484t0.448 0.21h9.7044q0.27414 0 0.44775-0.21017 0.17362-0.21017 0.12794-0.48431zm-2.193-5.282q0.12794-0.12794 0.12794-0.31069 0-0.18276-0.12794-0.31069-0.12793-0.12794-0.31069-0.12794h-5.8482q-0.18276 0-0.31069 0.12794-0.12793 0.12793-0.12793 0.31069t0.12793 0.31069q0.12794 0.12794 0.31069 0.12794h5.8482q0.18276 0 0.31069-0.12794zm3.7831 6.3142v5.5101h-1.1696v1.1696q0 0.48431-0.34724 0.8224-0.3381 0.34724-0.8224 0.34724-0.48431 0-0.83154-0.34724-0.3381-0.3381-0.3381-0.8224v-1.1696h-7.0179v1.1696q0 0.48431-0.34724 0.8224-0.3381 0.34724-0.8224 0.34724-0.48431 0-0.83154-0.34724-0.3381-0.3381-0.3381-0.8224v-1.1696h-1.1696v-5.5101q0-1.0234 0.22844-2.0377l0.9412-4.1486q0.08224-0.71275 0.88637-1.2519 0.81327-0.53913 2.1017-0.81327 1.2976-0.27414 2.8601-0.27414 1.5626 0 2.851 0.27414 1.2976 0.27413 2.1017 0.81327 0.81327 0.53913 0.89551 1.2519l0.95948 4.1486q0.21017 0.93206 0.21017 2.0377z"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapCar.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapCar.imageset/Contents.json
new file mode 100644
index 0000000..99d7aad
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapCar.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "car.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapCar.imageset/car.svg b/iosApp/iosApp/Assets.xcassets/MapCar.imageset/car.svg
new file mode 100644
index 0000000..da5b555
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapCar.imageset/car.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1" stroke="#333">
+ <path id="background" d="m20.002 3.6816l-1.131 3.3907a12.374 12.374 0 0 1 1.131 -0.0625 12.374 12.374 0 0 1 1.129 0.0566l-1.129-3.3848zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke-width="1.9" fill="#008000"/>
+ <path id="icon" d="m15.029 22.296q0.39535-0.39535 0.39535-0.95053t-0.39535-0.95053q-0.396-0.395-0.951-0.395-0.55518 0-0.95053 0.39535t-0.39535 0.95053 0.39535 0.95053 0.95053 0.39535 0.95053-0.39535zm0.69818-3.6423h8.5463l-0.74865-3.003q-0.01682-0.06729-0.11777-0.143-0.10094-0.08412-0.17665-0.08412h-6.4602q-0.07572 0-0.17665 0.08412-0.10095 0.07571-0.11777 0.143l-0.74865 3.003zm11.146 3.6423q0.39535-0.39535 0.39535-0.95053t-0.39535-0.95053q-0.396-0.395-0.951-0.395-0.55518 0-0.95053 0.39535t-0.39535 0.95053 0.39535 0.95053 0.95053 0.39535 0.95053-0.39535zm1.7412-1.7581v3.2301q0 0.11777-0.07571 0.19347-0.07572 0.07571-0.19347 0.07571h-0.80753v1.0767q0 0.67294-0.47106 1.144t-1.144 0.47106-1.144-0.47106-0.47106-1.144v-1.0767h-8.6136v1.0767q0 0.67294-0.47106 1.144t-1.144 0.47106-1.144-0.47106-0.47106-1.144v-1.0767h-0.80753q-0.11777 0-0.19347-0.07571-0.07571-0.07572-0.07571-0.19347v-3.2301q0-0.78229 0.54676-1.3291 0.55518-0.55518 1.3375-0.55518h0.23553l0.88324-3.5245q0.19347-0.7907 0.87482-1.3206 0.68135-0.53835 1.5057-0.53835h6.4602q0.82435 0 1.5057 0.53835 0.68135 0.52994 0.87482 1.3206l0.88323 3.5245h0.23553q0.78229 0 1.3291 0.55518 0.55518 0.54676 0.55518 1.3291z" stroke-width=".1"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapCrane.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapCrane.imageset/Contents.json
new file mode 100644
index 0000000..76c7751
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapCrane.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "crane.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapCrane.imageset/crane.svg b/iosApp/iosApp/Assets.xcassets/MapCrane.imageset/crane.svg
new file mode 100644
index 0000000..6b66b77
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapCrane.imageset/crane.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1">
+ <path id="background" d="m20.002 3.6816-1.1309 3.3906a12.374 12.374 0 0 1 1.1309 -0.0625 12.374 12.374 0 0 1 1.1289 0.056641l-1.129-3.3847zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke="#333" stroke-width="1.9" fill="#008000"/>
+ <path id="icon" stroke-width=".75357" d="m24.334 12.464-4.2153 3.0143c0.10399 0.11605 0.20347 0.23888 0.28259 0.37679l0.51808 0.91842 2.0252-1.4601-1.5778 2.2372 0.49453 0.87132c0.14017 0.18613 0.25282 0.39374 0.32969 0.61228l4.5921-6.5702h-2.4491zm2.4491 1.3188-1.5071 2.143v4.074c0 0.41597 0.3376 0.75357 0.75358 0.75357 0.41522 0 0.75357 0.33836 0.75357 0.75358s-0.33836 0.75357-0.75357 0.75357c-0.41522 0-0.75358-0.33835-0.75358-0.75357h-1.5071c0 1.3858 1.2521 2.4766 2.6846 2.2136 0.88771-0.16277 1.6164-0.87999 1.7897-1.7662 0.22909-1.1718-0.45328-2.2074-1.4601-2.5669v-5.6047zm-12.057 1.6955c-0.8327 0-1.5071 0.67445-1.5071 1.5071v3.7679c0 0.41597 0.3376 0.75358 0.75358 0.75358h0.75357v0.75357h5.275v-0.75357h0.75358c0.41597 0 0.75358-0.3376 0.75358-0.75358v-1.5071l-1.8368-3.0143c-0.269-0.468-0.756-0.753-1.296-0.753h-3.6501zm1.5071 1.5071h2.143l1.2952 2.2607h-3.4382v-2.2607zm-2.2607 6.0286c-1.2487 0-2.2607 1.0121-2.2607 2.2607 0 1.2487 1.012 2.2607 2.2607 2.2607h6.7822c1.2487 0 2.2607-1.0121 2.2607-2.2607 0-1.2487-1.0121-2.2607-2.2607-2.2607h-6.7822zm0 1.5071c0.41597 0 0.75357 0.3376 0.75357 0.75357s-0.3376 0.75358-0.75357 0.75358-0.75358-0.3376-0.75358-0.75358c0-0.41597 0.3376-0.75357 0.75358-0.75357zm2.2607 0c0.41597 0 0.75358 0.3376 0.75358 0.75357s-0.3376 0.75358-0.75358 0.75358c-0.41597 0-0.75357-0.3376-0.75357-0.75358 0-0.41597 0.3376-0.75357 0.75357-0.75357zm2.2607 0c0.41597 0 0.75358 0.3376 0.75358 0.75357s-0.3376 0.75358-0.75358 0.75358c-0.41597 0-0.75357-0.3376-0.75357-0.75358 0-0.41597 0.3376-0.75357 0.75357-0.75357zm2.2607 0c0.41597 0 0.75358 0.3376 0.75358 0.75357s-0.3376 0.75358-0.75358 0.75358c-0.41597 0-0.75358-0.3376-0.75358-0.75358 0-0.41597 0.3376-0.75357 0.75358-0.75357z"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapDefault.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapDefault.imageset/Contents.json
new file mode 100644
index 0000000..cb6c01f
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapDefault.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "default.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapDefault.imageset/default.svg b/iosApp/iosApp/Assets.xcassets/MapDefault.imageset/default.svg
new file mode 100644
index 0000000..f2e9790
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapDefault.imageset/default.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1">
+ <path id="background" d="m20.002 3.6816l-1.131 3.3907a12.374 12.374 0 0 1 1.131 -0.0625 12.374 12.374 0 0 1 1.129 0.0566l-1.129-3.3848zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke="#333" stroke-width="1.9" fill="#008000"/>
+ <circle id="icon" cx="20" cy="20" r="5.8251"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapHelicopter.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapHelicopter.imageset/Contents.json
new file mode 100644
index 0000000..46ef9f8
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapHelicopter.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "helicopter.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapHelicopter.imageset/helicopter.svg b/iosApp/iosApp/Assets.xcassets/MapHelicopter.imageset/helicopter.svg
new file mode 100644
index 0000000..f9c8241
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapHelicopter.imageset/helicopter.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1">
+ <path id="background" d="m20.002 3.6816-1.1309 3.3906a12.374 12.374 0 0 1 1.1309 -0.0625 12.374 12.374 0 0 1 1.1289 0.056641l-1.129-3.3847zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke="#333" stroke-width="1.9" fill="#008000"/>
+ <path id="icon" stroke-width=".88712" d="m14.606 13.91v1.7742h6.2098v0.88712c-2.6614 0-3.5165 1.7281-3.5485 1.7742h-3.5485v0.88712 0.88712l3.5485 0.88712c0 1.3236 1.3378 2.6614 2.6614 2.6614h2.6614c2.6614 0 4.4356-0.76026 4.4356-2.6614 0-1.6225-2.2284-3.988-5.3227-4.3802v-0.94256h6.2098v-1.7742l-6.2098 0.88712v-0.44356c0-0.24485-0.19872-0.44356-0.44356-0.44356s-0.44356 0.19871-0.44356 0.44356v0.44356l-6.2098-0.88712zm-0.88712 5.3227c0-0.97989-0.79436-1.7742-1.7742-1.7742-0.97988 0-1.7742 0.79435-1.7742 1.7742 0 0.97988 0.79436 1.7742 1.7742 1.7742 0.97989 0 1.7742-0.79436 1.7742-1.7742zm7.9841-0.88712c0.2821-0.03992 2.8831 0.79042 3.5485 2.6614h-3.5485v-2.6614zm4.4356 5.3227v0.88712h-8.8712v1.7742h8.8712c0.98027 0 1.7742-0.79397 1.7742-1.7742v-0.88712h-1.7742z"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapMotorcycle.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapMotorcycle.imageset/Contents.json
new file mode 100644
index 0000000..52e8181
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapMotorcycle.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "motorcycle.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapMotorcycle.imageset/motorcycle.svg b/iosApp/iosApp/Assets.xcassets/MapMotorcycle.imageset/motorcycle.svg
new file mode 100644
index 0000000..d8d18f1
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapMotorcycle.imageset/motorcycle.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1">
+ <path id="background" d="m20.002 3.6816l-1.131 3.3907a12.374 12.374 0 0 1 1.131 -0.0625 12.374 12.374 0 0 1 1.129 0.0566l-1.129-3.3848zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke="#333" stroke-width="1.9" fill="#008000"/>
+ <path id="icon" d="m29.386 21.143q0.09803 0.8414-0.17972 1.6256-0.27774 0.77605-0.80873 1.3315-0.53098 0.55549-1.2989 0.86591-0.75971 0.31042-1.6011 0.25324-1.3152-0.08986-2.2873-1.0211-0.96394-0.93126-1.0946-2.2383-0.09803-0.90675 0.22056-1.7155 0.32676-0.8169 0.9721-1.3969l-0.58-0.87408q-0.78422 0.65352-1.2335 1.5848-0.44929 0.93126-0.44929 1.9932 0 0.22056-0.15521 0.38394-0.14704 0.15521-0.3676 0.15521h-2.0913-0.56366q-0.18789 1.3397-1.2172 2.2383-1.0293 0.89858-2.4017 0.89858-1.5113 0-2.5896-1.0701-1.0701-1.0783-1.0701-2.5896t1.0701-2.5814q1.0783-1.0783 2.5896-1.0783 0.62084 0 1.2417 0.22056l0.19606-0.3676q-1.0048-0.89858-2.4834-0.89858h-0.52281q-0.21239 0-0.3676-0.15521t-0.15521-0.3676 0.15521-0.3676 0.3676-0.15521h1.0456q0.63718 0 1.1845 0.11437 0.54732 0.1062 0.9476 0.31042 0.40845 0.20422 0.58816 0.32676 0.17972 0.11437 0.41662 0.29408h4.1825 0.93943l-0.69436-1.0456h-1.8135q-0.24507 0-0.40028-0.17972-0.15521-0.18789-0.11437-0.43296 0.03267-0.18789 0.18788-0.31042t0.35126-0.12253h2.0667q0.26958 0 0.43296 0.22873l0.57183 0.85774 0.93126-0.93126q0.15521-0.15521 0.37577-0.15521h0.82506q0.21239 0 0.3676 0.15521t0.15521 0.3676v1.0456q0 0.21239-0.15521 0.3676t-0.3676 0.15521h-1.4622l0.93943 1.4051q1.0701-0.51465 2.2465-0.29408 1.1682 0.21239 1.9932 1.1028 0.82506 0.88225 0.96394 2.0667zm-15.137 3.039q0.93943 0 1.6583-0.58816 0.71887-0.59634 0.90675-1.5031h-2.5651q-0.28591 0-0.44929-0.25324-0.14704-0.26141-0.0082-0.51464l1.2008-2.2628q-0.38394-0.1062-0.74338-0.1062-1.0783 0-1.8462 0.76788-0.76788 0.76788-0.76788 1.8462t0.76788 1.8462q0.76788 0.76788 1.8462 0.76788zm9.6557-0.76788q0.76788 0.76788 1.8462 0.76788t1.8462-0.76788q0.76788-0.76788 0.76788-1.8462t-0.76788-1.8462q-0.76788-0.76788-1.8462-0.76788-0.49014 0-0.98844 0.19606l1.4214 2.1239q0.12254 0.18789 0.0817 0.40028-0.04085 0.21239-0.22056 0.32676-0.12253 0.08986-0.29408 0.08986-0.28591 0-0.43296-0.2369l-1.4214-2.1239q-0.75971 0.77605-0.75971 1.838 0 1.0783 0.76788 1.8462z"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapOffroad.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapOffroad.imageset/Contents.json
new file mode 100644
index 0000000..edae916
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapOffroad.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "offroad.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapOffroad.imageset/offroad.svg b/iosApp/iosApp/Assets.xcassets/MapOffroad.imageset/offroad.svg
new file mode 100644
index 0000000..51c9c81
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapOffroad.imageset/offroad.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1">
+ <path id="background" d="m20.002 3.6816-1.1309 3.3906a12.374 12.374 0 0 1 1.1309 -0.0625 12.374 12.374 0 0 1 1.1289 0.056641l-1.129-3.3847zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke="#333" stroke-width="1.9" fill="#008000"/>
+ <path id="icon" style="block-progression:tb;text-transform:none;text-indent:0" stroke-width=".80151" overflow="visible" d="m12.987 13.989c-0.51858 0-0.78749 0.10941-1.052 0.55104-0.2645 0.44164-1.5529 4.3925-1.5529 5.0345v2.7803c0 0.65003 0.60274 1.2524 1.2023 1.2524h0.40076c0 1.3281 1.0764 2.4045 2.4045 2.4045s2.4045-1.0764 2.4045-2.4045h7.2136c0 1.3281 1.0764 2.4045 2.4045 2.4045s2.4045-1.0764 2.4045-2.4045c0-0.07005-0.01918-0.13186-0.02505-0.20038 0.37553-0.28539 0.82656-0.80321 0.82656-1.052v-2.2292c0-0.86884-1.5457-1.1858-4.258-1.8535 0 0-2.4963-2.9345-3.156-3.732-0.42881-0.51858-0.98827-0.55104-1.4026-0.55104h-7.8148zm2.655 1.2774h1.9537v3.5317h-2.8303c-0.36549 0-0.64622-0.1066-0.52599-0.70132 0.12504-0.62037 0.51638-2.1555 0.62618-2.4296 0.12504-0.31099 0.38132-0.40076 0.77647-0.40076zm3.5567 0h1.7283c0.30858 0 0.65684 0.09879 0.85161 0.32562l2.2793 2.7051c0.25408 0.33664 0.14287 0.50095-0.17533 0.50095h-4.6838v-3.5317zm-4.8091 7.1385c0.66285 0 1.2023 0.53942 1.2023 1.2023 0 0.66285-0.53942 1.2023-1.2023 1.2023-0.66285 0-1.2023-0.53942-1.2023-1.2023 0-0.66285 0.53942-1.2023 1.2023-1.2023zm12.023 0c0.66285 0 1.2023 0.53942 1.2023 1.2023 0 0.66285-0.53942 1.2023-1.2023 1.2023-0.66285 0-1.2023-0.53942-1.2023-1.2023 0-0.66285 0.53942-1.2023 1.2023-1.2023z"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapPerson.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapPerson.imageset/Contents.json
new file mode 100644
index 0000000..e422019
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapPerson.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "person.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapPerson.imageset/person.svg b/iosApp/iosApp/Assets.xcassets/MapPerson.imageset/person.svg
new file mode 100644
index 0000000..124bbaf
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapPerson.imageset/person.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1">
+ <path id="background" d="m20.002 3.6816l-1.131 3.3907a12.374 12.374 0 0 1 1.131 -0.0625 12.374 12.374 0 0 1 1.129 0.0566l-1.129-3.3848zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke="#333" stroke-width="1.9" fill="#008000"/>
+ <path id="icon" d="m26.287 24.941q0 1.0708-0.6189 1.837-0.60907 0.76625-1.4736 0.76625h-8.3895q-0.86449 0-1.4834-0.76625-0.60907-0.76625-0.60907-1.837 0-0.83502 0.07859-1.5718 0.08841-0.7466 0.31436-1.4932 0.22595-0.75643 0.56978-1.2869 0.35366-0.54031 0.92343-0.87432 0.5796-0.34383 1.3262-0.34383 1.2869 1.2574 3.0748 1.2574t3.0748-1.2574q0.7466 0 1.3164 0.34383 0.5796 0.33401 0.92343 0.87432 0.35366 0.53048 0.5796 1.2869 0.22595 0.7466 0.30454 1.4932 0.08842 0.73678 0.08842 1.5718zm-3.625-11.376q1.1101 1.1003 1.1101 2.6622 0 1.562-1.1101 2.6721-1.1 1.101-2.662 1.101t-2.6721-1.1003q-1.1003-1.1101-1.1003-2.6721t1.1003-2.6622q1.11-1.11 2.672-1.11t2.6622 1.1101z"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapPickup.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapPickup.imageset/Contents.json
new file mode 100644
index 0000000..004cfb7
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapPickup.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "pickup.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapPickup.imageset/pickup.svg b/iosApp/iosApp/Assets.xcassets/MapPickup.imageset/pickup.svg
new file mode 100644
index 0000000..50bf57b
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapPickup.imageset/pickup.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1">
+ <path id="background" d="m20.002 3.6816-1.1309 3.3906a12.374 12.374 0 0 1 1.1309 -0.0625 12.374 12.374 0 0 1 1.1289 0.056641l-1.129-3.3847zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke="#333" stroke-width="1.9" fill="#008000"/>
+ <path id="icon" stroke-width=".88152" d="m17.19 14.711a0.8816 0.8816 0 0 0 -0.68868 0.66114l-0.71623 2.8649h-3.2781c-0.96967 0-1.763 0.79336-1.763 1.763v2.1211c0 0.35261 0.17079 0.62257 0.5234 0.79887l1.2672 0.4683c0.14704 1.0824 1.0477 1.9008 2.1762 1.9008 1.0799 0 1.9462-0.75066 2.1487-1.763h7.1623c0.20247 1.0124 1.0688 1.763 2.1487 1.763 1.157 0 2.0652-0.85999 2.1762-1.9834l0.4683-0.30302c0.26446-0.1763 0.44076-0.52891 0.44076-0.88152v-1.5151c0-0.35261-0.25344-0.68318-0.60604-0.77133l-3.9668-1.3498-2.1762-2.7272-0.0551-0.08264-0.02755 0.02755c-0.44623-0.66103-1.2059-0.99171-1.9008-0.99171h-3.1679a0.8816 0.8816 0 0 0 -0.08265 0 0.8816 0.8816 0 0 0 -0.08264 0zm0.85397 1.763h2.4793c0.33302 0 0.40036 0.03368 0.49585 0.19283a0.8816 0.8816 0 0 0 0.0551 0.08264l1.1845 1.4876h-4.6555l0.44076-1.763zm-3.3332 5.8125c0.44076 0 0.79887 0.35812 0.79887 0.79887 0 0.44076-0.35812 0.79887-0.79887 0.79887-0.44076 0-0.79887-0.35812-0.79887-0.79887 0-0.44076 0.35812-0.79887 0.79887-0.79887zm11.46 0c0.44076 0 0.79887 0.35812 0.79887 0.79887 0 0.44076-0.35812 0.79887-0.79887 0.79887-0.44076 0-0.79887-0.35812-0.79887-0.79887 0-0.44076 0.35812-0.79887 0.79887-0.79887z"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapPlane.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapPlane.imageset/Contents.json
new file mode 100644
index 0000000..65ca743
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapPlane.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "plane.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapPlane.imageset/plane.svg b/iosApp/iosApp/Assets.xcassets/MapPlane.imageset/plane.svg
new file mode 100644
index 0000000..a46eb74
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapPlane.imageset/plane.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1">
+ <path id="background" d="m20.002 3.6816l-1.131 3.3907a12.374 12.374 0 0 1 1.131 -0.0625 12.374 12.374 0 0 1 1.129 0.0566l-1.129-3.3848zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke="#333" stroke-width="1.9" fill="#008000"/>
+ <path id="icon" d="m26.238 13.763q0.4325 0.51114 0.11796 1.4548-0.31455 0.94364-1.0616 1.6907l-1.5826 1.5826 1.5727 6.8414q0.04915 0.18676-0.11796 0.32438l-1.2582 0.94364q-0.06881 0.05897-0.18676 0.05897-0.03931 0-0.06881-0.0099-0.14744-0.0295-0.20642-0.15727l-2.7425-4.9934-2.5459 2.5459 0.52097 1.9069q0.04915 0.1671-0.07864 0.30472l-0.94364 0.94364q-0.08847 0.08847-0.22608 0.08847h-0.01966q-0.14744-0.01966-0.23591-0.12778l-1.8578-2.477-2.4771-1.8578q-0.10813-0.06881-0.12778-0.22608-0.0099-0.12778 0.08847-0.24574l0.94364-0.95343q0.08847-0.08847 0.22608-0.08847 0.05898 0 0.07864 0.0099l1.9069 0.52097 2.5459-2.5459-4.9934-2.7425q-0.13762-0.07863-0.1671-0.23591-0.01966-0.15728 0.08847-0.2654l1.2582-1.2582q0.13762-0.12778 0.29489-0.07864l6.5367 1.5629 1.5727-1.5727q0.74705-0.74705 1.6907-1.0616 0.94364-0.31455 1.4548 0.11796z"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapScooter.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapScooter.imageset/Contents.json
new file mode 100644
index 0000000..1155efa
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapScooter.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "scooter.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapScooter.imageset/scooter.svg b/iosApp/iosApp/Assets.xcassets/MapScooter.imageset/scooter.svg
new file mode 100644
index 0000000..c7b531c
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapScooter.imageset/scooter.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1">
+ <path id="background" d="m20.002 3.6816l-1.131 3.3907a12.374 12.374 0 0 1 1.131 -0.0625 12.374 12.374 0 0 1 1.129 0.0566l-1.129-3.3848zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke="#333" stroke-width="1.9" fill="#008000"/>
+ <path id="icon" style="text-decoration-color:#000000;block-progression:tb;isolation:auto;mix-blend-mode:normal;text-indent:0;text-decoration-line:none;white-space:normal;text-transform:none;text-decoration-style:solid" stroke-width=".60887" d="m20.609 12.298a0.60893 0.60893 0 1 0 0 1.2177h1.3795l2.0228 6.443-2.5163 3.9077h-5.871c-0.25412-0.70466-0.92507-1.2177-1.7124-1.2177-1.0016 0-1.8266 0.82501-1.8266 1.8266s0.82501 1.8266 1.8266 1.8266c0.78736 0 1.4583-0.51307 1.7124-1.2177h6.2028a0.60893 0.60893 0 0 0 0.51135 -0.27946l2.1477-3.3345 0.49232 1.5697c-0.43114 0.33547-0.71589 0.85238-0.71589 1.4354 0 1.0016 0.82501 1.8266 1.8266 1.8266s1.8266-0.82501 1.8266-1.8266c0-0.98654-0.80143-1.7976-1.7826-1.8218l-3.1157-9.9286a0.60893 0.60893 0 0 0 -0.58151 -0.42692h-1.8266zm-6.6975 11.568c0.33112 0 0.58355 0.24891 0.60173 0.57438a0.60893 0.60893 0 0 0 0 0.07017c-0.01874 0.32487-0.27102 0.57319-0.60173 0.57319-0.34348 0-0.60887-0.26539-0.60887-0.60887s0.26539-0.60887 0.60887-0.60887zm12.177 0c0.34348 0 0.60887 0.26539 0.60887 0.60886 0 0.34348-0.26539 0.60887-0.60887 0.60887s-0.60886-0.26539-0.60886-0.60887 0.26539-0.60886 0.60886-0.60886z" white-space="normal" overflow="visible" font-weight="400"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapShip.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapShip.imageset/Contents.json
new file mode 100644
index 0000000..3fd9cd4
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapShip.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "ship.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapShip.imageset/ship.svg b/iosApp/iosApp/Assets.xcassets/MapShip.imageset/ship.svg
new file mode 100644
index 0000000..f94a6bb
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapShip.imageset/ship.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1">
+ <path id="background" d="m20.002 3.6816l-1.131 3.3907a12.374 12.374 0 0 1 1.131 -0.0625 12.374 12.374 0 0 1 1.129 0.0566l-1.129-3.3848zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke="#333" stroke-width="1.9" fill="#008000"/>
+ <path id="icon" d="m26.094 25.102q0.14711-0.14711 0.34842-0.14711t0.34842 0.14711l0.99107 0.99107-0.69685 0.69685-0.64265-0.64265-0.64265 0.64265q-0.13937 0.14711-0.34842 0.14711t-0.34842-0.14711l-0.64265-0.64265-0.64265 0.64265q-0.14711 0.14711-0.34842 0.14711t-0.34842-0.14711l-0.64265-0.64265-0.64265 0.64265q-0.14711 0.14711-0.34842 0.14711t-0.34842-0.14711l-0.64265-0.64265-0.64265 0.64265q-0.14711 0.14711-0.34842 0.14711t-0.34842-0.14711l-0.64265-0.64265-0.64265 0.64265q-0.14711 0.14711-0.34842 0.14711t-0.34842-0.14711l-0.64265-0.64265-0.64265 0.64265q-0.14711 0.14711-0.34842 0.14711t-0.34842-0.14711l-0.64265-0.64265-0.64265 0.64265q-0.14711 0.14711-0.34842 0.14711t-0.34842-0.14711l-0.99107-0.99107 0.69685-0.69685 0.64265 0.64265 0.64265-0.64265q0.14711-0.14711 0.34842-0.14711t0.34842 0.14711l0.64265 0.64265 0.64265-0.64265q0.14711-0.14711 0.34842-0.14711t0.34842 0.14711l0.64265 0.64265 0.64265-0.64265q0.14711-0.14711 0.34842-0.14711t0.34842 0.14711l0.64265 0.64265 0.64265-0.64265q0.14711-0.14711 0.34842-0.14711t0.34842 0.14711l0.64265 0.64265 0.64265-0.64265q0.14711-0.14711 0.34842-0.14711t0.34842 0.14711l0.64265 0.64265 0.64265-0.64265q0.14711-0.14711 0.34842-0.14711t0.34842 0.14711l0.64265 0.64265 0.64265-0.64265zm-12.188-0.294q-0.14711 0.14711-0.34842 0.14711t-0.34842-0.14711l-0.99107-0.99107 0.69685-0.69685 0.64265 0.6349 0.64265-0.6349q0.14711-0.14711 0.34842-0.14711t0.34842 0.14711l0.64265 0.6349 0.49554-0.49554v-2.2686l-1.626-2.4312q-0.13163-0.20131-0.0542-0.43359 0.07743-0.24003 0.30971-0.31745l1.3705-0.44908v-2.3151h0.99107v-0.99107h1.9821v-0.99107h1.9821v0.99107h1.9821v0.99107h0.99107v2.3151l1.3705 0.44908q0.23228 0.07742 0.30971 0.31745 0.07743 0.23228-0.0542 0.43359l-1.626 2.4312v2.2686l0.14711-0.13937q0.14711-0.14711 0.34842-0.14711t0.34842 0.14711l0.64265 0.6349 0.64265-0.6349q0.14711-0.14711 0.34842-0.14711t0.34842 0.14711l0.99107 0.99107-0.69685 0.69685-0.64265-0.64265-0.64265 0.64265q-0.13937 0.14711-0.34842 0.14711t-0.34842-0.14711l-0.64265-0.64265-0.64265 0.64265q-0.14711 0.14711-0.34842 0.14711t-0.34842-0.14711l-0.64265-0.64265-0.64265 0.64265q-0.14711 0.14711-0.34842 0.14711t-0.34842-0.14711l-0.64265-0.64265-0.64265 0.64265q-0.14711 0.14711-0.34842 0.14711t-0.34842-0.14711l-0.64265-0.64265-0.64265 0.64265q-0.14711 0.14711-0.34842 0.14711t-0.34842-0.14711l-0.64264-0.64265-0.64265 0.64265q-0.14711 0.14711-0.34842 0.14711t-0.34842-0.14711l-0.64265-0.64265-0.64265 0.64265zm3.1203-8.7725v0.99107l2.974-0.991 2.9732 0.99107v-0.99107h-0.99107v-0.99107h-3.9643v0.99107h-0.99107z"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapTractor.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapTractor.imageset/Contents.json
new file mode 100644
index 0000000..0774718
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapTractor.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "tractor.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapTractor.imageset/tractor.svg b/iosApp/iosApp/Assets.xcassets/MapTractor.imageset/tractor.svg
new file mode 100644
index 0000000..96643ef
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapTractor.imageset/tractor.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1">
+ <path id="background" d="m20.002 3.6816-1.1309 3.3906a12.374 12.374 0 0 1 1.1309 -0.0625 12.374 12.374 0 0 1 1.1289 0.056641l-1.129-3.3847zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke="#333" stroke-width="1.9" fill="#008000"/>
+ <path id="icon" stroke-width=".84153" d="m13.105 12.427a0.84162 0.84162 0 0 0 -0.68375 0.84153v5.0492a0.84162 0.84162 0 0 0 0 0.07889v1.8672c0.84153-0.67323 1.8514-1.1045 2.9454-1.1045 2.5246 0 4.6284 2.1038 4.6284 4.6284v0.42077h3.7869c-0.25895 0.34961-0.42077 0.78515-0.42077 1.2623 0 1.1781 0.92569 2.1038 2.1038 2.1038s2.1038-0.92569 2.1038-2.1038c0-0.55373-0.21318-1.0478-0.55226-1.4201 0.49718-0.2262 0.85521-0.67323 0.97302-1.2623l0.42077-2.7087c0.08415-0.42077-0.33661-0.92043-0.84153-0.92043l-7.1267-0.78894-1.3149-5.3122a0.84162 0.84162 0 0 0 -0.81524 -0.63115h-5.0492a0.84162 0.84162 0 0 0 -0.07889 0 0.84162 0.84162 0 0 0 -0.07889 0zm0.99932 1.6831h3.5502l1.0256 4.0499-4.5758-0.49966v-3.5502zm10.098 0v3.6291l1.6831 0.23668v-3.8658h-1.6831zm-8.8361 5.8907c-2.1038 0-3.7869 1.6831-3.7869 3.7869s1.6831 3.7869 3.7869 3.7869 3.7869-1.6831 3.7869-3.7869-1.6831-3.7869-3.7869-3.7869zm0 1.2623c1.4306 0 2.5246 1.094 2.5246 2.5246s-1.094 2.5246-2.5246 2.5246-2.5246-1.094-2.5246-2.5246 1.094-2.5246 2.5246-2.5246zm10.098 3.3661c0.50492 0 0.84154 0.33661 0.84154 0.84154 0 0.50492-0.33661 0.84153-0.84154 0.84153-0.50492 0-0.84153-0.33661-0.84153-0.84153s0.33661-0.84154 0.84153-0.84154z"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapTrain.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapTrain.imageset/Contents.json
new file mode 100644
index 0000000..6ff5ee7
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapTrain.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "train.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapTrain.imageset/train.svg b/iosApp/iosApp/Assets.xcassets/MapTrain.imageset/train.svg
new file mode 100644
index 0000000..e4b10ac
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapTrain.imageset/train.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1">
+ <path id="background" d="m20.002 3.6816l-1.131 3.3907a12.374 12.374 0 0 1 1.131 -0.0625 12.374 12.374 0 0 1 1.129 0.0566l-1.129-3.3848zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke="#333" stroke-width="1.9" fill="#008000"/>
+ <path id="icon" d="m18.127 11.484c-0.59864 0-1.0869 0.44565-1.1707 1.0217h-0.362c-1.3143 0-2.3839 1.027-2.3839 2.2881v9.7272c0 0.878 0.51749 1.6389 1.2771 2.0221l-1.6389 1.3622c-0.14633 0.12106-0.16895 0.3379-0.04789 0.48423s0.3379 0.16895 0.48423 0.04789l1.9688-1.6496c0.11175 0.01596 0.22482 0.02128 0.34056 0.02128h6.8111c0.11574 0 0.22881-0.0054 0.34056-0.02128l1.9688 1.6496c0.14633 0.12106 0.36317 0.09844 0.48423-0.04789s0.09844-0.36317-0.04789-0.48423l-1.6389-1.3622c0.7596-0.38313 1.2771-1.1441 1.2771-2.0221v-9.727c0-1.2611-1.0696-2.2881-2.3839-2.2881h-0.36183c-0.08381-0.57602-0.57203-1.0217-1.1707-1.0217-0.59864 0-1.0869 0.44565-1.1707 1.0217h-1.4048c-0.08381-0.57602-0.57203-1.0217-1.1707-1.0217zm0 0.68111c0.28202 0 0.51084 0.22881 0.51084 0.51084 0 0.28202-0.22881 0.51084-0.51084 0.51084-0.28202 0-0.51084-0.22881-0.51084-0.51084 0-0.28202 0.22881-0.51084 0.51084-0.51084zm3.7461 0c0.28202 0 0.51084 0.22881 0.51084 0.51084 0 0.28202-0.22881 0.51084-0.51084 0.51084-0.28202 0-0.51084-0.22881-0.51084-0.51084 0-0.28202 0.22881-0.51084 0.51084-0.51084zm-3.9164 2.7245h4.0867c0.1889 0 0.34056 0.15298 0.34056 0.34056v0.68111h-4.7678v-0.68111c0-0.18757 0.15298-0.34056 0.34056-0.34056zm-1.3622 1.7028h6.8111c0.37648 0 0.68111 0.28336 0.68111 0.6279v2.4903c0 0.34455-0.30464 0.6279-0.68111 0.6279h-6.8111c-0.37648 0-0.68111-0.28335-0.68111-0.6279v-2.4903c0-0.34455 0.30464-0.6279 0.68111-0.6279zm0.34056 6.13c0.56405 0 1.0217 0.45762 1.0217 1.0217 0 0.56405-0.45762 1.0217-1.0217 1.0217-0.56405 0-1.0217-0.45762-1.0217-1.0217 0-0.56405 0.45762-1.0217 1.0217-1.0217zm6.13 0c0.56405 0 1.0217 0.45762 1.0217 1.0217 0 0.56405-0.45762 1.0217-1.0217 1.0217-0.56405 0-1.0217-0.45762-1.0217-1.0217 0-0.56405 0.45762-1.0217 1.0217-1.0217z"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapTram.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapTram.imageset/Contents.json
new file mode 100644
index 0000000..c04e17e
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapTram.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "tram.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapTram.imageset/tram.svg b/iosApp/iosApp/Assets.xcassets/MapTram.imageset/tram.svg
new file mode 100644
index 0000000..70a0307
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapTram.imageset/tram.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1">
+ <path id="background" d="m20.002 3.6816l-1.131 3.3907a12.374 12.374 0 0 1 1.131 -0.0625 12.374 12.374 0 0 1 1.129 0.0566l-1.129-3.3848zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke="#333" stroke-width="1.9" fill="#008000"/>
+ <path id="icon" d="m20 11.299c-2.5762 0-3.8283 0.45542-3.8283 1.3921 0 0.19168 0.15634 0.34802 0.34802 0.34802s0.34802-0.15634 0.34802-0.34802c0-0.17129 0.34666-0.45134 1.4247-0.59817l0.294 1.719c-2.8141 0.3154-4.5026 1.5512-4.5026 2.7081v8.1024c0 1.0726 0.7545 1.978 1.7836 2.2513l-1.4574 1.2181c-0.14546 0.12235-0.16586 0.33307-0.0435 0.47853 0.06797 0.08157 0.16314 0.13051 0.26102 0.13051 0.07749 0 0.16314-0.03264 0.22839-0.087l1.9794-1.6531h6.3297l1.9794 1.6531c0.06525 0.05438 0.1509 0.087 0.22839 0.087 0.09788 0 0.19304-0.04894 0.26102-0.13051 0.12235-0.14546 0.10196-0.35618-0.0435-0.47853l-1.4574-1.2181c1.0291-0.27325 1.7836-1.1787 1.7836-2.2513v-8.1024c0-1.1569-1.6885-2.3927-4.5026-2.7081l0.29364-1.7184c1.0781 0.14682 1.4247 0.42687 1.4247 0.59817 0 0.19168 0.15498 0.34802 0.34802 0.34802s0.34802-0.15634 0.34802-0.34802c0-0.93667-1.2521-1.3921-3.8283-1.3921zm0 0.69605c0.37793 0 0.70285 0.01359 1.0006 0.03264l-0.29365 1.7292c-0.23111-0.01223-0.46358-0.02175-0.70692-0.02175-0.24335 0-0.47581 0.0095-0.70692 0.02175l-0.294-1.729c0.29772-0.01903 0.62264-0.03264 1.0006-0.03264zm-2.0881 3.8283h4.1763c0.19304 0 0.34802 0.15634 0.34802 0.34802v0.69605h-4.8723v-0.69605c0-0.19168 0.15634-0.34802 0.34803-0.34802zm-1.3921 1.7401h6.9605c0.38473 0 0.69605 0.28957 0.69605 0.64167v2.5449c0 0.3521-0.31132 0.64167-0.69605 0.64167h-6.9605c-0.38473 0-0.69605-0.28957-0.69605-0.64167v-2.5449c0-0.3521 0.31132-0.64167 0.69605-0.64167zm0.34802 5.5684c0.57641 0 1.0441 0.46766 1.0441 1.0441 0 0.57642-0.46766 1.0441-1.0441 1.0441-0.57642 0-1.0441-0.46766-1.0441-1.0441 0-0.57642 0.46766-1.0441 1.0441-1.0441zm6.2644 0c0.57641 0 1.0441 0.46766 1.0441 1.0441 0 0.57642-0.46766 1.0441-1.0441 1.0441-0.57642 0-1.0441-0.46766-1.0441-1.0441 0-0.57642 0.46766-1.0441 1.0441-1.0441z"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapTrolleybus.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapTrolleybus.imageset/Contents.json
new file mode 100644
index 0000000..b1013a6
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapTrolleybus.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "trolleybus.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapTrolleybus.imageset/trolleybus.svg b/iosApp/iosApp/Assets.xcassets/MapTrolleybus.imageset/trolleybus.svg
new file mode 100644
index 0000000..344ae8d
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapTrolleybus.imageset/trolleybus.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1">
+ <path id="background" d="m20.002 3.6816l-1.131 3.3907a12.374 12.374 0 0 1 1.131 -0.0625 12.374 12.374 0 0 1 1.129 0.0566l-1.129-3.3848zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke="#333" stroke-width="1.9" fill="#008000"/>
+ <path id="icon" d="m16.909 11.561c-0.10947 0.01846-0.20311 0.091-0.24927 0.19256-0.04615 0.10024-0.03956 0.21894 0.01715 0.31389l0.70692 1.1817h-1.7726c-1.3031 0-2.3634 1.0604-2.3634 2.3634v10.467c0 0.29807 0.13189 0.56316 0.33763 0.74912v0.60141c0 0.55788 0.45501 1.0129 1.0129 1.0129h1.3505c0.55789 0 1.0129-0.45502 1.0129-1.0129v-0.33763h6.0774v0.33763c0 0.55788 0.45501 1.0129 1.0129 1.0129h1.3505c0.55789 0 1.0129-0.45502 1.0129-1.0129v-0.601c0.204-0.186 0.336-0.451 0.336-0.749v-10.467c0-1.3031-1.0604-2.3634-2.3634-2.3634h-1.7726l0.70692-1.1817c0.06594-0.1121 0.062-0.25191-0.0092-0.35874-0.07254-0.10815-0.20047-0.16618-0.3284-0.14771-0.09892 0.01846-0.18332 0.08045-0.23212 0.16882l-0.90739 1.5193h-3.693l-0.908-1.518c-0.06726-0.12002-0.20179-0.18596-0.33763-0.16882zm-0.96014 3.3763h8.1032c0.57371 0 1.0129 0.43919 1.0129 1.0129v4.7269c0 0.57371-0.43919 1.0129-1.0129 1.0129h-8.1032c-0.57371 0-1.0129-0.43919-1.0129-1.0129v-4.7269c0-0.57371 0.43919-1.0129 1.0129-1.0129zm-3.0387 2.0258c-0.39171 0-0.67527 0.28356-0.67527 0.67526v2.0258c0 0.39171 0.28356 0.67527 0.67527 0.67527zm14.181 0v3.3763c0.39171 0 0.67527-0.28356 0.67527-0.67527v-2.0258c0-0.39171-0.28356-0.67526-0.67527-0.67526zm-11.142 6.415c0.5592 0 1.0129 0.4537 1.0129 1.0129s-0.4537 1.0129-1.0129 1.0129c-0.55921 0-1.0129-0.45369-1.0129-1.0129 0-0.5592 0.45369-1.0129 1.0129-1.0129zm8.1032 0c0.5592 0 1.0129 0.4537 1.0129 1.0129s-0.4537 1.0129-1.0129 1.0129c-0.55921 0-1.0129-0.45369-1.0129-1.0129 0-0.5592 0.45369-1.0129 1.0129-1.0129z"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapTruck.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapTruck.imageset/Contents.json
new file mode 100644
index 0000000..c95213a
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapTruck.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "truck.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapTruck.imageset/truck.svg b/iosApp/iosApp/Assets.xcassets/MapTruck.imageset/truck.svg
new file mode 100644
index 0000000..708744d
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapTruck.imageset/truck.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1">
+ <path id="background" d="m20.002 3.6816l-1.131 3.3907a12.374 12.374 0 0 1 1.131 -0.0625 12.374 12.374 0 0 1 1.129 0.0566l-1.129-3.3848zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke="#333" stroke-width="1.9" fill="#008000"/>
+ <path id="icon" d="m17.031 24.899q0.34603-0.34603 0.34603-0.81955t-0.34603-0.81955-0.81955-0.34603-0.81955 0.34603-0.34603 0.81955 0.34603 0.81955 0.81955 0.34603 0.81955-0.34603zm-3.1507-5.4819h3.4968v-2.3312h-1.4388q-0.11838 0-0.20034 0.08196l-1.7757 1.7757q-0.08196 0.08196-0.08196 0.20033v0.27318zm11.31 5.4819q0.34603-0.34603 0.34603-0.81955t-0.34603-0.81955-0.81955-0.34603-0.81955 0.34603-0.34603 0.81955 0.34603 0.81955 0.81955 0.34603 0.81955-0.34603zm2.6772-10.727v9.3247q0 0.13659-0.03642 0.24587-0.03642 0.10017-0.12749 0.16391-0.08196 0.06375-0.1457 0.10927-0.06374 0.03642-0.21855 0.05463-0.1457 0.0091-0.20034 0.01821-0.05463 0-0.23676 0-0.17302-0.0091-0.20034-0.0091 0 0.96525-0.68296 1.6482-0.68296 0.68296-1.6482 0.68296-0.96525 0-1.6482-0.68296-0.68296-0.68292-0.68296-1.6482h-3.4968q0 0.96525-0.68296 1.6482-0.68296 0.68296-1.6482 0.68296-0.96525 0-1.6482-0.68296-0.68296-0.68296-0.68296-1.6482h-0.58279q-0.02732 0-0.20944 0.0091-0.17302 0-0.22765 0-0.05463-0.0091-0.20944-0.01821-0.1457-0.01821-0.20944-0.05463-0.06375-0.04553-0.1548-0.10927-0.08196-0.06375-0.11838-0.16391-0.03642-0.10927-0.03642-0.24586 0-0.23676 0.17302-0.40978t0.40978-0.17302v-2.914q0-0.07285-0.0091-0.31871 0-0.24587 0-0.34603 0.0091-0.10017 0.02732-0.30961 0.01821-0.21855 0.05463-0.33693 0.04554-0.12749 0.12749-0.28229 0.09106-0.1548 0.20944-0.27318l1.803-1.803q0.17302-0.17302 0.45531-0.2914 0.2914-0.11838 0.53726-0.11838h1.457v-1.7484q0-0.23676 0.17302-0.40978t0.40978-0.17302h9.3247q0.23676 0 0.40978 0.17302t0.17302 0.40978z"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Assets.xcassets/MapVan.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/MapVan.imageset/Contents.json
new file mode 100644
index 0000000..c7b02d6
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapVan.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "van.svg",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/MapVan.imageset/van.svg b/iosApp/iosApp/Assets.xcassets/MapVan.imageset/van.svg
new file mode 100644
index 0000000..3394b88
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/MapVan.imageset/van.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg id="svg4145" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="40" width="40" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 40 40">
+ <g id="layer1">
+ <path id="background" d="m20.002 3.6816-1.1309 3.3906a12.374 12.374 0 0 1 1.1309 -0.0625 12.374 12.374 0 0 1 1.1289 0.056641l-1.129-3.3847zm-0.002 3.9434a12.374 12.374 0 0 0 -12.375 12.375 12.374 12.374 0 0 0 12.375 12.375 12.374 12.374 0 0 0 12.375 -12.375 12.374 12.374 0 0 0 -12.375 -12.375z" stroke="#333" stroke-width="1.9" fill="#008000"/>
+ <path id="icon" stroke-width="0.87" d="m12.17 13.91c-0.48024 0-0.87 0.38976-0.87 0.87v3.48 4.35c0 0.96135 0.77865 1.74 1.74 1.74h0.05438c0.20276 0.99123 1.0693 1.74 2.1206 1.74s1.9179-0.74877 2.1206-1.74h5.3287c0.20277 0.99123 1.0693 1.74 2.1206 1.74s1.9179-0.74877 2.1206-1.74h0.05438c0.96135 0 1.74-0.77865 1.74-1.74v-3.2081-0.27188s-1.1719-3.5328-3.2625-5.0841c-0.13137-0.09831-0.29863-0.13594-0.46219-0.13594h-12.805zm10.44 1.74h2.0119c0.74211 0.65859 1.3787 1.7078 1.8216 2.61h-3.8334v-2.61zm-7.395 7.395c0.47937 0 0.87 0.39063 0.87 0.87s-0.39063 0.87-0.87 0.87-0.87-0.39063-0.87-0.87 0.39063-0.87 0.87-0.87zm9.57 0c0.47937 0 0.87 0.39063 0.87 0.87s-0.39063 0.87-0.87 0.87-0.87-0.39063-0.87-0.87 0.39063-0.87 0.87-0.87z"/>
+ </g>
+</svg>
diff --git a/iosApp/iosApp/Details/Commands/UnitCommandsView.swift b/iosApp/iosApp/Details/Commands/UnitCommandsView.swift
new file mode 100644
index 0000000..eef3ae4
--- /dev/null
+++ b/iosApp/iosApp/Details/Commands/UnitCommandsView.swift
@@ -0,0 +1,58 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import SwiftUI
+import shared
+
+struct UnitCommandsView: View {
+ @ObservedObject var unitCommandsViewModel = UnitCommandsViewModel()
+
+ var unit: UnitInformation
+
+ init(unit: UnitInformation) {
+ self.unit = unit
+ unitCommandsViewModel.fetchCommands(id: unit.device.id)
+ }
+
+ var body: some View {
+ VStack {
+ List {
+ Picker("commands", selection: $unitCommandsViewModel.selectedId) {
+ ForEach(unitCommandsViewModel.commands, id: \.id) { command in
+ Text(command.description_ ?? "\(command.id!)")
+ .tag(Int(truncating: command.id!))
+ }
+ }.pickerStyle(InlinePickerStyle())
+
+ Button {
+ unitCommandsViewModel.showConfirmation = true
+ } label: {
+ Label("send-command", systemImage: "paperplane")
+ }
+ .disabled(unitCommandsViewModel.notSelected)
+ .actionSheet(isPresented: $unitCommandsViewModel.showConfirmation) {
+ ActionSheet(title: Text("send-command-confirm"), buttons: [
+ .cancel(),
+ .destructive(Text("send-command")) {
+ unitCommandsViewModel.sendCommand()
+ }
+ ])
+ }
+ }
+ }
+ }
+}
diff --git a/iosApp/iosApp/Details/Commands/UnitCommandsViewModel.swift b/iosApp/iosApp/Details/Commands/UnitCommandsViewModel.swift
new file mode 100644
index 0000000..d7298c4
--- /dev/null
+++ b/iosApp/iosApp/Details/Commands/UnitCommandsViewModel.swift
@@ -0,0 +1,54 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import Foundation
+import shared
+
+class UnitCommandsViewModel: ObservableObject {
+ @Inject var commandsController: CommandsController
+
+ @Published var commands = [Command]()
+ @Published var selected: Command?
+ @Published var selectedId: Int = 0 {
+ didSet {
+ if let selected = commands.first(where: {
+ Int(truncating: $0.id!) == selectedId
+ }) {
+ self.selected = selected
+ notSelected = false
+ } else {
+ self.selected = nil
+ notSelected = true
+ }
+ }
+ }
+ @Published var notSelected: Bool = true
+ @Published var showConfirmation: Bool = false
+
+ func fetchCommands(id: Int32) {
+ commandsController.fetchCommands(deviceId: id) { commands, error in
+ print("We've got the commands! \(commands ?? [])")
+ self.commands = commands ?? []
+ }
+ }
+
+ func sendCommand() {
+ if let command = selected {
+ commandsController.sendCommand(command: command) { _, error in }
+ }
+ }
+}
diff --git a/iosApp/iosApp/Details/DetailsView.swift b/iosApp/iosApp/Details/DetailsView.swift
new file mode 100644
index 0000000..1b86d2b
--- /dev/null
+++ b/iosApp/iosApp/Details/DetailsView.swift
@@ -0,0 +1,81 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import SwiftUI
+import shared
+
+struct DetailsView: View {
+ @Binding var isPresented: Bool
+ @State var action: DeviceRow.Action
+ var unit: UnitInformation?
+
+ init(isPresented: Binding<Bool>, action: DeviceRow.Action, for unit: UnitInformation?) {
+ self._isPresented = isPresented
+ self.action = action
+ self.unit = unit
+ }
+
+ var body: some View {
+ NavigationView {
+ VStack {
+ if let unit = unit {
+ switch action {
+ case .details:
+ UnitInformationView(unit: unit)
+ case .reports:
+ UnitReportsView(unit: unit)
+ case .commands:
+ UnitCommandsView(unit: unit)
+ default:
+ EmptyView()
+ }
+ } else {
+ LoadingView()
+ }
+ }
+ .navigationBarTitleView(
+ Picker(selection: $action) {
+ Text("details").tag(DeviceRow.Action.details)
+ //Text("reports").tag(DeviceRow.Action.reports)
+ Text("commands").tag(DeviceRow.Action.commands)
+ } label: {
+ EmptyView()
+ }.pickerStyle(SegmentedPickerStyle())
+ )
+ .navigationTitle(unit?.device.name ?? NSLocalizedString("loading", comment: ""))
+ .navigationBarTitleDisplayMode(.large)
+ .toolbar {
+ ToolbarItem(placement: .navigationBarLeading) {
+ if let category = unit?.device.category {
+ let type = Marker.companion
+ .categoryToMarkerType(category: category)
+ Image(MarkerTransformations.markerTypeToImageName(markerType: type))
+ } else {
+ EmptyView()
+ }
+ }
+ ToolbarItem(placement: .navigationBarTrailing) {
+ Button {
+ isPresented = false
+ } label: {
+ Text("done").bold()
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/iosApp/iosApp/Details/Information/UnitInformationView.swift b/iosApp/iosApp/Details/Information/UnitInformationView.swift
new file mode 100644
index 0000000..4c0d722
--- /dev/null
+++ b/iosApp/iosApp/Details/Information/UnitInformationView.swift
@@ -0,0 +1,120 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import SwiftUI
+import shared
+
+struct UnitInformationView: View {
+ var unit: UnitInformation
+
+ var body: some View {
+ List {
+ Section {
+ // MARK: - Contact
+ if let contact = unit.device.contact {
+ HStack {
+ Text("contact")
+ Spacer()
+ Text(contact).foregroundColor(.secondaryLabel)
+ }
+ }
+ // MARK: - Unique ID
+ if let uniqueId = unit.device.uniqueId {
+ HStack {
+ Text("unique-id")
+ Spacer()
+ Text(uniqueId).foregroundColor(.secondaryLabel)
+ }
+ }
+ // MARK: - Date time
+ if let datetime = unit.position?.fixTime {
+ HStack {
+ Text("datetime")
+ Spacer()
+ Text(Formatter.companion.formatDate(str: datetime))
+ .foregroundColor(.secondaryLabel)
+ }
+ }
+ // MARK: - Latitude
+ if let latitude = unit.position?.latitude {
+ HStack {
+ Text("latitude")
+ Spacer()
+ Text("\(latitude)").foregroundColor(.secondaryLabel)
+ }
+ }
+ // MARK: - Longitude
+ if let longitude = unit.position?.longitude {
+ HStack {
+ Text("longitude")
+ Spacer()
+ Text("\(longitude)").foregroundColor(.secondaryLabel)
+ }
+ }
+ // MARK: - Speed
+ if let speed = unit.position?.speed {
+ HStack {
+ Text("speed")
+ Spacer()
+ Text(Formatter.companion.formatSpeed(
+ speed: Double(truncating: speed), unit: .kmh))
+ .foregroundColor(.secondaryLabel)
+ }
+ }
+ // MARK: - Address
+ if let address = unit.position?.address {
+ HStack {
+ Text("address")
+ Spacer()
+ Text(address).foregroundColor(.secondaryLabel)
+ }
+ }
+ // MARK: - Hours
+ if let hours = unit.getHourmeter() {
+ HStack {
+ Text("hourmeter")
+ Spacer()
+ Text(Formatter.companion.formatHours(millis: Int64(truncating: hours)))
+ .foregroundColor(.secondaryLabel)
+ }
+ }
+ // MARK: - Protocol
+ if let `protocol` = unit.position?.protocol {
+ HStack {
+ Text("protocol")
+ Spacer()
+ Text(`protocol`).foregroundColor(.secondaryLabel)
+ }
+ }
+ }
+ Section {
+ Button {
+ if let longitude = unit.position?.longitude,
+ let latitude = unit.position?.latitude,
+ let url = Utils.getMapsURL(longitude: Float(truncating: longitude),
+ latitude: Float(truncating: latitude)) {
+ if UIApplication.shared.canOpenURL(url) {
+ UIApplication.shared.open(url, options: [:])
+ }
+ }
+ } label: {
+ Label("open-location-browser", systemImage: "globe")
+ }
+ }
+ }
+ }
+}
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/utils/MarkerType.kt b/iosApp/iosApp/Details/Reports/UnitReportsView.swift
index cb2d159..26ddead 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/utils/MarkerType.kt
+++ b/iosApp/iosApp/Details/Reports/UnitReportsView.swift
@@ -15,11 +15,13 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-package mx.trackermap.TrackerMap.utils
+import SwiftUI
+import shared
-enum class MarkerType {
- ANIMAL, BACKHOE, BICYCLE, BOAT, BUS, CAR, CRANE, DEFAULT, HELICOPTER, MOTORCYCLE, OFFROAD, PERSON,
- PICKUP, PLANE, SCOOTER, SHIP, TRACTOR, TRAIN, TRAM, TROLLEYBUS, TRUCK, VAN,
+struct UnitReportsView: View {
+ var unit: UnitInformation
- REPORT_POSITION, REPORT_START, REPORT_END
-} \ No newline at end of file
+ var body: some View {
+ Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
+ }
+}
diff --git a/iosApp/iosApp/Devices/DeviceRow.swift b/iosApp/iosApp/Devices/DeviceRow.swift
new file mode 100644
index 0000000..42ef0dc
--- /dev/null
+++ b/iosApp/iosApp/Devices/DeviceRow.swift
@@ -0,0 +1,197 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import SwiftUI
+import shared
+
+struct DeviceRow: View {
+ var unit: UnitInformation
+
+ enum Action {
+ case details
+ case reports
+ case commands
+ case close
+ }
+ var callback: (Action) -> ()
+ var isCell: Bool = true
+
+ @State var isSheet: Bool = false
+
+ var body: some View {
+ if isCell {
+ let row = HStack {
+ /* MARK: - Device icon */
+ let category = Marker.companion.categoryToMarkerType(category: unit.device.category)
+ Image(MarkerTransformations.markerTypeToImageName(markerType: category))
+ .padding(5.0)
+
+ getSharedContent()
+ }
+
+ /* MARK: - Device actions */
+ if #available(iOS 15, *) {
+ row.swipeActions(edge: .trailing, allowsFullSwipe: false) {
+ getActionButtons()
+ }
+ } else {
+ row.contextMenu {
+ getActionButtons()
+ }
+ }
+ } else {
+ VStack {
+ getSharedContent()
+ HStack {
+ getActionButtons()
+ }
+ }
+ .padding(2.0)
+ }
+ }
+
+ @ViewBuilder
+ func getSharedContent() -> some View {
+ VStack {
+ HStack {
+ /* MARK: - Status icon */
+ switch (unit.getStatus()) {
+ case .online:
+ Image(systemName: "circle.fill")
+ .foregroundColor(.systemGreen)
+ .imageScale(.small)
+ case .offline:
+ Image(systemName: "circle.fill")
+ .foregroundColor(.systemRed)
+ .imageScale(.small)
+ default:
+ EmptyView()
+ }
+
+ /* MARK: - Engine stop */
+ switch (unit.getEngineStop()) {
+ case .on:
+ Image(systemName: "lock.fill")
+ .foregroundColor(.systemRed)
+ .imageScale(.small)
+ case .off:
+ Image(systemName: "lock.open.fill")
+ .foregroundColor(.systemGreen)
+ .imageScale(.small)
+ default:
+ EmptyView()
+ }
+
+ /* MARK: - Device name */
+ Text(unit.device.name)
+ Spacer()
+
+ /* MARK: - Close button */
+ if !isCell {
+ Button {
+ callback(.close)
+ } label: {
+ Image(systemName: "xmark")
+ .foregroundColor(.secondary)
+ }
+ }
+ }
+ .padding(.bottom, 5.0)
+
+ /* MARK: - Driver */
+ if let contact = unit.device.contact {
+ HStack {
+ Label(contact, systemImage: "person")
+ .labelStyle(SmallLabelStyle())
+ Spacer()
+ }
+ }
+
+ /* MARK: - Speed */
+ if let speed = unit.position?.speed {
+ HStack {
+ Label(Formatter.companion.formatSpeed(
+ speed: Double(truncating: speed),
+ unit: .kmh),
+ systemImage: "speedometer")
+ .labelStyle(SmallLabelStyle())
+ Spacer()
+ }
+ }
+
+ /* MARK: - Address */
+ if let address = unit.position?.address {
+ HStack {
+ Label(address, systemImage: "mappin.and.ellipse")
+ .labelStyle(SmallLabelStyle())
+ Spacer()
+ }
+ }
+
+ /* MARK: - Hourmeter */
+ if let hourmeter = Int64(truncating: unit.getHourmeter() ?? 0),
+ hourmeter >= 60 * 60 * 1000 {
+ HStack {
+ Label(Formatter.companion.formatHours(millis: hourmeter),
+ systemImage: "timer")
+ .labelStyle(SmallLabelStyle())
+ Spacer()
+ }
+ }
+
+ /* MARK: - Date time */
+ if let datetime = unit.position?.fixTime {
+ HStack {
+ Label(Formatter.companion.formatDate(str: datetime),
+ systemImage: "calendar")
+ .labelStyle(SmallLabelStyle())
+ Spacer()
+ }
+ }
+ }
+ }
+
+ @ViewBuilder
+ func getActionButtons() -> some View {
+ let details = Button { callback(.details) } label: {
+ Label("details", systemImage: "info.circle")
+ }
+
+ //let reports = Button { callback(.reports) } label: {
+ // Label("reports", systemImage: "clock")
+ //}
+
+ let commands = Button { callback(.commands) } label: {
+ Label("commands", systemImage: "paperplane")
+ }
+
+ if isCell {
+ commands
+ // reports
+ details
+ } else {
+ Group {
+ details
+ // reports
+ commands
+ }
+ .frame(maxWidth: .infinity)
+ .labelStyle(.titleOnly)
+ .padding(5.0)
+ }
+ }
+}
diff --git a/iosApp/iosApp/Devices/DevicesView.swift b/iosApp/iosApp/Devices/DevicesView.swift
new file mode 100644
index 0000000..e80a4c3
--- /dev/null
+++ b/iosApp/iosApp/Devices/DevicesView.swift
@@ -0,0 +1,38 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import SwiftUI
+
+struct DevicesView: View {
+ @ObservedObject var devicesViewModel: DevicesViewModel
+
+ init(unitsViewModel: UnitsViewModel) {
+ self._devicesViewModel = ObservedObject(
+ wrappedValue: DevicesViewModel(unitsViewModel: unitsViewModel))
+ }
+
+ var body: some View {
+ List(devicesViewModel.units, id: \.device.id) { unit in
+ DeviceRow(unit: unit, callback: { action in
+ self.devicesViewModel.show(action: action, for: unit)
+ }).onTapGesture {
+ self.devicesViewModel.select(unit: unit)
+ UIApplication.shared.endEditing()
+ }
+ }
+ }
+}
diff --git a/iosApp/iosApp/Devices/DevicesViewModel.swift b/iosApp/iosApp/Devices/DevicesViewModel.swift
new file mode 100644
index 0000000..76cf9a2
--- /dev/null
+++ b/iosApp/iosApp/Devices/DevicesViewModel.swift
@@ -0,0 +1,48 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import Foundation
+import shared
+
+class DevicesViewModel: ObservableObject {
+ var unitsViewModel: UnitsViewModel
+ var id: Int32? = nil
+ var units: [UnitInformation] {
+ get {
+ return unitsViewModel.units
+ }
+ }
+
+ @Published var shouldShowView = false
+ @Published var action: DeviceRow.Action = .details
+
+ init(unitsViewModel: UnitsViewModel) {
+ self.unitsViewModel = unitsViewModel
+ }
+
+ func select(unit: UnitInformation) {
+ unitsViewModel.searchQuery = ""
+ unitsViewModel.isEditing = false
+ unitsViewModel.unitsDisplayMode = .map
+ unitsViewModel.selectedUnit = unit
+
+ }
+
+ func show(action: DeviceRow.Action, for unit: UnitInformation) {
+ unitsViewModel.show(action: action, for: unit)
+ }
+}
diff --git a/iosApp/iosApp/Info.plist b/iosApp/iosApp/Info.plist
index 237f735..bf9db74 100644
--- a/iosApp/iosApp/Info.plist
+++ b/iosApp/iosApp/Info.plist
@@ -4,6 +4,10 @@
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
+ <key>UIBackgroundModes</key>
+ <array>
+ <string>remote-notification</string>
+ </array>
<key>CFBundleDisplayName</key>
<string>TrackerMap</string>
<key>CFBundleExecutable</key>
diff --git a/iosApp/iosApp/Koin.swift b/iosApp/iosApp/Koin.swift
deleted file mode 100644
index ffa0819..0000000
--- a/iosApp/iosApp/Koin.swift
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// Koin.swift
-// iosApp
-//
-// Created by Iván on 23/01/22.
-// Copyright © 2022 orgName. All rights reserved.
-//
-
-import Foundation
-import shared
-
-func startKoin() {
- let koinApplication = KoinIosKt.
-}
diff --git a/iosApp/iosApp/Map/MapView.swift b/iosApp/iosApp/Map/MapView.swift
new file mode 100644
index 0000000..e52c034
--- /dev/null
+++ b/iosApp/iosApp/Map/MapView.swift
@@ -0,0 +1,71 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import SwiftUI
+import Combine
+import WhirlyGlobe
+import shared
+
+struct MapView: UIViewControllerRepresentable {
+ typealias UIViewControllerType = MapViewController
+
+ @Binding var layer: MapLayer
+ @Binding var markers: [Marker]
+ @Binding var selected: Marker?
+ var markerCallback: MarkerCallback?
+
+ class Coordinator {
+ var shouldCenter: Bool = true
+ var oldMarkers: [Marker] = []
+ }
+
+ func makeCoordinator() -> Coordinator {
+ return Coordinator()
+ }
+
+ func makeUIViewController(context: Context) -> MapViewController {
+ let mapVC = MapViewController()
+ mapVC.markerCallback = markerCallback
+ mapVC.mapLayer = layer
+ return mapVC
+ }
+
+ func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
+ // MARK: - Set map layer
+ uiViewController.setMapLayer(layer)
+
+ // MARK: - Set markers
+ if context.coordinator.oldMarkers != markers {
+ print("center = \(context.coordinator.shouldCenter)")
+ uiViewController.display(markers: markers,
+ isReport: false,
+ center: context.coordinator.shouldCenter)
+ context.coordinator.shouldCenter = false
+ }
+ context.coordinator.oldMarkers = markers
+
+ // MARK: - Center selected marker
+ if let selected = selected {
+ uiViewController.focusOn(marker: selected)
+ self.selected = nil
+ }
+ }
+
+ static func dismantleUIViewController(_ uiViewController: MapViewController, coordinator: Coordinator) {
+ uiViewController.dismantle()
+ }
+}
diff --git a/iosApp/iosApp/Map/MapViewController.swift b/iosApp/iosApp/Map/MapViewController.swift
new file mode 100644
index 0000000..131a511
--- /dev/null
+++ b/iosApp/iosApp/Map/MapViewController.swift
@@ -0,0 +1,338 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import UIKit
+import WhirlyGlobe
+import shared
+
+typealias MarkerCallback = (Int32?) -> ()
+
+class MapViewController: UIViewController {
+ var markerCallback: MarkerCallback? = nil
+ var mapLayer: MapLayer = MapLayer.companion.defaultLayer
+
+ @IBOutlet weak var mapContainer: UIView!
+ @IBOutlet weak var attributionText: UITextView!
+
+ private var mapView: OurMaplyViewController!
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ // MARK: - Initialise MapViewController
+ mapView = OurMaplyViewController(mapType: .typeFlat)
+ mapView.delegate = self
+ view.sendSubviewToBack(mapContainer)
+ mapContainer.addSubview(mapView.view)
+ mapView.view.frame = mapContainer.bounds
+ addChild(mapView)
+
+ setAttributionText(mapLayer)
+
+ // MARK: - Configure MaplyViewController
+ let tileInfo = Utils.tileInfoFrom(layer: mapLayer)
+ mapView.setZoomLimits(minZoom: mapLayer.minZoom,
+ maxZoom: mapLayer.maxZoom)
+
+
+ let sampleParams = MaplySamplingParams()
+ sampleParams.coordSys = MaplySphericalMercator(webStandard: ())
+ sampleParams.coverPoles = true
+ sampleParams.edgeMatching = true
+ sampleParams.minZoom = tileInfo.minZoom
+ sampleParams.maxZoom = tileInfo.maxZoom
+ sampleParams.singleLevel = true
+ sampleParams.maxTiles = 25
+
+ if let loader = MaplyQuadImageLoader(params: sampleParams,
+ tileInfo: tileInfo,
+ viewC: mapView) {
+ mapView.setLoader(loader)
+ }
+
+ mapView.runOnInit {
+ let point = MaplyCoordinateMakeWithDegrees(-100.36, 23.191)
+ self.mapView.setPosition(point, height: 0.4)
+ }
+ }
+
+ func setMapLayer(_ layer: MapLayer) {
+ setAttributionText(layer)
+ mapView.setLayer(layer)
+ }
+
+ func display(markers: [Marker],
+ isReport: Bool,
+ center: Bool = false) {
+ mapView.runOnInit {
+ self.mapView.display(markers: markers,
+ isReport: isReport,
+ center: center)
+ }
+ }
+
+ func focusOn(marker: Marker) {
+ mapView.runOnInit {
+ self.mapView.focusOn(marker: marker)
+ }
+ }
+
+ func dismantle() {
+ mapView.dismantle()
+ }
+
+ private func setAttributionText(_ layer: MapLayer) {
+ DispatchQueue.main.async {
+ self.attributionText.attributedText = HtmlString.htmlToAttrStr(
+ layer.attribution,
+ size: UIFont.smallSystemFontSize,
+ color: UIColor.label)
+ }
+ attributionText.sizeToFit()
+ attributionText.layoutIfNeeded()
+ }
+
+ @IBAction func onZoomInPressed(_ sender: UIButton) {
+ mapView.zoomIn()
+ }
+
+ @IBAction func onZoomOutPressed(_ sender: UIButton) {
+ mapView.zoomOut()
+ }
+}
+
+extension MapViewController: MaplyViewControllerDelegate {
+
+ func maplyViewController(_ viewC: MaplyViewController,
+ didTapAt coord: MaplyCoordinate) {
+ markerCallback?(nil)
+ }
+
+ func maplyViewController(_ viewC: MaplyViewController,
+ didSelect selectedObj: NSObject,
+ atLoc coord: MaplyCoordinate,
+ onScreen screenPt: CGPoint) {
+ if let marker = selectedObj as? MaplyScreenMarker {
+ if let id = marker.userObject as? Int32 {
+ markerCallback?(id)
+ }
+ }
+ }
+
+}
+
+class OurMaplyViewController: MaplyViewController {
+ private var loader: MaplyQuadImageLoader? = nil
+ private var objects = [MaplyComponentObject]()
+ private var geofenceObjects = [MaplyComponentObject]()
+
+ func runOnInit(callback: @escaping () -> ()) {
+ addPostInitBlock {
+ callback()
+ }
+ }
+
+ func setLoader(_ loader: MaplyQuadImageLoader) {
+ self.loader = loader
+ }
+
+ func setLayer(_ layer: MapLayer) {
+ loader?.changeTileInfo(Utils.tileInfoFrom(layer: layer))
+ setZoomLimits(minZoom: layer.minZoom,
+ maxZoom: layer.maxZoom)
+ }
+
+ func focusOn(point: MaplyCoordinate,
+ height: Float = 0.0000264,
+ animated: Bool = true) {
+ let z = max(height, getMinZoom())
+ if animated {
+ animate(toPosition: point, height: z, time: 0.2)
+ } else {
+ setPosition(point, height: z)
+ }
+ }
+
+ func focusOn(marker: Marker, animated: Bool = true) {
+ let point = MaplyCoordinateMakeWithDegrees(Float(marker.longitude),
+ Float(marker.latitude))
+ focusOn(point: point, animated: animated)
+ }
+
+ func zoomIn() {
+ let pos = getPosition()
+ let zoom = currentMapScale() / 2
+ focusOn(point: pos, height: height(forMapScale: zoom))
+ }
+
+ func zoomOut() {
+ let pos = getPosition()
+ let zoom = currentMapScale() * 2
+ focusOn(point: pos, height: height(forMapScale: zoom))
+ }
+
+ func clear(geofences: Bool = false) {
+ if geofences {
+ remove(geofenceObjects)
+ geofenceObjects.removeAll()
+ } else {
+ remove(objects)
+ objects.removeAll()
+ }
+ }
+
+ func display(markers: [Marker],
+ isReport: Bool,
+ center: Bool = false) {
+ clear()
+
+ let points = markers.map { marker in
+ MaplyCoordinateMakeWithDegrees(Float(marker.longitude),
+ Float(marker.latitude))
+ }
+
+ let fontSize = 11.0
+ let colorReport = UIColor.green
+ let colorLabel = UIColor.secondaryLabel
+ let colorLabelOutline = UIColor.systemBackground
+
+ let vectorDesc: [AnyHashable : Any] = [
+ kMaplyColor: colorReport,
+ kMaplyVecWidth: 20.0
+ ]
+
+ let labelDesc: [AnyHashable : Any] = [
+ kMaplyFont: UIFont.boldSystemFont(ofSize: fontSize),
+ kMaplyTextColor: colorLabel,
+ kMaplyTextOutlineColor: colorLabelOutline,
+ kMaplyTextOutlineSize: 3.0
+ ]
+
+ /* MARK: - Draw markers for positions */
+ let screenMarkers = markers.enumerated().map { (i, marker) -> MaplyScreenMarker in
+ let screenMarker = MaplyScreenMarker()
+ screenMarker.layoutImportance = .greatestFiniteMagnitude
+ screenMarker.loc = MaplyCoordinateMakeWithDegrees(Float(marker.longitude),
+ Float(marker.latitude))
+ var type: Marker.Type_ = .default_
+ if isReport {
+ // For reports, position, start and end icons must be different
+ switch i {
+ case markers.startIndex: type = .reportStart
+ case markers.endIndex: type = .reportEnd
+ default: type = .reportPosition
+ }
+ } else {
+ type = marker.type
+ }
+ screenMarker.image = getIcon(markerType: type)
+
+ var size = 50.0
+ if isReport {
+ // For reports, position, start and end sizes must be different
+ switch i {
+ case markers.startIndex: size = 50.0
+ case markers.endIndex: size = 50.0
+ default: size = 25.0
+ }
+ }
+ screenMarker.size = CGSize(width: size, height: size)
+ screenMarker.userObject = marker.id
+ screenMarker.selectable = true
+
+ return screenMarker
+ }
+
+ if let objs = addScreenMarkers(screenMarkers, desc: nil, mode: .any) {
+ objects.append(objs)
+ }
+
+ /* MARK: - Add labels for markers */
+ if !isReport && !markers.isEmpty {
+ let screenLabels = markers.map { marker -> MaplyScreenLabel in
+ let label = MaplyScreenLabel()
+ label.layoutImportance = .greatestFiniteMagnitude
+ var text = marker.name
+ if marker.name.count >= 20 {
+ let end = marker.name.index(marker.name.startIndex, offsetBy: 20)
+ text = String(marker.name[..<end])
+ }
+ label.text = text
+ label.loc = MaplyCoordinateMakeWithDegrees(Float(marker.longitude),
+ Float(marker.latitude))
+ label.offset = CGPoint(x: 0.0, y: 25.0)
+
+ return label
+ }
+
+ if let objs = addScreenLabels(screenLabels, desc: labelDesc) {
+ objects.append(objs)
+ }
+ }
+
+ /* MARK: - Draw polyline for report */
+ if isReport && !markers.isEmpty {
+ let geoJSON: [AnyHashable : Any] = [
+ "type": "FeatureCollection",
+ "features": [
+ [
+ "type": "LineString",
+ "coordinates": points.map({ point in
+ [point.x, point.y]
+ })
+ ]
+ ]
+ ]
+ if let vector = MaplyVectorObject(fromGeoJSONDictionary: geoJSON) {
+ if let objs = addVectors([vector], desc: vectorDesc, mode: .any) {
+ objects.append(objs)
+ }
+ }
+ }
+
+ /* MARK: - Center map to bounds */
+ if center && !markers.isEmpty {
+ let box = MaplyBoundingBoxExpandByFraction(
+ MaplyBoundingBoxFromCoordinates(points, UInt32(points.count)), 0.1)
+ let center = MaplyCoordinate(x: (box.ur.x + box.ll.x) / 2,
+ y: (box.ur.y + box.ll.y) / 2)
+ let zoom = max(findHeight(toViewBounds: box, pos: center), getMinZoom())
+ setPosition(center, height: zoom)
+ }
+ }
+
+ func setZoomLimits(minZoom: Int32, maxZoom: Int32) {
+ setZoomLimitsMin(
+ height(forMapScale: Float(truncating:
+ MapCalculus.companion.zoomLevelToScale(zoom: maxZoom)
+ ?? MapCalculus.companion.zoomLevelToScale(zoom: 21)!
+ )),
+ max: height(forMapScale: Float(truncating:
+ MapCalculus.companion.zoomLevelToScale(zoom: minZoom)
+ ?? MapCalculus.companion.zoomLevelToScale(zoom: 1)!
+ )))
+ }
+
+ func dismantle() {
+ loader?.shutdown()
+ teardown()
+ }
+
+ private func getIcon(markerType: Marker.Type_) -> UIImage {
+ return UIImage(named: MarkerTransformations
+ .markerTypeToImageName(markerType: markerType))!
+ }
+}
diff --git a/iosApp/iosApp/Map/MapViewController.xib b/iosApp/iosApp/Map/MapViewController.xib
new file mode 100644
index 0000000..305a15b
--- /dev/null
+++ b/iosApp/iosApp/Map/MapViewController.xib
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+ <device id="retina5_9" orientation="portrait" appearance="light"/>
+ <dependencies>
+ <deployment identifier="iOS"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
+ <capability name="Image references" minToolsVersion="12.0"/>
+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+ <capability name="System colors in document resources" minToolsVersion="11.0"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+ </dependencies>
+ <objects>
+ <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MapViewController" customModule="iosApp" customModuleProvider="target">
+ <connections>
+ <outlet property="attributionText" destination="R7q-da-DO1" id="Noy-FR-ZRo"/>
+ <outlet property="mapContainer" destination="T6C-8E-ftt" id="esY-iz-qsl"/>
+ <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
+ </connections>
+ </placeholder>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+ <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="XUh-lD-GKm">
+ <rect key="frame" x="317" y="52" width="50" height="50"/>
+ <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+ <constraints>
+ <constraint firstAttribute="height" constant="50" id="SFA-XB-o3z"/>
+ <constraint firstAttribute="width" constant="50" id="ezA-Bu-6Mq"/>
+ </constraints>
+ <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+ <state key="normal">
+ <color key="titleColor" systemColor="labelColor"/>
+ <imageReference key="image" image="plus" catalog="system" symbolScale="large"/>
+ <preferredSymbolConfiguration key="preferredSymbolConfiguration"/>
+ </state>
+ <userDefinedRuntimeAttributes>
+ <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
+ <integer key="value" value="10"/>
+ </userDefinedRuntimeAttribute>
+ </userDefinedRuntimeAttributes>
+ <connections>
+ <action selector="onZoomInPressed:" destination="-1" eventType="touchUpInside" id="x4P-sk-jdi"/>
+ </connections>
+ </button>
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kdu-l3-IK7">
+ <rect key="frame" x="317" y="110" width="50" height="50"/>
+ <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+ <constraints>
+ <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="50" id="2yG-8e-OLn"/>
+ <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="50" id="ACq-Cq-PTq"/>
+ <constraint firstAttribute="width" constant="50" id="Ep3-3d-iue"/>
+ <constraint firstAttribute="height" constant="50" id="gMl-lS-Lvw"/>
+ </constraints>
+ <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+ <state key="normal">
+ <color key="titleColor" systemColor="labelColor"/>
+ <imageReference key="image" image="minus" catalog="system" symbolScale="large"/>
+ <preferredSymbolConfiguration key="preferredSymbolConfiguration"/>
+ </state>
+ <userDefinedRuntimeAttributes>
+ <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
+ <integer key="value" value="10"/>
+ </userDefinedRuntimeAttribute>
+ </userDefinedRuntimeAttributes>
+ <connections>
+ <action selector="onZoomOutPressed:" destination="-1" eventType="touchUpInside" id="rt2-fy-VCy"/>
+ </connections>
+ </button>
+ <textView clipsSubviews="YES" multipleTouchEnabled="YES" userInteractionEnabled="NO" alpha="0.40000000000000002" contentMode="scaleToFill" scrollEnabled="NO" editable="NO" text="Copyright (C) 2020 OpenStreetMap" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="R7q-da-DO1">
+ <rect key="frame" x="0.0" y="745" width="375" height="33"/>
+ <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+ <color key="textColor" systemColor="labelColor"/>
+ <fontDescription key="fontDescription" name=".AppleSystemUIFont" family=".AppleSystemUIFont" pointSize="14"/>
+ <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
+ </textView>
+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="T6C-8E-ftt">
+ <rect key="frame" x="0.0" y="44" width="375" height="734"/>
+ <color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
+ </view>
+ </subviews>
+ <viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
+ <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+ <constraints>
+ <constraint firstItem="T6C-8E-ftt" firstAttribute="trailing" secondItem="fnl-2z-Ty3" secondAttribute="trailing" id="Adi-2F-rXH"/>
+ <constraint firstItem="T6C-8E-ftt" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" id="EGw-gK-1tb"/>
+ <constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="XUh-lD-GKm" secondAttribute="trailing" constant="8" id="END-FB-FNk"/>
+ <constraint firstItem="T6C-8E-ftt" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="HzR-cl-3zE"/>
+ <constraint firstItem="R7q-da-DO1" firstAttribute="bottom" secondItem="fnl-2z-Ty3" secondAttribute="bottom" id="NMu-yb-3sE"/>
+ <constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="kdu-l3-IK7" secondAttribute="trailing" constant="8" id="Um2-vS-uoQ"/>
+ <constraint firstItem="R7q-da-DO1" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="XM1-Gu-sfE"/>
+ <constraint firstItem="kdu-l3-IK7" firstAttribute="top" secondItem="XUh-lD-GKm" secondAttribute="bottom" constant="8" id="hTB-Wm-3eQ"/>
+ <constraint firstItem="R7q-da-DO1" firstAttribute="trailing" secondItem="fnl-2z-Ty3" secondAttribute="trailing" id="heK-zH-Ob4"/>
+ <constraint firstItem="T6C-8E-ftt" firstAttribute="bottom" secondItem="fnl-2z-Ty3" secondAttribute="bottom" id="oT6-iC-7PW"/>
+ <constraint firstItem="XUh-lD-GKm" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="8" id="oXT-Ln-tOw"/>
+ </constraints>
+ <point key="canvasLocation" x="140" y="96.059113300492612"/>
+ </view>
+ </objects>
+ <resources>
+ <image name="minus" catalog="system" width="128" height="24"/>
+ <image name="plus" catalog="system" width="128" height="113"/>
+ <systemColor name="labelColor">
+ <color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+ </systemColor>
+ <systemColor name="secondarySystemBackgroundColor">
+ <color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ </systemColor>
+ <systemColor name="systemBackgroundColor">
+ <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+ </systemColor>
+ </resources>
+</document>
diff --git a/iosApp/iosApp/Map/UnitMapView.swift b/iosApp/iosApp/Map/UnitMapView.swift
new file mode 100644
index 0000000..533ac13
--- /dev/null
+++ b/iosApp/iosApp/Map/UnitMapView.swift
@@ -0,0 +1,44 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import SwiftUI
+import shared
+
+struct UnitMapView: View {
+ @StateObject var unitsViewModel: UnitsViewModel
+
+ var body: some View {
+ ZStack {
+ MapView(layer: $unitsViewModel.mapLayerType,
+ markers: $unitsViewModel.markers,
+ selected: $unitsViewModel.selectedMarker,
+ markerCallback: unitsViewModel.selectUnitWith)
+ if let unit = unitsViewModel.selectedUnit {
+ VStack {
+ DeviceRow(unit: unit, callback: { action in
+ unitsViewModel.show(action: action, for: unit)
+ }, isCell: false)
+ .padding()
+ .background(.secondarySystemBackground)
+ }
+ .frame(maxWidth: .infinity,
+ maxHeight: .infinity,
+ alignment: .bottom)
+ }
+ }
+ }
+}
diff --git a/iosApp/iosApp/Session/AboutView.swift b/iosApp/iosApp/Session/AboutView.swift
new file mode 100644
index 0000000..7e5325b
--- /dev/null
+++ b/iosApp/iosApp/Session/AboutView.swift
@@ -0,0 +1,48 @@
+//
+// AboutView.swift
+// iosApp
+//
+// Created by Iván on 15/02/22.
+// Copyright © 2022 orgName. All rights reserved.
+//
+
+import SwiftUI
+
+struct AboutView: View {
+
+ private func getVersion() -> String? {
+ return Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
+ }
+
+ var body: some View {
+ List {
+ Text("about-text").padding()
+ if let version = getVersion() {
+ HStack {
+ Text("version")
+ Spacer()
+ Text(version).foregroundColor(.secondary)
+ }
+ }
+
+ Button {
+ if let url = URL(string: NSLocalizedString("app-source-code", comment: "")) {
+ if UIApplication.shared.canOpenURL(url) {
+ UIApplication.shared.open(url, options: [:])
+ }
+ }
+ } label: {
+ Label("source-code", systemImage: "chevron.left.forwardslash.chevron.right")
+ }
+
+ Button {
+ if let url = URL(string: NSLocalizedString("app-website", comment: "")) {
+ if UIApplication.shared.canOpenURL(url) {
+ UIApplication.shared.open(url, options: [:])
+ }
+ } } label: {
+ Label("website", systemImage: "globe")
+ }
+ }
+ }
+}
diff --git a/iosApp/iosApp/Session/AccountView.swift b/iosApp/iosApp/Session/AccountView.swift
new file mode 100644
index 0000000..4ca453a
--- /dev/null
+++ b/iosApp/iosApp/Session/AccountView.swift
@@ -0,0 +1,73 @@
+//
+// AccountView.swift
+// iosApp
+//
+// Created by Iván on 15/02/22.
+// Copyright © 2022 orgName. All rights reserved.
+//
+
+import SwiftUI
+
+struct AccountView: View {
+ @StateObject var accountViewModel = AccountViewModel()
+ @EnvironmentObject var rootViewModel: RootViewModel
+
+ var body: some View {
+ List {
+ Section {
+ // MARK: - Name
+ if let name = accountViewModel.user?.name {
+ HStack {
+ Text("username")
+ Spacer()
+ Text(name).foregroundColor(.secondaryLabel)
+ }
+ }
+ // MARK: - E-mail
+ if let email = accountViewModel.user?.email {
+ HStack {
+ Text("email")
+ Spacer()
+ Text(email).foregroundColor(.secondaryLabel)
+ }
+ }
+ // MARK: - Unique ID
+ if let uid = accountViewModel.user?.id {
+ HStack {
+ Text("unique-id")
+ Spacer()
+ Text("\(uid)").foregroundColor(.secondaryLabel)
+ }
+ }
+ // MARK: - Administrator
+ if let admin = accountViewModel.user?.administrator {
+ HStack {
+ Text("admin")
+ Spacer()
+ Text("\(admin)").foregroundColor(.secondaryLabel)
+ }
+ }
+ // MARK: - Server URL
+ if let server = UserDefaults.standard.string(forKey: "server-url") {
+ HStack {
+ Text("server-url")
+ Spacer()
+ Text(server).foregroundColor(.secondaryLabel)
+ }
+ }
+ }
+
+ Section {
+ // MARK: - Sign out
+ Button {
+ rootViewModel.signOut()
+ } label: {
+ Label("signout", systemImage: "rectangle.portrait.and.arrow.right")
+ .foregroundColor(.systemRed)
+ }
+ }
+ }.onAppear {
+ accountViewModel.fetchUserInfo()
+ }
+ }
+}
diff --git a/iosApp/iosApp/Session/AccountViewModel.swift b/iosApp/iosApp/Session/AccountViewModel.swift
new file mode 100644
index 0000000..7953265
--- /dev/null
+++ b/iosApp/iosApp/Session/AccountViewModel.swift
@@ -0,0 +1,29 @@
+//
+// AccountViewModel.swift
+// iosApp
+//
+// Created by Iván on 15/02/22.
+// Copyright © 2022 orgName. All rights reserved.
+//
+
+import Foundation
+import shared
+
+class AccountViewModel: ObservableObject {
+ @Inject var sessionController: SessionController
+
+ @Published var user: User? = nil
+
+ init() {
+ let userCollector = Collector<User?>(callback: setUser)
+ sessionController.userFlow.collect(collector: userCollector) {_, _ in }
+ }
+
+ func setUser(user: User?) {
+ self.user = user
+ }
+
+ func fetchUserInfo() {
+ self.sessionController.getSession()
+ }
+}
diff --git a/iosApp/iosApp/Authentication/LoginView.swift b/iosApp/iosApp/Session/RootView.swift
index 5014ca5..297a2aa 100644
--- a/iosApp/iosApp/Authentication/LoginView.swift
+++ b/iosApp/iosApp/Session/RootView.swift
@@ -1,46 +1,61 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
import SwiftUI
import shared
-struct LoginContainerView: View {
+class SessionState: ObservableObject {
+ @Published var loggedIn = false
+}
+
+struct RootView: View {
+ @StateObject private var rootViewModel = RootViewModel()
@State private var username = ""
@State private var password = ""
- @State private var server = ""
-
- private var sessionController = SessionController(
- sessionApi: SessionApi(defaultBaseUrl: "https://etbsa.net/api"),
- usersApi: UsersApi(defaultBaseUrl: "https://etbsa.net/api"))
+ @State private var server: String
init() {
- sessionController.loginStateFlow.collect(collector: Kotlinx_coroutines_coreFlowCollector) { <#KotlinUnit?#>, <#Error?#> in
- <#code#>
- }
+ server = UserDefaults.standard.string(forKey: "server-url")
+ ?? NSLocalizedString("app-server-url", comment: "")
}
var body: some View {
- LoginView(username: $username,
- password: $password,
- server: $server,
- onLogin: login)
- }
-
- private func login() {
- print("Username: \(username)")
- print("Password: \(password)")
- print("Server URL: \(server)")
- sessionController.login(
- body: SessionBody(url: server,
- email: username,
- password: password,
- fcmToken: nil))
+ Group {
+ switch rootViewModel.loginState {
+ case is SessionController.LoginStateLoading:
+ LoadingView()
+ case is SessionController.LoginStateSuccess:
+ UnitsView()
+ default:
+ LoginContentView(username: $username,
+ password: $password,
+ server: $server,
+ onLogin: rootViewModel.login)
+ }
+ }.environmentObject(rootViewModel)
}
}
-struct LoginView: View {
+struct LoginContentView: View {
@Binding var username: String
@Binding var password: String
@Binding var server: String
- let onLogin: () -> Void
+ let onLogin: (String, String, String) -> Void
var body: some View {
VStack {
@@ -53,7 +68,7 @@ struct LoginView: View {
server: $server)
Button(action: {
- self.onLogin()
+ self.onLogin(username, password, server)
}) {
Text("login")
.font(.system(size: 18))
@@ -67,6 +82,8 @@ struct LoginView: View {
}
}
+// Source: https://github.com/niochat/nio
+
struct LoginTitleView: View {
var body: some View {
return VStack {
diff --git a/iosApp/iosApp/Session/RootViewModel.swift b/iosApp/iosApp/Session/RootViewModel.swift
new file mode 100644
index 0000000..682deee
--- /dev/null
+++ b/iosApp/iosApp/Session/RootViewModel.swift
@@ -0,0 +1,60 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import Foundation
+import shared
+
+class RootViewModel: ObservableObject {
+ @Inject private var sessionController: SessionController
+
+ @Published var loginState: SessionController.LoginState = SessionController.LoginStateNothing()
+
+ init() {
+ let collector = Collector<SessionController.LoginState?>(callback: setLoginState)
+ sessionController.loginStateFlow.collect(collector: collector) { (unit, error) in }
+ restoreSession()
+ }
+
+ func setLoginState(state: SessionController.LoginState?) {
+ print("State is: \(state?.debugDescription ?? "")")
+ self.loginState = state ?? SessionController.LoginStateNothing()
+ }
+
+ func restoreSession() {
+ sessionController.restoreSession()
+ }
+
+ private func getFcmToken() -> String? {
+ let token = UserDefaults.standard.string(forKey: "fcmtoken")
+ print("FCM token is \(String(describing: token))")
+ return token
+ }
+
+ func login(username: String, password: String, url: String) {
+ print("Username: \(username)")
+ print("Password: \(password)")
+ print("Server URL: \(url)")
+ sessionController.login(body: SessionBody(url: url,
+ email: username,
+ password: password,
+ fcmToken: getFcmToken()))
+ }
+
+ func signOut() {
+ sessionController.logout(token: getFcmToken())
+ }
+}
diff --git a/iosApp/iosApp/Session/UserInformationView.swift b/iosApp/iosApp/Session/UserInformationView.swift
new file mode 100644
index 0000000..98d4bfd
--- /dev/null
+++ b/iosApp/iosApp/Session/UserInformationView.swift
@@ -0,0 +1,50 @@
+//
+// UserInformationView.swift
+// iosApp
+//
+// Created by Iván on 15/02/22.
+// Copyright © 2022 orgName. All rights reserved.
+//
+
+import SwiftUI
+
+struct UserInformationView: View {
+ @Environment(\.presentationMode) var presentationMode
+ @State var action = Action.account
+
+ enum Action {
+ case account
+ case about
+ }
+
+ var body: some View {
+ NavigationView {
+ VStack {
+ switch action {
+ case .account:
+ AccountView()
+ case .about:
+ AboutView()
+ }
+ }
+ .navigationBarTitleView(
+ Picker(selection: $action) {
+ Text("account").tag(Action.account)
+ Text("about").tag(Action.about)
+ } label: {
+ EmptyView()
+ }.pickerStyle(SegmentedPickerStyle())
+ )
+ .navigationBarTitleDisplayMode(.inline)
+ .toolbar {
+ ToolbarItem(placement: .navigationBarTrailing) {
+ Button {
+ presentationMode.wrappedValue.dismiss()
+ } label: {
+ Text("done").bold()
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/iosApp/iosApp/Shared/FlowCollector.swift b/iosApp/iosApp/Shared/FlowCollector.swift
new file mode 100644
index 0000000..628c0cd
--- /dev/null
+++ b/iosApp/iosApp/Shared/FlowCollector.swift
@@ -0,0 +1,35 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import Foundation
+import shared
+
+// Source: https://stackoverflow.com/66030092
+class Collector<T>: Kotlinx_coroutines_coreFlowCollector {
+
+ let callback: (T) -> Void
+
+ init(callback: @escaping (T) -> Void) {
+ self.callback = callback
+ }
+
+ func emit(value: Any?, completionHandler: @escaping (KotlinUnit?, Error?) -> Void) {
+ callback(value as! T)
+
+ completionHandler(KotlinUnit(), nil)
+ }
+}
diff --git a/iosApp/iosApp/Shared/HyperlinkText.swift b/iosApp/iosApp/Shared/HyperlinkText.swift
new file mode 100644
index 0000000..a735f8d
--- /dev/null
+++ b/iosApp/iosApp/Shared/HyperlinkText.swift
@@ -0,0 +1,103 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import Foundation
+import UIKit
+
+// Source: https://stackoverflow.com/a/50272137
+extension UIColor {
+ enum HexFormat {
+ case RGB
+ case ARGB
+ case RGBA
+ case RRGGBB
+ case AARRGGBB
+ case RRGGBBAA
+ }
+
+ enum HexDigits {
+ case d3, d4, d6, d8
+ }
+
+ func hexString(_ format: HexFormat = .RRGGBBAA) -> String {
+ let maxi = [.RGB, .ARGB, .RGBA].contains(format) ? 16 : 256
+
+ func toI(_ f: CGFloat) -> Int {
+ return min(maxi - 1, Int(CGFloat(maxi) * f))
+ }
+
+ var r: CGFloat = 0
+ var g: CGFloat = 0
+ var b: CGFloat = 0
+ var a: CGFloat = 0
+
+ self.getRed(&r, green: &g, blue: &b, alpha: &a)
+
+ let ri = toI(r)
+ let gi = toI(g)
+ let bi = toI(b)
+ let ai = toI(a)
+
+ switch format {
+ case .RGB: return String(format: "#%X%X%X", ri, gi, bi)
+ case .ARGB: return String(format: "#%X%X%X%X", ai, ri, gi, bi)
+ case .RGBA: return String(format: "#%X%X%X%X", ri, gi, bi, ai)
+ case .RRGGBB: return String(format: "#%02X%02X%02X", ri, gi, bi)
+ case .AARRGGBB: return String(format: "#%02X%02X%02X%02X", ai, ri, gi, bi)
+ case .RRGGBBAA: return String(format: "#%02X%02X%02X%02X", ri, gi, bi, ai)
+ }
+ }
+
+ func hexString(_ digits: HexDigits) -> String {
+ switch digits {
+ case .d3: return hexString(.RGB)
+ case .d4: return hexString(.RGBA)
+ case .d6: return hexString(.RRGGBB)
+ case .d8: return hexString(.RRGGBBAA)
+ }
+ }
+}
+
+// Source: https://swiftuirecipes.com/blog/swiftui-text-with-html-via-nsattributedstring
+class HtmlString {
+ static func htmlToAttrStr(_ html: String, size: CGFloat, color: UIColor) -> NSAttributedString? {
+ let fullHTML = """
+ <!doctype html>
+ <html>
+ <head>
+ <style>
+ body {
+ font-family: -apple-system;
+ font-size: \(size)px;
+ color: \(color.hexString(.RGB))
+ }
+ </style>
+ </head>
+ <body>
+ \(html)
+ </body>
+ </html>
+ """
+ if let data = fullHTML.data(using: .utf8) {
+ return try? NSAttributedString(
+ data: data,
+ options: [.documentType: NSAttributedString.DocumentType.html],
+ documentAttributes: nil)
+ }
+ return nil
+ }
+}
diff --git a/iosApp/iosApp/Shared/Inject.swift b/iosApp/iosApp/Shared/Inject.swift
new file mode 100644
index 0000000..5b292b0
--- /dev/null
+++ b/iosApp/iosApp/Shared/Inject.swift
@@ -0,0 +1,34 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import Foundation
+import shared
+
+// Source: https://www.kiloloco.com/articles/004-dependency-injection-via-property-wrappers/
+// Source: https://medium.com/swlh/c1f02f06cd51
+@propertyWrapper
+struct Inject<T: Injectable> {
+ var injectable: T
+
+ init() {
+ injectable = Resolver.shared.resolve()
+ }
+
+ public var wrappedValue: T {
+ get { return injectable }
+ }
+}
diff --git a/iosApp/iosApp/Shared/LoadingView.swift b/iosApp/iosApp/Shared/LoadingView.swift
new file mode 100644
index 0000000..ef88f99
--- /dev/null
+++ b/iosApp/iosApp/Shared/LoadingView.swift
@@ -0,0 +1,28 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import SwiftUI
+
+struct LoadingView: UIViewRepresentable {
+ func makeUIView(context: Context) -> UIActivityIndicatorView {
+ return UIActivityIndicatorView(style: .large)
+ }
+
+ func updateUIView(_ uiView: UIActivityIndicatorView, context: Context) {
+ uiView.startAnimating()
+ }
+}
diff --git a/iosApp/iosApp/Shared/MarkerTransformations.swift b/iosApp/iosApp/Shared/MarkerTransformations.swift
new file mode 100644
index 0000000..2e71980
--- /dev/null
+++ b/iosApp/iosApp/Shared/MarkerTransformations.swift
@@ -0,0 +1,49 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import SwiftUI
+import shared
+
+class MarkerTransformations {
+ static func markerTypeToImageName(markerType: Marker.Type_) -> String {
+ var imageName = "MapDefault"
+ switch markerType {
+ case .animal: imageName = "MapAnimal"
+ case .bicycle: imageName = "MapBicycle"
+ case .boat: imageName = "MapBoat"
+ case .bus: imageName = "MapBus"
+ case .car: imageName = "MapCar"
+ case .crane: imageName = "MapCrane"
+ case .helicopter: imageName = "MapHelicopter"
+ case .motorcycle: imageName = "MapMotorcycle"
+ case .offroad: imageName = "MapOffroad"
+ case .person: imageName = "MapPerson"
+ case .pickup: imageName = "MapPickup"
+ case .plane: imageName = "MapPlane"
+ case .scooter: imageName = "MapScooter"
+ case .ship: imageName = "MapShip"
+ case .tractor: imageName = "MapTractor"
+ case .train: imageName = "MapTrain"
+ case .tram: imageName = "MapTram"
+ case .trolleybus: imageName = "MapTrolleybus"
+ case .truck: imageName = "MapTruck"
+ case .van: imageName = "MapVan"
+ default: break
+ }
+ return imageName
+ }
+}
diff --git a/iosApp/iosApp/Shared/Resolver.swift b/iosApp/iosApp/Shared/Resolver.swift
new file mode 100644
index 0000000..3935405
--- /dev/null
+++ b/iosApp/iosApp/Shared/Resolver.swift
@@ -0,0 +1,45 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import Foundation
+import shared
+
+// Source: https://www.kiloloco.com/articles/004-dependency-injection-via-property-wrappers/
+// Source: https://medium.com/swlh/c1f02f06cd51
+class Resolver {
+
+ private var storage = [String: (Resolver) -> Injectable]()
+
+ static let shared = Resolver()
+ private init() {}
+
+ func add(_ type: Injectable.Type, factory: @escaping (Resolver) -> Injectable) {
+ let key = String(reflecting: type.self)
+ storage[key] = factory
+ }
+
+ func resolve<T: Injectable>() -> T {
+ let key = String(reflecting: T.self)
+
+ guard let injectable = storage[key]?(self) as? T else {
+ fatalError("\(key) has not been added as an injectable object.")
+ }
+
+ return injectable
+ }
+
+}
diff --git a/iosApp/iosApp/Shared/SmallLabelStyle.swift b/iosApp/iosApp/Shared/SmallLabelStyle.swift
new file mode 100644
index 0000000..51308e0
--- /dev/null
+++ b/iosApp/iosApp/Shared/SmallLabelStyle.swift
@@ -0,0 +1,32 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import SwiftUI
+
+struct SmallLabelStyle: LabelStyle {
+ func makeBody(configuration: Configuration) -> some View {
+ HStack {
+ configuration.icon
+ .foregroundColor(.secondary)
+ .imageScale(.small)
+
+ configuration.title
+ .font(.subheadline)
+ .foregroundColor(.secondary)
+ }
+ }
+}
diff --git a/iosApp/iosApp/Shared/Utils.swift b/iosApp/iosApp/Shared/Utils.swift
new file mode 100644
index 0000000..61a8f90
--- /dev/null
+++ b/iosApp/iosApp/Shared/Utils.swift
@@ -0,0 +1,48 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import Foundation
+import CryptoKit
+import WhirlyGlobe
+import shared
+
+class Utils {
+ static func MD5(string: String) -> String {
+ let digest = Insecure.MD5.hash(data: string.data(using: .utf8) ?? Data())
+ return digest.map {
+ String(format: "%02hhx", $0)
+ }.joined()
+ }
+
+ static func tileInfoFrom(layer: MapLayer) -> MaplyRemoteTileInfoNew {
+ let cacheDir = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)[0]
+ let thisCacheDir = "\(cacheDir)/\(Utils.MD5(string: layer.url))"
+
+ let tileInfo = MaplyRemoteTileInfoNew(baseURL: layer.url,
+ minZoom: layer.minZoom,
+ maxZoom: layer.maxZoom)
+ tileInfo.cacheDir = thisCacheDir
+ return tileInfo
+ }
+
+ static func getMapsURL(longitude: Float, latitude: Float) -> URL? {
+ let template = NSLocalizedString("maps-url-template", comment: "")
+ return URL(string: template
+ .replacingOccurrences(of: "{x}", with: "\(latitude)")
+ .replacingOccurrences(of: "{y}", with: "\(longitude)"))
+ }
+}
diff --git a/iosApp/iosApp/Units/UnitsView.swift b/iosApp/iosApp/Units/UnitsView.swift
new file mode 100644
index 0000000..a91511e
--- /dev/null
+++ b/iosApp/iosApp/Units/UnitsView.swift
@@ -0,0 +1,102 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import SwiftUI
+import SwiftUIX
+import shared
+
+struct UnitsView: View {
+ @StateObject var unitsViewModel = UnitsViewModel()
+ @State var shouldShowMenu = false
+
+ var body: some View {
+ NavigationView {
+ TabView(selection: $unitsViewModel.unitsDisplayMode, content: {
+ UnitMapView(unitsViewModel: unitsViewModel)
+ .tabItem {
+ Image(systemName: "map")
+ Text("map")
+ }
+ .tag(UnitsViewModel.UnitsDisplayMode.map)
+ DevicesView(unitsViewModel: unitsViewModel)
+ .tabItem {
+ Image(systemName: "list.bullet")
+ Text("devices")
+ }
+ .tag(UnitsViewModel.UnitsDisplayMode.list)
+ })
+ .navigationTitle(getNavigationTitle(unitsViewModel.unitsDisplayMode))
+ .navigationBarTitleDisplayMode(.inline)
+ .navigationSearchBar {
+ SearchBar(NSLocalizedString("search", comment: ""),
+ text: $unitsViewModel.searchQuery,
+ isEditing: $unitsViewModel.isEditing,
+ onCommit: {})
+ .showsCancelButton(unitsViewModel.isEditing)
+ .onCancel {
+ unitsViewModel.searchQuery = ""
+ }
+ }
+ .navigationSearchBarHiddenWhenScrolling(false)
+ .toolbar {
+ ToolbarItem(placement: .navigationBarTrailing) {
+ Menu {
+ Picker (selection: $unitsViewModel.mapLayerType, label: Text("map-layer")) {
+ Text("openstreetmap")
+ .tag(MapLayer.companion.layers[MapLayer.Type_.streets]!)
+ Text("satellite")
+ .tag(MapLayer.companion.layers[MapLayer.Type_.satellite]!)
+ }
+ } label: {
+ Image(systemName: "square.stack.3d.up")
+ }
+ .visible(unitsViewModel.unitsDisplayMode == .map)
+ }
+ ToolbarItem(placement: .navigationBarTrailing) {
+ Button {
+ unitsViewModel.showUserInfo = true
+ } label: {
+ Image(systemName: "person")
+ }
+ }
+ }
+ }
+ .navigationViewStyle(StackNavigationViewStyle())
+ .sheet(isPresented: $unitsViewModel.showDetails) {
+ print("Dismissed")
+ } content: {
+ DetailsView(isPresented: $unitsViewModel.showDetails,
+ action: unitsViewModel.detailsAction,
+ for: unitsViewModel.detailsUnit)
+ }
+ .sheet(isPresented: $unitsViewModel.showUserInfo) {
+ print("Dismissed")
+ } content: {
+ UserInformationView()
+ }
+
+ }
+
+ private func getNavigationTitle(_ unitDisplayMode: UnitsViewModel.UnitsDisplayMode) -> LocalizedStringKey {
+ switch unitDisplayMode {
+ case .list:
+ return "devices"
+ case .map:
+ return "map"
+ }
+ }
+}
diff --git a/iosApp/iosApp/Units/UnitsViewModel.swift b/iosApp/iosApp/Units/UnitsViewModel.swift
new file mode 100644
index 0000000..af6fe32
--- /dev/null
+++ b/iosApp/iosApp/Units/UnitsViewModel.swift
@@ -0,0 +1,139 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import Foundation
+import WhirlyGlobe
+import shared
+
+class UnitsViewModel: ObservableObject {
+ @Inject var unitsController: UnitsController
+ @Inject var geofenceController: GeofencesController
+
+ let mainScope = MainScope.companion.createMainScope()
+
+ enum UnitsDisplayMode {
+ case map
+ case list
+ }
+
+ class Camera {
+ let point: MaplyCoordinate?
+ let height: Float?
+
+ init(_ point: MaplyCoordinate? = nil,
+ height: Float? = nil) {
+ self.point = point
+ self.height = height
+ }
+ }
+
+ var detailsUnit: UnitInformation? = nil
+ var detailsAction = DeviceRow.Action.details
+
+ @Published var searchQuery = "" {
+ didSet {
+ unitsDisplayMode = .list
+ search(query: searchQuery)
+ }
+ }
+ @Published var isEditing = false
+ @Published var showDetails = false
+ @Published var showUserInfo = false
+ @Published var unitsDisplayMode: UnitsDisplayMode = .map
+ @Published var units: [UnitInformation] = [] {
+ didSet {
+ markers = units.compactMap(Marker.companion.fromUnit)
+ }
+ }
+ @Published var markers: [Marker] = []
+ @Published var selectedUnit: UnitInformation? = nil {
+ didSet {
+ if let unit = selectedUnit {
+ selectedMarker = Marker.companion.fromUnit(unit: unit)
+ } else {
+ selectedMarker = nil
+ }
+ }
+ }
+ @Published var selectedMarker: Marker? = nil
+ @Published var mapLayerType: MapLayer = .companion.defaultLayer
+ @Published var geofences: [Int: Geofence] = [:]
+ @Published var camera: Camera = Camera()
+
+ init() {
+ unitsController.fetchUnits(scope: mainScope)
+ setupObservers()
+ }
+
+ deinit {
+ MainScope.companion.cancelScope(scope: mainScope)
+ }
+
+ private func setupObservers() {
+ let unitsCollector = Collector<[UnitInformation]>(callback: setUnits)
+ unitsController.displayedUnitsFlow.collect(collector: unitsCollector) { unit, error in }
+
+ let geofencesCollector = Collector<[Int: Geofence]>(callback: setGeofences)
+ geofenceController.geofencesFlow.collect(collector: geofencesCollector) { unit, error in }
+ }
+
+ private func setUnits(units: [UnitInformation]) {
+ print("Positions")
+ self.units = units
+ }
+
+ private func setGeofences(geofences: [Int: Geofence]) {
+ self.geofences = geofences
+ }
+
+ func selectUnitWith(position id: Int32?) {
+ if id == nil {
+ print("Deselecting unit")
+ selectedUnit = nil
+ return
+ }
+ print("Selecting unit with position id: \(id ?? 0)")
+ if let unit = units.first(where: {
+ Int32(truncating: $0.position?.id ?? 0) == id
+ }) {
+ selectedUnit = unit
+ }
+ }
+
+ func toggleDisplayMode() {
+ switch unitsDisplayMode {
+ case .map:
+ unitsDisplayMode = .list
+ case .list:
+ unitsDisplayMode = .map
+ }
+ }
+
+ func search(query: String) {
+ unitsController.search(query: query)
+ }
+
+ func show(action: DeviceRow.Action, for unit: UnitInformation) {
+ if action != .close {
+ detailsAction = action
+ detailsUnit = unit
+ showDetails = true
+ } else {
+ selectedUnit = nil
+ }
+ }
+}
diff --git a/iosApp/iosApp/en.lproj/Localizable.strings b/iosApp/iosApp/en.lproj/Localizable.strings
new file mode 100644
index 0000000..392bc1c
--- /dev/null
+++ b/iosApp/iosApp/en.lproj/Localizable.strings
@@ -0,0 +1,68 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+"app-name" = "TrackerMap";
+"app-server-url" = "https://gps.trackermap.mx/api";
+"app-website" = "https://trackermap.mx";
+"app-source-code" = "https://git.sr.ht/~avalos/trackermap-mobile";
+
+"loading" = "Loading";
+"done" = "Done";
+
+"username" = "Username";
+"password" = "Password";
+"server-url" = "Server URL";
+"login" = "Login";
+
+"devices" = "Devices";
+"map" = "Map";
+"search" = "Search";
+
+"details" = "Details";
+"reports" = "Reports";
+"commands" = "Commands";
+"select-action" = "Select an action";
+
+"map-layer" = "Map layer";
+"openstreetmap" = "OpenStreetMap";
+"satellite" = "Satellite";
+
+"contact" = "Contact";
+"unique-id" = "Unique ID";
+"datetime" = "Datetime";
+"latitude" = "Latitude";
+"longitude" = "Longitude";
+"speed" = "Speed";
+"address" = "Address";
+"hourmeter" = "Hourmeter";
+"protocol" = "Protocol";
+"open-location-browser" = "Open location in browser";
+"maps-url-template" = "https://www.google.com/maps/place/{y},{x}?z=19";
+
+"send-command" = "Send command";
+"send-command-confirm" = "Are you sure you want to send the command?";
+
+"account" = "Account";
+"about" = "About";
+"email" = "E-mail";
+"admin" = "Administrator";
+"signout" = "Sign out";
+
+"about-text" = "TrackerMap is a free (as in freedom) software app for tracking and managing GPS devices in Traccar servers.\n\nTrackerMap source code is licensed under the GNU General Public License Version 3.";
+"version" = "Version";
+"website" = "Website";
+"source-code" = "Source code";
diff --git a/iosApp/iosApp/es-419.lproj/Localizable.strings b/iosApp/iosApp/es-419.lproj/Localizable.strings
new file mode 100644
index 0000000..401582e
--- /dev/null
+++ b/iosApp/iosApp/es-419.lproj/Localizable.strings
@@ -0,0 +1,68 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+"app-name" = "TrackerMap";
+"app-server-url" = "https://gps.trackermap.mx/api";
+"app-website" = "https://trackermap.mx";
+"app-source-code" = "https://git.sr.ht/~avalos/trackermap-mobile";
+
+"loading" = "Cargando";
+"done" = "Hecho";
+
+"username" = "Usuario";
+"password" = "Contraseña";
+"server-url" = "URL del servidor";
+"login" = "Iniciar sesión";
+
+"devices" = "Dispositivos";
+"map" = "Mapa";
+"search" = "Buscar";
+
+"details" = "Detalles";
+"reports" = "Reportes";
+"commands" = "Comandos";
+"select-action" = "Seleccionar una acción";
+
+"map-layer" = "Capa del mapa";
+"openstreetmap" = "OpenStreetMap";
+"satellite" = "Satélite";
+
+"contact" = "Contacto";
+"unique-id" = "ID único";
+"datetime" = "Fecha y hora";
+"latitude" = "Latitud";
+"longitude" = "Longitud";
+"speed" = "Velocidad";
+"address" = "Dirección";
+"hourmeter" = "Horómetro";
+"protocol" = "Protocolo";
+"open-location-browser" = "Abrir ubicación en navegador";
+"maps-url-template" = "https://www.google.com/maps/place/{y},{x}?z=19";
+
+"send-command" = "Enviar comando";
+"send-command-confirm" = "¿Está seguro que desea enviar el comando?";
+
+"account" = "Cuenta";
+"about" = "Acerca de";
+"email" = "Correo electrónico";
+"admin" = "Administrador";
+"signout" = "Cerrar sesión";
+
+"about-text" = "TrackerMap es una aplicación de software libre para rastrear y gestionar dispositivos GPS en servidores de Traccar.\n\nEl código fuente de TrackerMap está disponible bajo la licencia GNU General Public License versión 3.";
+"version" = "Versión";
+"website" = "Sitio web";
+"source-code" = "Código fuente";
diff --git a/iosApp/iosApp/iOSApp.swift b/iosApp/iosApp/iOSApp.swift
index 241beca..763e0e2 100644
--- a/iosApp/iosApp/iOSApp.swift
+++ b/iosApp/iosApp/iOSApp.swift
@@ -1,16 +1,85 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+import Foundation
import SwiftUI
import shared
@main
struct iOSApp: App {
-
+ @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
+
init() {
- startKoin()
+ /* Dependency injections */
+
+ Resolver.shared.add(SessionManager.self) { resolver in
+ return SessionManager(defaultBaseUrl: NSLocalizedString("app-server-url", comment: ""))
+ }
+ Resolver.shared.add(SessionApi.self) { resolver in
+ return SessionApi(sessionManager: resolver.resolve())
+ }
+ Resolver.shared.add(UsersApi.self) { resolver in
+ return UsersApi(sessionManager: resolver.resolve())
+ }
+ Resolver.shared.add(DevicesApi.self) { resolver in
+ return DevicesApi(sessionManager: resolver.resolve())
+ }
+ Resolver.shared.add(PositionsApi.self) { resolver in
+ return PositionsApi(sessionManager: resolver.resolve())
+ }
+ Resolver.shared.add(CommandsApi.self) { resolver in
+ return CommandsApi(sessionManager: resolver.resolve())
+ }
+ Resolver.shared.add(ReportsApi.self) { resolver in
+ return ReportsApi(sessionManager: resolver.resolve())
+ }
+ Resolver.shared.add(GeofencesApi.self) { resolver in
+ return GeofencesApi(sessionManager: resolver.resolve())
+ }
+ Resolver.shared.add(CommandsApi.self) { resolver in
+ return CommandsApi(sessionManager: resolver.resolve())
+ }
+ Resolver.shared.add(SessionController.self) { resolver in
+ return SessionController(sessionApi: resolver.resolve(), usersApi: resolver.resolve())
+ }
+ Resolver.shared.add(UnitsController.self) { resolver in
+ return UnitsController(devicesApi: resolver.resolve(), positionsApi: resolver.resolve())
+ }
+ Resolver.shared.add(GeofencesController.self) { resolver in
+ return GeofencesController(geofencesApi: resolver.resolve())
+ }
+ Resolver.shared.add(ReportController.self) { resolver in
+ return ReportController(reportsApi: resolver.resolve(), geofencesApi: resolver.resolve())
+ }
+ Resolver.shared.add(CommandsController.self) { resolver in
+ return CommandsController(commandsApi: resolver.resolve())
+ }
}
var body: some Scene {
WindowGroup {
- LoginContainerView()
+ RootView()
}
}
}
+
+// Source: https://stackoverflow.com/questions/56491386
+extension UIApplication {
+ func endEditing() {
+ sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
+ }
+}
diff --git a/iosApp/iosApp/iosApp.entitlements b/iosApp/iosApp/iosApp.entitlements
new file mode 100644
index 0000000..903def2
--- /dev/null
+++ b/iosApp/iosApp/iosApp.entitlements
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>aps-environment</key>
+ <string>development</string>
+</dict>
+</plist>
diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts
index 61c42f3..0ecd643 100644
--- a/shared/build.gradle.kts
+++ b/shared/build.gradle.kts
@@ -26,6 +26,7 @@ kotlin {
implementation("io.ktor:ktor-client-core:$ktor_version")
implementation("io.ktor:ktor-client-logging:$ktor_version")
implementation("io.ktor:ktor-client-serialization:$ktor_version")
+ implementation("io.insert-koin:koin-core:3.1.4")
implementation("ch.qos.logback:logback-classic:1.2.6")
implementation("com.russhwolf:multiplatform-settings:$settings_version")
@@ -60,7 +61,6 @@ kotlin {
iosArm64Main.dependsOn(this)
//iosSimulatorArm64Main.dependsOn(this)
dependencies {
- implementation("io.insert-koin:koin-ios:3.1.4")
implementation("io.ktor:ktor-client-ios:$ktor_version")
}
}
diff --git a/shared/src/androidMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/HttpClientProvider.kt b/shared/src/androidMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/HttpClientProvider.kt
new file mode 100644
index 0000000..8b43d20
--- /dev/null
+++ b/shared/src/androidMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/HttpClientProvider.kt
@@ -0,0 +1,10 @@
+package mx.trackermap.TrackerMap.client.infrastructure
+
+import io.ktor.client.*
+import io.ktor.client.engine.cio.*
+
+actual class HttpClientProvider {
+ actual fun getHttpClient(): HttpClient {
+ return HttpClient(CIO)
+ }
+} \ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/Injectable.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/Injectable.kt
new file mode 100644
index 0000000..6dda226
--- /dev/null
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/Injectable.kt
@@ -0,0 +1,20 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package mx.trackermap.TrackerMap
+
+interface Injectable \ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/AttributesApi.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/AttributesApi.kt
index 2a67fd0..1da9831 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/AttributesApi.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/AttributesApi.kt
@@ -11,11 +11,12 @@
*/
package mx.trackermap.TrackerMap.client.apis
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.models.Attribute
import mx.trackermap.TrackerMap.client.infrastructure.*
-class AttributesApi(defaultBaseUrl: String) : ApiClient(defaultBaseUrl) {
+class AttributesApi(sessionManager: SessionManager) : ApiClient(sessionManager), Injectable {
/**
* Fetch a list of Attributes
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/CalendarsApi.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/CalendarsApi.kt
index 8dd2da8..c666dc3 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/CalendarsApi.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/CalendarsApi.kt
@@ -11,11 +11,12 @@
*/
package mx.trackermap.TrackerMap.client.apis
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.models.Calendar
import mx.trackermap.TrackerMap.client.infrastructure.*
-class CalendarsApi(defaultBaseUrl: String) : ApiClient(defaultBaseUrl) {
+class CalendarsApi(sessionManager: SessionManager) : ApiClient(sessionManager), Injectable {
/**
* Fetch a list of Calendars
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/CommandsApi.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/CommandsApi.kt
index 8ee7436..eb1718c 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/CommandsApi.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/CommandsApi.kt
@@ -11,12 +11,13 @@
*/
package mx.trackermap.TrackerMap.client.apis
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.models.Command
import mx.trackermap.TrackerMap.client.models.CommandType
import mx.trackermap.TrackerMap.client.infrastructure.*
-class CommandsApi(defaultBaseUrl: String) : ApiClient(defaultBaseUrl) {
+class CommandsApi(sessionManager: SessionManager) : ApiClient(sessionManager), Injectable {
/**
* Fetch a list of Saved Commands
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/DevicesApi.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/DevicesApi.kt
index 74d105f..8b839aa 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/DevicesApi.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/DevicesApi.kt
@@ -11,12 +11,13 @@
*/
package mx.trackermap.TrackerMap.client.apis
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.models.Device
import mx.trackermap.TrackerMap.client.models.DeviceAccumulators
import mx.trackermap.TrackerMap.client.infrastructure.*
-class DevicesApi(defaultBaseUrl: String) : ApiClient(defaultBaseUrl) {
+class DevicesApi(sessionManager: SessionManager) : ApiClient(sessionManager), Injectable {
/**
* Fetch a list of Devices
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/DriversApi.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/DriversApi.kt
index a9f47b8..bff61c2 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/DriversApi.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/DriversApi.kt
@@ -11,11 +11,12 @@
*/
package mx.trackermap.TrackerMap.client.apis
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.models.Driver
import mx.trackermap.TrackerMap.client.infrastructure.*
-class DriversApi(defaultBaseUrl: String) : ApiClient(defaultBaseUrl) {
+class DriversApi(sessionManager: SessionManager) : ApiClient(sessionManager), Injectable {
/**
* Fetch a list of Drivers
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/EventsApi.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/EventsApi.kt
index 360d6e1..87f8dce 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/EventsApi.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/EventsApi.kt
@@ -11,11 +11,12 @@
*/
package mx.trackermap.TrackerMap.client.apis
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.models.Event
import mx.trackermap.TrackerMap.client.infrastructure.*
-class EventsApi(defaultBaseUrl: String) : ApiClient(defaultBaseUrl) {
+class EventsApi(sessionManager: SessionManager) : ApiClient(sessionManager), Injectable {
/**
*
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/GeofencesApi.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/GeofencesApi.kt
index d7174e5..049aee9 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/GeofencesApi.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/GeofencesApi.kt
@@ -11,11 +11,12 @@
*/
package mx.trackermap.TrackerMap.client.apis
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.models.Geofence
import mx.trackermap.TrackerMap.client.infrastructure.*
-class GeofencesApi(defaultBaseUrl: String) : ApiClient(defaultBaseUrl) {
+class GeofencesApi(sessionManager: SessionManager) : ApiClient(sessionManager), Injectable {
/**
* Fetch a list of Geofences
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/GroupsApi.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/GroupsApi.kt
index 620a25e..07b3b05 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/GroupsApi.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/GroupsApi.kt
@@ -11,11 +11,12 @@
*/
package mx.trackermap.TrackerMap.client.apis
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.models.Group
import mx.trackermap.TrackerMap.client.infrastructure.*
-class GroupsApi(defaultBaseUrl: String) : ApiClient(defaultBaseUrl) {
+class GroupsApi(sessionManager: SessionManager) : ApiClient(sessionManager), Injectable {
/**
* Fetch a list of Groups
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/MaintenanceApi.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/MaintenanceApi.kt
index 5b10e9e..e28a728 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/MaintenanceApi.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/MaintenanceApi.kt
@@ -11,11 +11,12 @@
*/
package mx.trackermap.TrackerMap.client.apis
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.models.Maintenance
import mx.trackermap.TrackerMap.client.infrastructure.*
-class MaintenanceApi(defaultBaseUrl: String) : ApiClient(defaultBaseUrl) {
+class MaintenanceApi(sessionManager: SessionManager) : ApiClient(sessionManager), Injectable {
/**
* Fetch a list of Maintenance
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/NotificationsApi.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/NotificationsApi.kt
index 290a14d..f311fdb 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/NotificationsApi.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/NotificationsApi.kt
@@ -11,12 +11,13 @@
*/
package mx.trackermap.TrackerMap.client.apis
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.models.Notification
import mx.trackermap.TrackerMap.client.models.NotificationType
import mx.trackermap.TrackerMap.client.infrastructure.*
-class NotificationsApi(defaultBaseUrl: String) : ApiClient(defaultBaseUrl) {
+class NotificationsApi(sessionManager: SessionManager) : ApiClient(sessionManager), Injectable {
/**
* Fetch a list of Notifications
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/PermissionsApi.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/PermissionsApi.kt
index 33aab48..76fd4a8 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/PermissionsApi.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/PermissionsApi.kt
@@ -11,11 +11,12 @@
*/
package mx.trackermap.TrackerMap.client.apis
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.models.Permission
import mx.trackermap.TrackerMap.client.infrastructure.*
-class PermissionsApi(defaultBaseUrl: String) : ApiClient(defaultBaseUrl) {
+class PermissionsApi(sessionManager: SessionManager) : ApiClient(sessionManager), Injectable {
/**
* Unlink an Object from another Object
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/PositionsApi.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/PositionsApi.kt
index 61285e9..6ad74cb 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/PositionsApi.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/PositionsApi.kt
@@ -11,11 +11,12 @@
*/
package mx.trackermap.TrackerMap.client.apis
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.models.Position
import mx.trackermap.TrackerMap.client.infrastructure.*
-class PositionsApi(defaultBaseUrl: String) : ApiClient(defaultBaseUrl) {
+class PositionsApi(sessionManager: SessionManager) : ApiClient(sessionManager), Injectable {
/**
* Fetches a list of Positions
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/ReportsApi.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/ReportsApi.kt
index eff40ad..64ef8ea 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/ReportsApi.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/ReportsApi.kt
@@ -13,6 +13,7 @@ package mx.trackermap.TrackerMap.client.apis
import io.ktor.content.*
import kotlinx.datetime.LocalDateTime
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.models.Event
import mx.trackermap.TrackerMap.client.models.Position
import mx.trackermap.TrackerMap.client.models.Stop
@@ -21,7 +22,7 @@ import mx.trackermap.TrackerMap.client.models.ReportTrips
import mx.trackermap.TrackerMap.client.infrastructure.*
-class ReportsApi(defaultBaseUrl: String) : ApiClient(defaultBaseUrl) {
+class ReportsApi(sessionManager: SessionManager) : ApiClient(sessionManager), Injectable {
/**
* Fetch a list of Events within the time period for the Devices or Groups
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/ServerApi.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/ServerApi.kt
index bf65dfe..5672543 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/ServerApi.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/ServerApi.kt
@@ -11,11 +11,12 @@
*/
package mx.trackermap.TrackerMap.client.apis
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.models.Server
import mx.trackermap.TrackerMap.client.infrastructure.*
-class ServerApi(defaultBaseUrl: String) : ApiClient(defaultBaseUrl) {
+class ServerApi(sessionManager: SessionManager) : ApiClient(sessionManager), Injectable {
/**
* Fetch Server information
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/SessionApi.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/SessionApi.kt
index 3f90c4c..a22d2d9 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/SessionApi.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/SessionApi.kt
@@ -11,14 +11,11 @@
*/
package mx.trackermap.TrackerMap.client.apis
-import com.russhwolf.settings.Settings
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.models.User
import mx.trackermap.TrackerMap.client.infrastructure.*
-const val SERVER_URL_KEY = "server_url"
-const val ACCESS_TOKEN_KEY = "access_token"
-
-class SessionApi(defaultBaseUrl: String) : ApiClient(defaultBaseUrl) {
+class SessionApi(sessionManager: SessionManager) : ApiClient(sessionManager), Injectable {
/**
* Close the Session
@@ -36,8 +33,7 @@ class SessionApi(defaultBaseUrl: String) : ApiClient(defaultBaseUrl) {
return when (response.responseType) {
ResponseType.Success -> {
- val settings = Settings()
- settings.remove(ACCESS_TOKEN_KEY)
+ sessionManager.clearSession()
}
ResponseType.Informational -> TODO()
ResponseType.Redirection -> TODO()
@@ -102,14 +98,13 @@ class SessionApi(defaultBaseUrl: String) : ApiClient(defaultBaseUrl) {
return when (response.responseType) {
ResponseType.Success -> {
+ print("Response headers = ${response.headers.values}\n")
val cookie = response.headers
.values
.flatten()
.find { it.contains("JSESSIONID") }!!
.replace("; Path=/", "")
- this.token = cookie
- val settings = Settings()
- settings.putString(ACCESS_TOKEN_KEY, cookie)
+ this.sessionManager.token = cookie
(response as Success<*>).data as User
}
ResponseType.Informational -> TODO()
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/StatisticsApi.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/StatisticsApi.kt
index 296e589..0b9c766 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/StatisticsApi.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/StatisticsApi.kt
@@ -12,11 +12,12 @@
package mx.trackermap.TrackerMap.client.apis
import kotlinx.datetime.LocalDateTime
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.models.Statistics
import mx.trackermap.TrackerMap.client.infrastructure.*
-class StatisticsApi(defaultBaseUrl: String) : ApiClient(defaultBaseUrl) {
+class StatisticsApi(sessionManager: SessionManager) : ApiClient(sessionManager), Injectable {
/**
* Fetch server Statistics
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/UsersApi.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/UsersApi.kt
index 51f2138..90dd9f6 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/UsersApi.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/UsersApi.kt
@@ -11,11 +11,12 @@
*/
package mx.trackermap.TrackerMap.client.apis
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.models.User
import mx.trackermap.TrackerMap.client.infrastructure.*
-class UsersApi(defaultBaseUrl: String) : ApiClient(defaultBaseUrl) {
+class UsersApi(sessionManager: SessionManager) : ApiClient(sessionManager), Injectable {
/**
* Fetch a list of Users
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/ApiClient.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/ApiClient.kt
index dd61893..e9865e8 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/ApiClient.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/ApiClient.kt
@@ -17,7 +17,6 @@
*/
package mx.trackermap.TrackerMap.client.infrastructure
-import com.russhwolf.settings.Settings
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.features.*
@@ -32,12 +31,10 @@ import io.ktor.client.request.forms.FormDataContent
import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.util.*
-import mx.trackermap.TrackerMap.client.apis.ACCESS_TOKEN_KEY
-import mx.trackermap.TrackerMap.client.apis.SERVER_URL_KEY
import kotlinx.serialization.json.Json as KotlinJson
open class ApiClient(
- defaultBaseUrl: String = "",
+ val sessionManager: SessionManager
) {
companion object {
protected const val ApiContentType = "Content-Type"
@@ -47,7 +44,7 @@ open class ApiClient(
protected const val ApiFormURLType = "application/x-www-form-urlencoded"
protected const val ApiXmlMediaType = "application/xml"
- val client: HttpClient = HttpClient {
+ val client: HttpClient = HttpClientProvider().getHttpClient().config {
install(HttpTimeout) {
connectTimeoutMillis = 20_000
requestTimeoutMillis = 20_000
@@ -56,12 +53,13 @@ open class ApiClient(
serializer = KotlinxSerializer(
KotlinJson {
ignoreUnknownKeys = true
+ useAlternativeNames = false
}
)
}
install(Logging) {
logger = Logger.DEFAULT
- level = LogLevel.ALL
+ level = LogLevel.INFO
}
}
@@ -70,21 +68,6 @@ open class ApiClient(
ApiContentType to ApiJsonMediaType,
ApiAccept to ApiJsonMediaType
)
-
- val jsonHeaders: Map<String, String> =
- mapOf(
- ApiContentType to ApiJsonMediaType,
- ApiAccept to ApiJsonMediaType
- )
- }
-
- var baseUrl: String = ""
- var token: String = ""
-
- init {
- val settings = Settings()
- baseUrl = settings.getString(SERVER_URL_KEY, defaultBaseUrl)
- token = settings.getString(ACCESS_TOKEN_KEY, "")
}
protected inline fun <reified T> fillRequest(
@@ -130,7 +113,7 @@ open class ApiClient(
): ApiInfrastructureResponse<T?> {
val httpUrl: Url
try {
- httpUrl = Url(baseUrl)
+ httpUrl = Url(sessionManager.baseUrl)
} catch (e: URLDecodeException) {
throw IllegalStateException("baseUrl is invalid.")
}
@@ -147,11 +130,11 @@ open class ApiClient(
val url = urlBuilder.build()
val headers = defaultHeaders + requestConfig.headers
- if (headers[ApiContentType] ?: "" == "") {
+ if ((headers[ApiContentType] ?: "") == "") {
throw IllegalStateException("Missing Content-Type header. This is required.")
}
- if (headers[ApiAccept] ?: "" == "") {
+ if ((headers[ApiAccept] ?: "") == "") {
throw IllegalStateException("Missing Accept header. This is required.")
}
@@ -190,8 +173,8 @@ open class ApiClient(
}
}
- if (token.isNotEmpty()) {
- request.headers["Cookie"] = token
+ if (sessionManager.token.isNotEmpty()) {
+ request.headers["Cookie"] = sessionManager.token
}
val response: HttpResponse = client.request(request)
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/HttpClientProvider.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/HttpClientProvider.kt
new file mode 100644
index 0000000..873722f
--- /dev/null
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/HttpClientProvider.kt
@@ -0,0 +1,7 @@
+package mx.trackermap.TrackerMap.client.infrastructure
+
+import io.ktor.client.*
+
+expect class HttpClientProvider() {
+ fun getHttpClient(): HttpClient
+} \ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/SessionManager.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/SessionManager.kt
new file mode 100644
index 0000000..caf2da1
--- /dev/null
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/SessionManager.kt
@@ -0,0 +1,35 @@
+package mx.trackermap.TrackerMap.client.infrastructure
+
+import com.russhwolf.settings.Settings
+import com.russhwolf.settings.get
+import com.russhwolf.settings.set
+import mx.trackermap.TrackerMap.Injectable
+
+class SessionManager(
+ private val defaultBaseUrl: String
+): Injectable {
+
+ companion object {
+ const val SERVER_URL_KEY = "server_url"
+ const val ACCESS_TOKEN_KEY = "access_token"
+ }
+
+ private val settings = Settings()
+
+ var baseUrl: String
+ get() = settings[SERVER_URL_KEY] ?: defaultBaseUrl
+ set(baseUrl) {
+ settings[SERVER_URL_KEY] = baseUrl
+ }
+
+ var token: String
+ get() = settings[ACCESS_TOKEN_KEY] ?: ""
+ set(token) {
+ settings[ACCESS_TOKEN_KEY] = token
+ }
+
+ fun clearSession() {
+ settings.remove(ACCESS_TOKEN_KEY)
+ settings.remove(SERVER_URL_KEY)
+ }
+} \ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/EventInformation.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/EventInformation.kt
index a008fa8..17682b8 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/EventInformation.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/EventInformation.kt
@@ -1,3 +1,20 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
package mx.trackermap.TrackerMap.client.models
import kotlinx.serialization.Serializable
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/MapLayer.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/MapLayer.kt
index 4a48952..7bb41ae 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/MapLayer.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/MapLayer.kt
@@ -1,3 +1,20 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
package mx.trackermap.TrackerMap.client.models
data class MapLayer(
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/Marker.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/Marker.kt
new file mode 100644
index 0000000..ff3fb29
--- /dev/null
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/Marker.kt
@@ -0,0 +1,102 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package mx.trackermap.TrackerMap.client.models
+
+
+data class Marker(
+ val id: Int,
+ val name: String,
+ val latitude: Double,
+ val longitude: Double,
+ val type: Type = Type.DEFAULT
+) {
+ enum class Type {
+ ANIMAL, BICYCLE, BOAT, BUS, CAR, CRANE, DEFAULT, HELICOPTER, MOTORCYCLE, OFFROAD, PERSON,
+ PICKUP, PLANE, SCOOTER, SHIP, TRACTOR, TRAIN, TRAM, TROLLEYBUS, TRUCK, VAN,
+
+ REPORT_POSITION, REPORT_START, REPORT_END
+ }
+
+ companion object {
+ fun fromUnit(unit: UnitInformation): Marker? {
+ if (unit.position?.latitude == null || unit.position.longitude == null) {
+ return null
+ }
+
+ return Marker(
+ unit.position.id!!,
+ unit.device.name,
+ unit.position.latitude,
+ unit.position.longitude,
+ categoryToMarkerType(unit.device.category ?: "")
+ )
+ }
+
+ fun fromPosition(position: Position): Marker? {
+ if (position.latitude == null || position.longitude == null) {
+ return null
+ }
+
+ return Marker(
+ position.id!!,
+ "",
+ position.latitude,
+ position.longitude
+ )
+ }
+
+ fun fromStop(stop: Stop): Marker? {
+ if (stop.latitude == null || stop.longitude == null) {
+ return null
+ }
+
+ return Marker(
+ stop.deviceId!!,
+ stop.deviceName!!,
+ stop.latitude,
+ stop.longitude
+ )
+ }
+
+ fun categoryToMarkerType(category: String?): Type {
+ return when (category?.lowercase()) {
+ "animal" -> Type.ANIMAL
+ "bicycle" -> Type.BICYCLE
+ "boat" -> Type.BOAT
+ "bus" -> Type.BUS
+ "car" -> Type.CAR
+ "crane" -> Type.CRANE
+ "helicopter" -> Type.HELICOPTER
+ "motorcycle" -> Type.MOTORCYCLE
+ "offroad" -> Type.OFFROAD
+ "person" -> Type.PERSON
+ "pickup" -> Type.PICKUP
+ "plane" -> Type.PLANE
+ "scooter" -> Type.SCOOTER
+ "ship" -> Type.SHIP
+ "tractor" -> Type.TRACTOR
+ "train" -> Type.TRAIN
+ "tram" -> Type.TRAM
+ "trolleybus" -> Type.TROLLEYBUS
+ "truck" -> Type.TRUCK
+ "van" -> Type.VAN
+ else -> Type.DEFAULT
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/UnitInformation.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/UnitInformation.kt
index edebff0..1e23396 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/UnitInformation.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/UnitInformation.kt
@@ -1,6 +1,58 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
package mx.trackermap.TrackerMap.client.models
+import kotlinx.serialization.json.longOrNull
+
data class UnitInformation(
val device: Device,
val position: Position?
-) \ No newline at end of file
+) {
+ enum class Status {
+ ONLINE, OFFLINE, UNKNOWN
+ }
+
+ enum class EngineStop {
+ ON, OFF, UNKNOWN
+ }
+
+ /**
+ * Status is calculated from speed, because status based on
+ * the actual connection to the server is useless for our clients.
+ */
+ fun getStatus() = position?.speed?.let {
+ if (it >= 2) {
+ Status.ONLINE
+ } else {
+ Status.OFFLINE
+ }
+ } ?: Status.UNKNOWN
+
+ /* Many GPS devices reserve pin 1 for engine stop */
+ fun getEngineStop() = if (position?.attributes?.containsKey("out1") == true) {
+ position.attributes["out1"]?.toString()?.let {
+ when (it) {
+ "true" -> EngineStop.ON
+ "false" -> EngineStop.OFF
+ else -> EngineStop.UNKNOWN
+ }
+ } ?: EngineStop.UNKNOWN
+ } else EngineStop.UNKNOWN
+
+ fun getHourmeter() = position?.attributes?.get("hours")?.longOrNull
+} \ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/CommandsController.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/CommandsController.kt
new file mode 100644
index 0000000..03ba5ab
--- /dev/null
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/CommandsController.kt
@@ -0,0 +1,17 @@
+package mx.trackermap.TrackerMap.controllers
+
+import mx.trackermap.TrackerMap.Injectable
+import mx.trackermap.TrackerMap.client.apis.CommandsApi
+import mx.trackermap.TrackerMap.client.models.Command
+
+class CommandsController(
+ private val commandsApi: CommandsApi
+): Injectable {
+ suspend fun fetchCommands(deviceId: Int): List<Command> {
+ return commandsApi.commandsGet(deviceId = deviceId).toList()
+ }
+
+ suspend fun sendCommand(command: Command) {
+ commandsApi.commandsSendPost(command)
+ }
+} \ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/GeofencesController.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/GeofencesController.kt
index 0e4c5c9..e16bb72 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/GeofencesController.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/GeofencesController.kt
@@ -21,13 +21,14 @@ import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.apis.GeofencesApi
import mx.trackermap.TrackerMap.client.models.Geofence
@DelicateCoroutinesApi
class GeofencesController(
private val geofencesApi: GeofencesApi
-) {
+): Injectable {
val geofencesFlow = MutableStateFlow<Map<Int,Geofence>>(emptyMap())
init {
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/ReportController.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/ReportController.kt
index b60a034..b2e97e6 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/ReportController.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/ReportController.kt
@@ -21,6 +21,7 @@ import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.apis.GeofencesApi
import mx.trackermap.TrackerMap.client.apis.ReportsApi
import mx.trackermap.TrackerMap.client.models.EventInformation
@@ -32,12 +33,12 @@ import mx.trackermap.TrackerMap.utils.ReportDates
class ReportController(
private val reportsApi: ReportsApi,
private val geofencesApi: GeofencesApi
-) {
+): Injectable {
sealed class Report {
- class PositionsReport(val positions: Array<Position>) : Report()
- class EventsReport(val events: Array<EventInformation>) : Report()
- class StopsReport(val stops: Array<Stop>) : Report()
+ class PositionsReport(val positions: List<Position>) : Report()
+ class EventsReport(val events: List<EventInformation>) : Report()
+ class StopsReport(val stops: List<Stop>) : Report()
class XlsxReport(val data: ByteArray) : Report()
object LoadingReport: Report()
}
@@ -81,7 +82,7 @@ class ReportController(
) {
if (!xlsx) {
val result = reportsApi.reportsRouteGet(from, to, deviceId)
- reportFlow.value = Report.PositionsReport(result)
+ reportFlow.value = Report.PositionsReport(result.toList())
} else {
val result = reportsApi.reportsRouteGetXlsx(from, to, deviceId)
reportFlow.value = Report.XlsxReport(result)
@@ -113,7 +114,7 @@ class ReportController(
))
}
- reportFlow.value = Report.EventsReport(result.toTypedArray())
+ reportFlow.value = Report.EventsReport(result)
} else {
val result = reportsApi.reportsEventsGetXlsx(
from, to, EventInformation.reportTypesToStrings(types), deviceId
@@ -131,7 +132,7 @@ class ReportController(
) {
if (!xlsx) {
val result = reportsApi.reportsStopsGet(from, to, deviceId)
- reportFlow.value = Report.StopsReport(result)
+ reportFlow.value = Report.StopsReport(result.toList())
} else {
val result = reportsApi.reportsStopsGetXlsx(from, to, deviceId)
reportFlow.value = Report.XlsxReport(result)
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/SessionController.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/SessionController.kt
index a945ee9..d3deca1 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/SessionController.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/SessionController.kt
@@ -22,6 +22,7 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import kotlinx.serialization.json.JsonPrimitive
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.apis.SessionApi
import mx.trackermap.TrackerMap.client.apis.UsersApi
import mx.trackermap.TrackerMap.client.models.SessionBody
@@ -31,7 +32,7 @@ import mx.trackermap.TrackerMap.client.models.User
class SessionController(
private val sessionApi: SessionApi,
private val usersApi: UsersApi
-) {
+): Injectable {
sealed class LoginState {
object Nothing: LoginState()
object Loading: LoginState()
@@ -65,6 +66,7 @@ class SessionController(
userFlow.value = sessionApi.sessionGet()
loginStateFlow.value = LoginState.Success
} catch (e: Exception) {
+ e.printStackTrace()
loginStateFlow.value = LoginState.Nothing
}
}
@@ -94,14 +96,13 @@ class SessionController(
loginStateFlow.value = LoginState.Loading
GlobalScope.launch {
try {
- sessionApi.baseUrl = url
- usersApi.baseUrl = sessionApi.baseUrl
+ sessionApi.sessionManager.baseUrl = url
val session = sessionApi.sessionPost(email, password)
userFlow.value = session
- usersApi.token = sessionApi.token
token?.let { registerFcmToken(it) }
loginStateFlow.value = LoginState.Success
} catch (e: Exception) {
+ e.printStackTrace()
loginStateFlow.value = LoginState.Failure
}
}
diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/UnitsController.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/UnitsController.kt
index a5d5bd7..8c36d50 100644
--- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/UnitsController.kt
+++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/UnitsController.kt
@@ -25,6 +25,7 @@ import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
+import mx.trackermap.TrackerMap.Injectable
import mx.trackermap.TrackerMap.client.apis.DevicesApi
import mx.trackermap.TrackerMap.client.apis.PositionsApi
import mx.trackermap.TrackerMap.client.models.Position
@@ -39,7 +40,7 @@ import kotlinx.coroutines.Job
class UnitsController(
private val devicesApi: DevicesApi,
private val positionsApi: PositionsApi
-) {
+): Injectable {
private companion object {
const val UPDATE_TIME = 20
}
diff --git a/shared/src/iosMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/HttpClientProvider.kt b/shared/src/iosMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/HttpClientProvider.kt
new file mode 100644
index 0000000..e95e964
--- /dev/null
+++ b/shared/src/iosMain/kotlin/mx/trackermap/TrackerMap/client/infrastructure/HttpClientProvider.kt
@@ -0,0 +1,33 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package mx.trackermap.TrackerMap.client.infrastructure
+
+import io.ktor.client.*
+import io.ktor.client.engine.ios.*
+
+actual class HttpClientProvider {
+ actual fun getHttpClient(): HttpClient {
+ return HttpClient(Ios) {
+ engine {
+ configureSession {
+ HTTPCookieStorage = null
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/shared/src/iosMain/kotlin/mx/trackermap/TrackerMap/utils/MainScope.kt b/shared/src/iosMain/kotlin/mx/trackermap/TrackerMap/utils/MainScope.kt
new file mode 100644
index 0000000..b992524
--- /dev/null
+++ b/shared/src/iosMain/kotlin/mx/trackermap/TrackerMap/utils/MainScope.kt
@@ -0,0 +1,34 @@
+/**
+ * TrackerMap
+ * Copyright (C) 2021-2022 Iván Ávalos <avalos@disroot.org>, Henoch Ojeda <imhenoch@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package mx.trackermap.TrackerMap.utils
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
+
+class MainScope {
+ companion object {
+ fun createMainScope(): CoroutineScope {
+ return MainScope()
+ }
+
+ fun cancelScope(scope: CoroutineScope) {
+ scope.cancel()
+ }
+ }
+} \ No newline at end of file