├── .gitignore ├── GeoJSONMap.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── GeoJSONMap.xcscheme ├── GeoJSONMap ├── GJError.swift ├── GJGeometry+MapKit.swift ├── GJMap.swift ├── GeoJSON.swift ├── GeoJSONMap.h ├── Info.plist ├── MKMapPoint+CGPoint.swift ├── MKMapRect+GeoJSON.swift └── MKMapSize+CGSize.swift ├── LICENSE ├── Package.swift ├── README.md └── amstertram.jpeg /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | # Package.resolved 41 | .build/ 42 | 43 | # CocoaPods 44 | # 45 | # We recommend against adding the Pods directory to your .gitignore. However 46 | # you should judge for yourself, the pros and cons are mentioned at: 47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 48 | # 49 | # Pods/ 50 | 51 | # Carthage 52 | # 53 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 54 | # Carthage/Checkouts 55 | 56 | Carthage/Build 57 | 58 | # fastlane 59 | # 60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 61 | # screenshots whenever they are needed. 62 | # For more information about the recommended setup visit: 63 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 64 | 65 | fastlane/report.xml 66 | fastlane/Preview.html 67 | fastlane/screenshots/**/*.png 68 | fastlane/test_output 69 | *.xcworkspacedata 70 | -------------------------------------------------------------------------------- /GeoJSONMap.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 948E925F219CA8A000D0C0D5 /* GeoJSONMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 948E9251219CA8A000D0C0D5 /* GeoJSONMap.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 948E926C219CAA2A00D0C0D5 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 948E926B219CAA2A00D0C0D5 /* MapKit.framework */; }; 12 | 948E926E219CAA3300D0C0D5 /* SpriteKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 948E926D219CAA3300D0C0D5 /* SpriteKit.framework */; }; 13 | 948E9272219CAD5E00D0C0D5 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 948E9271219CAD5E00D0C0D5 /* CoreLocation.framework */; }; 14 | 948E927A219CAEA700D0C0D5 /* MKMapRect+GeoJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948E9273219CAEA200D0C0D5 /* MKMapRect+GeoJSON.swift */; }; 15 | 948E927B219CAEA700D0C0D5 /* GeoJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948E9274219CAEA300D0C0D5 /* GeoJSON.swift */; }; 16 | 948E927C219CAEA700D0C0D5 /* GJGeometry+MapKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948E9275219CAEA400D0C0D5 /* GJGeometry+MapKit.swift */; }; 17 | 948E927D219CAEA700D0C0D5 /* GJError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948E9276219CAEA500D0C0D5 /* GJError.swift */; }; 18 | 948E927E219CAEA700D0C0D5 /* MKMapSize+CGSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948E9277219CAEA500D0C0D5 /* MKMapSize+CGSize.swift */; }; 19 | 948E927F219CAEA700D0C0D5 /* GJMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948E9278219CAEA600D0C0D5 /* GJMap.swift */; }; 20 | 948E9280219CAEA700D0C0D5 /* MKMapPoint+CGPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948E9279219CAEA700D0C0D5 /* MKMapPoint+CGPoint.swift */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXFileReference section */ 24 | 948E924E219CA8A000D0C0D5 /* GeoJSONMap.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = GeoJSONMap.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 25 | 948E9251219CA8A000D0C0D5 /* GeoJSONMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeoJSONMap.h; sourceTree = ""; }; 26 | 948E9252219CA8A000D0C0D5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 27 | 948E9268219CA8D800D0C0D5 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; 28 | 948E9269219CA8D800D0C0D5 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 29 | 948E926B219CAA2A00D0C0D5 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; }; 30 | 948E926D219CAA3300D0C0D5 /* SpriteKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SpriteKit.framework; path = System/Library/Frameworks/SpriteKit.framework; sourceTree = SDKROOT; }; 31 | 948E9271219CAD5E00D0C0D5 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; }; 32 | 948E9273219CAEA200D0C0D5 /* MKMapRect+GeoJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MKMapRect+GeoJSON.swift"; sourceTree = ""; }; 33 | 948E9274219CAEA300D0C0D5 /* GeoJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeoJSON.swift; sourceTree = ""; }; 34 | 948E9275219CAEA400D0C0D5 /* GJGeometry+MapKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "GJGeometry+MapKit.swift"; sourceTree = ""; }; 35 | 948E9276219CAEA500D0C0D5 /* GJError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GJError.swift; sourceTree = ""; }; 36 | 948E9277219CAEA500D0C0D5 /* MKMapSize+CGSize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MKMapSize+CGSize.swift"; sourceTree = ""; }; 37 | 948E9278219CAEA600D0C0D5 /* GJMap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GJMap.swift; sourceTree = ""; }; 38 | 948E9279219CAEA700D0C0D5 /* MKMapPoint+CGPoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MKMapPoint+CGPoint.swift"; sourceTree = ""; }; 39 | /* End PBXFileReference section */ 40 | 41 | /* Begin PBXFrameworksBuildPhase section */ 42 | 948E924B219CA8A000D0C0D5 /* Frameworks */ = { 43 | isa = PBXFrameworksBuildPhase; 44 | buildActionMask = 2147483647; 45 | files = ( 46 | 948E9272219CAD5E00D0C0D5 /* CoreLocation.framework in Frameworks */, 47 | 948E926E219CAA3300D0C0D5 /* SpriteKit.framework in Frameworks */, 48 | 948E926C219CAA2A00D0C0D5 /* MapKit.framework in Frameworks */, 49 | ); 50 | runOnlyForDeploymentPostprocessing = 0; 51 | }; 52 | /* End PBXFrameworksBuildPhase section */ 53 | 54 | /* Begin PBXGroup section */ 55 | 948E9244219CA8A000D0C0D5 = { 56 | isa = PBXGroup; 57 | children = ( 58 | 948E9268219CA8D800D0C0D5 /* LICENSE */, 59 | 948E9269219CA8D800D0C0D5 /* README.md */, 60 | 948E9250219CA8A000D0C0D5 /* GeoJSONMap */, 61 | 948E924F219CA8A000D0C0D5 /* Products */, 62 | 948E926A219CAA2A00D0C0D5 /* Frameworks */, 63 | ); 64 | sourceTree = ""; 65 | }; 66 | 948E924F219CA8A000D0C0D5 /* Products */ = { 67 | isa = PBXGroup; 68 | children = ( 69 | 948E924E219CA8A000D0C0D5 /* GeoJSONMap.framework */, 70 | ); 71 | name = Products; 72 | sourceTree = ""; 73 | }; 74 | 948E9250219CA8A000D0C0D5 /* GeoJSONMap */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 948E9274219CAEA300D0C0D5 /* GeoJSON.swift */, 78 | 948E9278219CAEA600D0C0D5 /* GJMap.swift */, 79 | 948E9276219CAEA500D0C0D5 /* GJError.swift */, 80 | 948E9275219CAEA400D0C0D5 /* GJGeometry+MapKit.swift */, 81 | 948E9279219CAEA700D0C0D5 /* MKMapPoint+CGPoint.swift */, 82 | 948E9273219CAEA200D0C0D5 /* MKMapRect+GeoJSON.swift */, 83 | 948E9277219CAEA500D0C0D5 /* MKMapSize+CGSize.swift */, 84 | 948E9251219CA8A000D0C0D5 /* GeoJSONMap.h */, 85 | 948E9252219CA8A000D0C0D5 /* Info.plist */, 86 | ); 87 | path = GeoJSONMap; 88 | sourceTree = ""; 89 | }; 90 | 948E926A219CAA2A00D0C0D5 /* Frameworks */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 948E9271219CAD5E00D0C0D5 /* CoreLocation.framework */, 94 | 948E926D219CAA3300D0C0D5 /* SpriteKit.framework */, 95 | 948E926B219CAA2A00D0C0D5 /* MapKit.framework */, 96 | ); 97 | name = Frameworks; 98 | sourceTree = ""; 99 | }; 100 | /* End PBXGroup section */ 101 | 102 | /* Begin PBXHeadersBuildPhase section */ 103 | 948E9249219CA8A000D0C0D5 /* Headers */ = { 104 | isa = PBXHeadersBuildPhase; 105 | buildActionMask = 2147483647; 106 | files = ( 107 | 948E925F219CA8A000D0C0D5 /* GeoJSONMap.h in Headers */, 108 | ); 109 | runOnlyForDeploymentPostprocessing = 0; 110 | }; 111 | /* End PBXHeadersBuildPhase section */ 112 | 113 | /* Begin PBXNativeTarget section */ 114 | 948E924D219CA8A000D0C0D5 /* GeoJSONMap */ = { 115 | isa = PBXNativeTarget; 116 | buildConfigurationList = 948E9262219CA8A000D0C0D5 /* Build configuration list for PBXNativeTarget "GeoJSONMap" */; 117 | buildPhases = ( 118 | 948E9249219CA8A000D0C0D5 /* Headers */, 119 | 948E924A219CA8A000D0C0D5 /* Sources */, 120 | 948E924B219CA8A000D0C0D5 /* Frameworks */, 121 | 948E924C219CA8A000D0C0D5 /* Resources */, 122 | ); 123 | buildRules = ( 124 | ); 125 | dependencies = ( 126 | ); 127 | name = GeoJSONMap; 128 | productName = GeoJSONMap; 129 | productReference = 948E924E219CA8A000D0C0D5 /* GeoJSONMap.framework */; 130 | productType = "com.apple.product-type.framework"; 131 | }; 132 | /* End PBXNativeTarget section */ 133 | 134 | /* Begin PBXProject section */ 135 | 948E9245219CA8A000D0C0D5 /* Project object */ = { 136 | isa = PBXProject; 137 | attributes = { 138 | LastSwiftUpdateCheck = 1010; 139 | LastUpgradeCheck = 1010; 140 | ORGANIZATIONNAME = "Maxim Volgin"; 141 | TargetAttributes = { 142 | 948E924D219CA8A000D0C0D5 = { 143 | CreatedOnToolsVersion = 10.1; 144 | LastSwiftMigration = 1010; 145 | }; 146 | }; 147 | }; 148 | buildConfigurationList = 948E9248219CA8A000D0C0D5 /* Build configuration list for PBXProject "GeoJSONMap" */; 149 | compatibilityVersion = "Xcode 9.3"; 150 | developmentRegion = en; 151 | hasScannedForEncodings = 0; 152 | knownRegions = ( 153 | en, 154 | ); 155 | mainGroup = 948E9244219CA8A000D0C0D5; 156 | productRefGroup = 948E924F219CA8A000D0C0D5 /* Products */; 157 | projectDirPath = ""; 158 | projectRoot = ""; 159 | targets = ( 160 | 948E924D219CA8A000D0C0D5 /* GeoJSONMap */, 161 | ); 162 | }; 163 | /* End PBXProject section */ 164 | 165 | /* Begin PBXResourcesBuildPhase section */ 166 | 948E924C219CA8A000D0C0D5 /* Resources */ = { 167 | isa = PBXResourcesBuildPhase; 168 | buildActionMask = 2147483647; 169 | files = ( 170 | ); 171 | runOnlyForDeploymentPostprocessing = 0; 172 | }; 173 | /* End PBXResourcesBuildPhase section */ 174 | 175 | /* Begin PBXSourcesBuildPhase section */ 176 | 948E924A219CA8A000D0C0D5 /* Sources */ = { 177 | isa = PBXSourcesBuildPhase; 178 | buildActionMask = 2147483647; 179 | files = ( 180 | 948E9280219CAEA700D0C0D5 /* MKMapPoint+CGPoint.swift in Sources */, 181 | 948E927A219CAEA700D0C0D5 /* MKMapRect+GeoJSON.swift in Sources */, 182 | 948E927F219CAEA700D0C0D5 /* GJMap.swift in Sources */, 183 | 948E927B219CAEA700D0C0D5 /* GeoJSON.swift in Sources */, 184 | 948E927C219CAEA700D0C0D5 /* GJGeometry+MapKit.swift in Sources */, 185 | 948E927E219CAEA700D0C0D5 /* MKMapSize+CGSize.swift in Sources */, 186 | 948E927D219CAEA700D0C0D5 /* GJError.swift in Sources */, 187 | ); 188 | runOnlyForDeploymentPostprocessing = 0; 189 | }; 190 | /* End PBXSourcesBuildPhase section */ 191 | 192 | /* Begin XCBuildConfiguration section */ 193 | 948E9260219CA8A000D0C0D5 /* Debug */ = { 194 | isa = XCBuildConfiguration; 195 | buildSettings = { 196 | ALWAYS_SEARCH_USER_PATHS = NO; 197 | CLANG_ANALYZER_NONNULL = YES; 198 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 199 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 200 | CLANG_CXX_LIBRARY = "libc++"; 201 | CLANG_ENABLE_MODULES = YES; 202 | CLANG_ENABLE_OBJC_ARC = YES; 203 | CLANG_ENABLE_OBJC_WEAK = YES; 204 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 205 | CLANG_WARN_BOOL_CONVERSION = YES; 206 | CLANG_WARN_COMMA = YES; 207 | CLANG_WARN_CONSTANT_CONVERSION = YES; 208 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 209 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 210 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 211 | CLANG_WARN_EMPTY_BODY = YES; 212 | CLANG_WARN_ENUM_CONVERSION = YES; 213 | CLANG_WARN_INFINITE_RECURSION = YES; 214 | CLANG_WARN_INT_CONVERSION = YES; 215 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 216 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 217 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 218 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 219 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 220 | CLANG_WARN_STRICT_PROTOTYPES = YES; 221 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 222 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 223 | CLANG_WARN_UNREACHABLE_CODE = YES; 224 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 225 | CODE_SIGN_IDENTITY = "iPhone Developer"; 226 | COPY_PHASE_STRIP = NO; 227 | CURRENT_PROJECT_VERSION = 1; 228 | DEBUG_INFORMATION_FORMAT = dwarf; 229 | ENABLE_STRICT_OBJC_MSGSEND = YES; 230 | ENABLE_TESTABILITY = YES; 231 | GCC_C_LANGUAGE_STANDARD = gnu11; 232 | GCC_DYNAMIC_NO_PIC = NO; 233 | GCC_NO_COMMON_BLOCKS = YES; 234 | GCC_OPTIMIZATION_LEVEL = 0; 235 | GCC_PREPROCESSOR_DEFINITIONS = ( 236 | "DEBUG=1", 237 | "$(inherited)", 238 | ); 239 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 240 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 241 | GCC_WARN_UNDECLARED_SELECTOR = YES; 242 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 243 | GCC_WARN_UNUSED_FUNCTION = YES; 244 | GCC_WARN_UNUSED_VARIABLE = YES; 245 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 246 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 247 | MTL_FAST_MATH = YES; 248 | ONLY_ACTIVE_ARCH = YES; 249 | SDKROOT = iphoneos; 250 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 251 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 252 | VERSIONING_SYSTEM = "apple-generic"; 253 | VERSION_INFO_PREFIX = ""; 254 | }; 255 | name = Debug; 256 | }; 257 | 948E9261219CA8A000D0C0D5 /* Release */ = { 258 | isa = XCBuildConfiguration; 259 | buildSettings = { 260 | ALWAYS_SEARCH_USER_PATHS = NO; 261 | CLANG_ANALYZER_NONNULL = YES; 262 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 263 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 264 | CLANG_CXX_LIBRARY = "libc++"; 265 | CLANG_ENABLE_MODULES = YES; 266 | CLANG_ENABLE_OBJC_ARC = YES; 267 | CLANG_ENABLE_OBJC_WEAK = YES; 268 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 269 | CLANG_WARN_BOOL_CONVERSION = YES; 270 | CLANG_WARN_COMMA = YES; 271 | CLANG_WARN_CONSTANT_CONVERSION = YES; 272 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 273 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 274 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 275 | CLANG_WARN_EMPTY_BODY = YES; 276 | CLANG_WARN_ENUM_CONVERSION = YES; 277 | CLANG_WARN_INFINITE_RECURSION = YES; 278 | CLANG_WARN_INT_CONVERSION = YES; 279 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 280 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 281 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 282 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 283 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 284 | CLANG_WARN_STRICT_PROTOTYPES = YES; 285 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 286 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 287 | CLANG_WARN_UNREACHABLE_CODE = YES; 288 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 289 | CODE_SIGN_IDENTITY = "iPhone Developer"; 290 | COPY_PHASE_STRIP = NO; 291 | CURRENT_PROJECT_VERSION = 1; 292 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 293 | ENABLE_NS_ASSERTIONS = NO; 294 | ENABLE_STRICT_OBJC_MSGSEND = YES; 295 | GCC_C_LANGUAGE_STANDARD = gnu11; 296 | GCC_NO_COMMON_BLOCKS = YES; 297 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 298 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 299 | GCC_WARN_UNDECLARED_SELECTOR = YES; 300 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 301 | GCC_WARN_UNUSED_FUNCTION = YES; 302 | GCC_WARN_UNUSED_VARIABLE = YES; 303 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 304 | MTL_ENABLE_DEBUG_INFO = NO; 305 | MTL_FAST_MATH = YES; 306 | SDKROOT = iphoneos; 307 | SWIFT_COMPILATION_MODE = wholemodule; 308 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 309 | VALIDATE_PRODUCT = YES; 310 | VERSIONING_SYSTEM = "apple-generic"; 311 | VERSION_INFO_PREFIX = ""; 312 | }; 313 | name = Release; 314 | }; 315 | 948E9263219CA8A000D0C0D5 /* Debug */ = { 316 | isa = XCBuildConfiguration; 317 | buildSettings = { 318 | CLANG_ENABLE_MODULES = YES; 319 | CODE_SIGN_IDENTITY = ""; 320 | CODE_SIGN_STYLE = Automatic; 321 | DEFINES_MODULE = YES; 322 | DYLIB_COMPATIBILITY_VERSION = 1; 323 | DYLIB_CURRENT_VERSION = 1; 324 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 325 | INFOPLIST_FILE = GeoJSONMap/Info.plist; 326 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 327 | LD_RUNPATH_SEARCH_PATHS = ( 328 | "$(inherited)", 329 | "@executable_path/Frameworks", 330 | "@loader_path/Frameworks", 331 | ); 332 | PRODUCT_BUNDLE_IDENTIFIER = maxvol.GeoJSONMap; 333 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 334 | SKIP_INSTALL = YES; 335 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 336 | SWIFT_VERSION = 4.2; 337 | TARGETED_DEVICE_FAMILY = "1,2"; 338 | }; 339 | name = Debug; 340 | }; 341 | 948E9264219CA8A000D0C0D5 /* Release */ = { 342 | isa = XCBuildConfiguration; 343 | buildSettings = { 344 | CLANG_ENABLE_MODULES = YES; 345 | CODE_SIGN_IDENTITY = ""; 346 | CODE_SIGN_STYLE = Automatic; 347 | DEFINES_MODULE = YES; 348 | DYLIB_COMPATIBILITY_VERSION = 1; 349 | DYLIB_CURRENT_VERSION = 1; 350 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 351 | INFOPLIST_FILE = GeoJSONMap/Info.plist; 352 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 353 | LD_RUNPATH_SEARCH_PATHS = ( 354 | "$(inherited)", 355 | "@executable_path/Frameworks", 356 | "@loader_path/Frameworks", 357 | ); 358 | PRODUCT_BUNDLE_IDENTIFIER = maxvol.GeoJSONMap; 359 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 360 | SKIP_INSTALL = YES; 361 | SWIFT_VERSION = 4.2; 362 | TARGETED_DEVICE_FAMILY = "1,2"; 363 | }; 364 | name = Release; 365 | }; 366 | /* End XCBuildConfiguration section */ 367 | 368 | /* Begin XCConfigurationList section */ 369 | 948E9248219CA8A000D0C0D5 /* Build configuration list for PBXProject "GeoJSONMap" */ = { 370 | isa = XCConfigurationList; 371 | buildConfigurations = ( 372 | 948E9260219CA8A000D0C0D5 /* Debug */, 373 | 948E9261219CA8A000D0C0D5 /* Release */, 374 | ); 375 | defaultConfigurationIsVisible = 0; 376 | defaultConfigurationName = Release; 377 | }; 378 | 948E9262219CA8A000D0C0D5 /* Build configuration list for PBXNativeTarget "GeoJSONMap" */ = { 379 | isa = XCConfigurationList; 380 | buildConfigurations = ( 381 | 948E9263219CA8A000D0C0D5 /* Debug */, 382 | 948E9264219CA8A000D0C0D5 /* Release */, 383 | ); 384 | defaultConfigurationIsVisible = 0; 385 | defaultConfigurationName = Release; 386 | }; 387 | /* End XCConfigurationList section */ 388 | }; 389 | rootObject = 948E9245219CA8A000D0C0D5 /* Project object */; 390 | } 391 | -------------------------------------------------------------------------------- /GeoJSONMap.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /GeoJSONMap.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /GeoJSONMap.xcodeproj/xcshareddata/xcschemes/GeoJSONMap.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /GeoJSONMap/GJError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GJError.swift 3 | // GeoJSONMap 4 | // 5 | // Created by Maxim Volgin on 14/11/2018. 6 | // Copyright © 2018 Maxim Volgin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public enum GJError: Error { 12 | case element(String) 13 | case geometry(String) 14 | } 15 | -------------------------------------------------------------------------------- /GeoJSONMap/GJGeometry+MapKit.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GJGeometry+MapKit.swift 3 | // GeoJSONMap 4 | // 5 | // Created by Maxim Volgin on 11/11/2018. 6 | // Copyright © 2018 Maxim Volgin. All rights reserved. 7 | // 8 | 9 | import CoreLocation 10 | import SpriteKit 11 | import MapKit 12 | 13 | public extension GJGeometry { 14 | 15 | // public var coordinate: CLLocationCoordinate2D { 16 | // get { 17 | // switch self { 18 | // case .point(let coordinate): 19 | // return coordinate 20 | // case .lineString(let coordinates): 21 | // return coordinates.first! // TODO 22 | // } 23 | // } 24 | // } 25 | 26 | public var boundingMapRect: MKMapRect { 27 | get { 28 | return MKMapRect.boundingMapRect(for: self) 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /GeoJSONMap/GJMap.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GeoJSONMap.swift 3 | // GJMap 4 | // 5 | // Created by Maxim Volgin on 11/11/2018. 6 | // Copyright © 2018 Maxim Volgin. All rights reserved. 7 | // 8 | 9 | import CoreLocation 10 | import SpriteKit 11 | import MapKit 12 | 13 | // MARK: - map 14 | public class GJMap { 15 | // private 16 | private var _features: [GJFeature] = [] 17 | private var _mapRect: MKMapRect? = nil 18 | // public 19 | public init() {} 20 | public func add(featureCollection: GJFeatureCollection) { 21 | _features.append(contentsOf: featureCollection.features) 22 | _mapRect = nil 23 | } 24 | public func add(feature: GJFeature) { 25 | _features.append(feature) 26 | _mapRect = nil 27 | } 28 | public func remove(feature: GJFeature) { 29 | // TODO 30 | // _features.remove(feature) 31 | _mapRect = nil 32 | } 33 | public var features: [GJFeature] { 34 | get { 35 | return _features as Array> 36 | } 37 | } 38 | public var boundingMapRect: MKMapRect { 39 | get { 40 | if _mapRect == nil { 41 | _mapRect = MKMapRect.boundingMapRect(for: self.features) 42 | } 43 | return _mapRect! 44 | } 45 | } 46 | public var nodes: [SKNode] { 47 | get { 48 | return self.features.map { self.delegate?.map(self, nodeFor: $0) }.filter { $0 != nil }.map { $0! } 49 | } 50 | } 51 | public var delegate: D? 52 | } 53 | 54 | // MARK: - delegate 55 | public protocol GJMapDelegate { 56 | associatedtype P: Codable 57 | func map(_ map: GJMap, nodeFor feature: GJFeature

) -> SKNode? 58 | } 59 | -------------------------------------------------------------------------------- /GeoJSONMap/GeoJSON.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GeoJSON.swift 3 | // GeoJSONMap 4 | // 5 | // Created by Maxim Volgin on 26/04/2018. 6 | // Copyright © 2018 Maxim Volgin. All rights reserved. 7 | // 8 | 9 | import CoreLocation 10 | 11 | fileprivate enum GeoJSON: String { 12 | case Feature = "Feature" 13 | // TODO 14 | } 15 | 16 | public struct GJFeatureCollection: Codable { 17 | public let type: String 18 | public let features: [GJFeature

] 19 | } 20 | 21 | public struct GJFeature { 22 | public let id: Int? 23 | public let geometry: GJGeometry 24 | public let properties: P 25 | 26 | fileprivate enum CodingKeys: String, CodingKey { 27 | case id 28 | case type 29 | case geometry 30 | case properties 31 | } 32 | 33 | } 34 | 35 | extension GJFeature: Encodable { 36 | public func encode(to encoder: Encoder) throws { 37 | var container = encoder.container(keyedBy: CodingKeys.self) 38 | // try container.encode(name, forKey: .name) 39 | // TODO not implemented yet 40 | } 41 | } 42 | 43 | extension GJFeature: Decodable { 44 | public init(from decoder: Decoder) throws { 45 | let values = try decoder.container(keyedBy: CodingKeys.self) 46 | let type = try values.decode(String.self, forKey: .type) 47 | guard type == GeoJSON.Feature.rawValue else { 48 | throw GJError.element("Unexpected type: \(type)") 49 | } 50 | self.id = try? values.decode(Int.self, forKey: .id) 51 | self.geometry = try values.decode(GJGeometry.self, forKey: .geometry) 52 | self.properties = try values.decode(P.self, forKey: .properties) 53 | } 54 | } 55 | 56 | public enum GJGeometry { 57 | case point(CLLocationCoordinate2D) 58 | case lineString([CLLocationCoordinate2D]) 59 | case polygon([[CLLocationCoordinate2D]]) 60 | case multiPoint([CLLocationCoordinate2D]) 61 | case multiLineString([[CLLocationCoordinate2D]]) 62 | case multiPolygon([[[CLLocationCoordinate2D]]]) 63 | 64 | fileprivate enum CodingKeys: String, CodingKey { 65 | case type 66 | case coordinates 67 | } 68 | 69 | fileprivate enum Element: String { 70 | case Point = "Point" 71 | case LineString = "LineString" 72 | case Polygon = "Polygon" 73 | case MultiPoint = "MultiPoint" 74 | case MultiLineString = "MultiLineString" 75 | case MultiPolygon = "MultiPolygon" 76 | } 77 | } 78 | 79 | // TODO 80 | extension GJGeometry: Encodable { 81 | public func encode(to encoder: Encoder) throws { 82 | var container = encoder.container(keyedBy: CodingKeys.self) 83 | // try container.encode(name, forKey: .name) 84 | } 85 | } 86 | 87 | extension GJGeometry: Decodable { 88 | public init(from decoder: Decoder) throws { 89 | let values = try decoder.container(keyedBy: CodingKeys.self) 90 | let type = try values.decode(String.self, forKey: .type) 91 | switch type { 92 | case Element.Point.rawValue: 93 | let coordinates = try values.decode([CLLocationDegrees].self, forKey: .coordinates) 94 | let location = try GJGeometry.parse(coordinates: coordinates) 95 | self = .point(location) 96 | case Element.LineString.rawValue: 97 | let coordinates = try values.decode([[CLLocationDegrees]].self, forKey: .coordinates) 98 | self = try .lineString(coordinates.map { try GJGeometry.parse(coordinates: $0) }) 99 | case Element.Polygon.rawValue: 100 | let coordinates = try values.decode([[[CLLocationDegrees]]].self, forKey: .coordinates) 101 | self = try .polygon(coordinates.map { coordinates in 102 | return try coordinates.map { try GJGeometry.parse(coordinates: $0) } 103 | }) 104 | case Element.MultiPoint.rawValue: 105 | let coordinates = try values.decode([[CLLocationDegrees]].self, forKey: .coordinates) 106 | self = try .multiPoint(coordinates.map { try GJGeometry.parse(coordinates: $0) }) 107 | case Element.MultiLineString.rawValue: 108 | let coordinates = try values.decode([[[CLLocationDegrees]]].self, forKey: .coordinates) 109 | self = try .multiLineString(coordinates.map { coordinates in 110 | return try coordinates.map { try GJGeometry.parse(coordinates: $0) } 111 | }) 112 | case Element.MultiPolygon.rawValue: 113 | let coordinates = try values.decode([[[[CLLocationDegrees]]]].self, forKey: .coordinates) 114 | self = try .multiPolygon(coordinates.map { coordinates in 115 | try coordinates.map { coordinates in 116 | return try coordinates.map { try GJGeometry.parse(coordinates: $0) } 117 | } 118 | }) 119 | default: 120 | throw GJError.geometry("Unexpected type: \(type)") 121 | } 122 | } 123 | 124 | static func parse(coordinates: [CLLocationDegrees]) throws -> CLLocationCoordinate2D { 125 | guard coordinates.count == 2 else { 126 | throw GJError.geometry("coordinates count: \(coordinates.count)") 127 | } 128 | return CLLocationCoordinate2D(latitude: coordinates[1], longitude: coordinates[0]) 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /GeoJSONMap/GeoJSONMap.h: -------------------------------------------------------------------------------- 1 | // 2 | // GeoJSONMap.h 3 | // GeoJSONMap 4 | // 5 | // Created by Maxim Volgin on 14/11/2018. 6 | // Copyright © 2018 Maxim Volgin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for GeoJSONMap. 12 | FOUNDATION_EXPORT double GeoJSONMapVersionNumber; 13 | 14 | //! Project version string for GeoJSONMap. 15 | FOUNDATION_EXPORT const unsigned char GeoJSONMapVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /GeoJSONMap/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.1.2 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /GeoJSONMap/MKMapPoint+CGPoint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MKMapPoint+CGPoint.swift 3 | // GeoJSONMap 4 | // 5 | // Created by Maxim Volgin on 10/11/2018. 6 | // Copyright © 2018 Maxim Volgin. All rights reserved. 7 | // 8 | 9 | import CoreLocation 10 | import MapKit 11 | 12 | public extension MKMapPoint { 13 | 14 | public func normalized(in rect: MKMapRect) throws -> MKMapPoint { 15 | guard rect.contains(self) else { 16 | throw GJError.geometry("Point is not in rect!") 17 | } 18 | let normX = (self.x - rect.minX) / rect.width 19 | let normY = (self.y - rect.minY) / rect.height 20 | return MKMapPoint(x: normX, y: normY) 21 | } 22 | 23 | public func cgPoint(from rect: MKMapRect, to size: CGSize) throws -> CGPoint { 24 | let normalized = try self.normalized(in: rect) 25 | let newX = normalized.x * Double(size.width) 26 | let newY = Double(size.height) - normalized.y * Double(size.height) 27 | return CGPoint(x: newX, y: newY) 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /GeoJSONMap/MKMapRect+GeoJSON.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MKMapRect+GeoJSON.swift 3 | // GeoJSONMap 4 | // 5 | // Created by Maxim Volgin on 10/11/2018. 6 | // Copyright © 2018 Maxim Volgin. All rights reserved. 7 | // 8 | 9 | import CoreLocation 10 | import MapKit 11 | 12 | public extension MKMapRect { 13 | 14 | public static func boundingMapRect(for geometry: GJGeometry) -> MKMapRect { 15 | switch geometry { 16 | case .point(let coordinate): 17 | return boundingMapRect(for: [MKMapPoint(coordinate)]) 18 | case .lineString(let coordinates): 19 | return boundingMapRect(for: coordinates.map { MKMapPoint($0) }) 20 | case .polygon(let coordinates): 21 | return boundingMapRect(for: coordinates.flatMap { $0.map { MKMapPoint($0) } }) 22 | case .multiPoint(let coordinates): 23 | return boundingMapRect(for: coordinates.map { MKMapPoint($0) }) 24 | case .multiLineString(let coordinates): 25 | return boundingMapRect(for: coordinates.flatMap { $0.map { MKMapPoint($0) } }) 26 | case .multiPolygon(let coordinates): 27 | return boundingMapRect(for: coordinates.flatMap { $0.flatMap { $0.map { MKMapPoint($0) } } }) 28 | } 29 | } 30 | 31 | public static func boundingMapRect(for feature: GJFeature

) -> MKMapRect { 32 | return boundingMapRect(for: feature.geometry) 33 | } 34 | 35 | public static func boundingMapRect(for features: [GJFeature

]) -> MKMapRect { 36 | let geometry: [GJGeometry] = features.map { $0.geometry } 37 | let points: [[MKMapPoint]] = geometry.map { geometry in 38 | switch geometry { 39 | case .point(let coordinate): 40 | return [MKMapPoint(coordinate)] 41 | case .lineString(let coordinates): 42 | return coordinates.map { MKMapPoint($0) } 43 | case .polygon(let coordinates): 44 | return coordinates.flatMap { $0.map { MKMapPoint($0) } } 45 | case .multiPoint(let coordinates): 46 | return coordinates.map { MKMapPoint($0) } 47 | case .multiLineString(let coordinates): 48 | return coordinates.flatMap { $0.map { MKMapPoint($0) } } 49 | case .multiPolygon(let coordinates): 50 | return coordinates.flatMap { $0.flatMap { $0.map { MKMapPoint($0) } } } 51 | } 52 | } 53 | return boundingMapRect(for: points.flatMap { $0 }) 54 | } 55 | 56 | public static func boundingMapRect(for featureCollections: [GJFeatureCollection

]) -> MKMapRect { 57 | return boundingMapRect(for: featureCollections.flatMap { $0.features } ) 58 | } 59 | 60 | public static func boundingMapRect(for points: [MKMapPoint]) -> MKMapRect { 61 | let xs = points.map { $0.x } 62 | let ys = points.map { $0.y } 63 | let minX = xs.min()! 64 | let minY = ys.min()! 65 | let maxX = xs.max()! 66 | let maxY = ys.max()! 67 | let origin = MKMapPoint(x: minX, y: minY) 68 | let size = MKMapSize(width: maxX - minX, height: maxY - minY) 69 | let rect = MKMapRect(origin: origin, size: size) 70 | return rect 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /GeoJSONMap/MKMapSize+CGSize.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MKMapSize+CGSize.swift 3 | // GeoJSONMap 4 | // 5 | // Created by Maxim Volgin on 10/11/2018. 6 | // Copyright © 2018 Maxim Volgin. All rights reserved. 7 | // 8 | 9 | import CoreLocation 10 | import MapKit 11 | 12 | public extension MKMapSize { 13 | 14 | public var cgSize: CGSize { 15 | return CGSize(width: self.width * 0.5, height: self.height) 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Maxim Volgin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "GeoJSONMap", 7 | platforms: [ 8 | .macOS(.v10_10), .iOS(.v8), .tvOS(.v9), .watchOS(.v3) 9 | ], 10 | products: [ 11 | .library( 12 | name: "GeoJSONMap", 13 | targets: ["GeoJSONMap"]), 14 | ], 15 | dependencies: [ 16 | ], 17 | targets: [ 18 | .target( 19 | name: "GeoJSONMap", 20 | dependencies: [], 21 | path: "."), 22 | // .testTarget( 23 | // name: "GeoJSONMapTests", 24 | // dependencies: ["GeoJSONMap"], 25 | // path: "Tests" 26 | // ) 27 | ] 28 | ) 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GeoJSONMap 2 | Build maps from GeoJSON with MapKit or SpriteKit. 3 | 4 | SpriteKit maps can be displayed offline and/or as planes in ARKit. 5 | 6 | ![alt Amstertram](https://github.com/maxvol/GeoJSONMap/blob/master/amstertram.jpeg?raw=true) 7 | 8 | Basic usage: 9 | 10 | ```swift 11 | import GeoJSONMap 12 | 13 | final class ViewController: UIViewController { 14 | let map = GJMap() 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | 19 | self.map.delegate = self 20 | self.map.add(featureCollection: /* ... */) 21 | 22 | let mapRect = self.map.boundingMapRect 23 | let cgSize = mapRect.size.cgSize 24 | let scene = SKScene(size: cgSize) 25 | for node in self.map.nodes { 26 | scene.addChild(node) 27 | } 28 | 29 | /* use `scene` */ 30 | } 31 | } 32 | 33 | public struct Properties: Codable { 34 | let prop0: String 35 | let prop1: Int? 36 | } 37 | 38 | extension ViewController: GJMapDelegate { 39 | typealias P = Properties 40 | 41 | func map(_ map: GJMap, nodeFor feature: GJFeature) -> SKNode? { 42 | let mapRect = self.map.boundingMapRect 43 | let cgSize = mapRect.size.cgSize 44 | switch feature.geometry { 45 | case .point(let coordinate): 46 | let point = MKMapPoint(coordinate) 47 | guard let cgPoint = try? point.cgPoint(from: mapRect, to: cgSize) else { return nil } 48 | let node = SKShapeNode(circleOfRadius: /* ... */) 49 | node.position = cgPoint 50 | /* ... */ 51 | return node 52 | case .lineString(let coordinates): 53 | do { 54 | var points = try coordinates.map { try MKMapPoint($0).cgPoint(from: mapRect, to: cgSize) } 55 | let node = SKShapeNode(splinePoints: &points, count: points.count) 56 | /* ... */ 57 | return node 58 | } catch { 59 | print(error) 60 | return nil 61 | } 62 | } 63 | } 64 | } 65 | ``` 66 | Carthage setup. 67 | 68 | ``` 69 | github "maxvol/GeoJSONMap" ~> 0.1.2 70 | ``` 71 | 72 | -------------------------------------------------------------------------------- /amstertram.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maxvol/GeoJSONMap/cbbb9c58f8b31b20c3de46de73f07c200a8f7a73/amstertram.jpeg --------------------------------------------------------------------------------