From 7bffd1610c523c4b35dd012098a56765b016a946 Mon Sep 17 00:00:00 2001 From: eyaldar Date: Sat, 2 Jan 2016 00:45:48 +0200 Subject: [PATCH 1/8] migrating code from objective-c to swift --- .gitignore | 1 + .../project.pbxproj | 355 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../UserInterfaceState.xcuserstate | Bin 0 -> 32523 bytes .../xcdebugger/Breakpoints_v2.xcbkptlist | 23 ++ .../TBAnnotationClustering-Swift.xcscheme | 91 +++++ .../xcschemes/xcschememanagement.plist | 22 ++ .../AppDelegate.swift | 46 +++ .../AppIcon.appiconset/Contents.json | 68 ++++ .../Base.lproj/LaunchScreen.storyboard | 27 ++ .../Base.lproj/Main.storyboard | 42 +++ TBAnnotationClustering-Swift/Info.plist | 47 +++ .../TBClusterAnnotation.swift | 35 ++ .../TBClusterAnnotationView.swift | 95 +++++ .../TBCoordinateQuadTree.swift | 117 ++++++ .../TBHotelCSVTreeBuilder.swift | 53 +++ .../ViewController.swift | 105 ++++++ .../project.pbxproj | 51 +-- .../UserInterfaceState.xcuserstate | Bin 0 -> 20370 bytes .../xcdebugger/Breakpoints_v2.xcbkptlist | 5 + .../xcschemes/TBAnnotationClustering.xcscheme | 101 +++++ .../xcschemes/xcschememanagement.plist | 27 ++ TBAnnotationClustering/.DS_Store | Bin 0 -> 8196 bytes .../TBAnnotationClustering-Info.plist | 2 +- TBAnnotationClustering/TBClusterAnnotation.m | 2 +- TBAnnotationClustering/TBCoordinateQuadTree.m | 2 +- .../TBAnnotationClusteringTests-Info.plist | 22 -- .../TBAnnotationClusteringTests.m | 34 -- .../en.lproj/InfoPlist.strings | 2 - TBBoundingBox.swift | 33 ++ TBHotelInfo.swift | 19 + TBQuadTreeNode.swift | 113 ++++++ TBQuadTreeNodeData.swift | 19 + .../USA-HotelMotel.csv => USA-HotelMotel.csv | 0 34 files changed, 1462 insertions(+), 104 deletions(-) create mode 100644 .gitignore create mode 100644 TBAnnotationClustering-Swift.xcodeproj/project.pbxproj create mode 100644 TBAnnotationClustering-Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 TBAnnotationClustering-Swift.xcodeproj/project.xcworkspace/xcuserdata/Ran.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 TBAnnotationClustering-Swift.xcodeproj/xcuserdata/Ran.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist create mode 100644 TBAnnotationClustering-Swift.xcodeproj/xcuserdata/Ran.xcuserdatad/xcschemes/TBAnnotationClustering-Swift.xcscheme create mode 100644 TBAnnotationClustering-Swift.xcodeproj/xcuserdata/Ran.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 TBAnnotationClustering-Swift/AppDelegate.swift create mode 100644 TBAnnotationClustering-Swift/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 TBAnnotationClustering-Swift/Base.lproj/LaunchScreen.storyboard create mode 100644 TBAnnotationClustering-Swift/Base.lproj/Main.storyboard create mode 100644 TBAnnotationClustering-Swift/Info.plist create mode 100644 TBAnnotationClustering-Swift/TBClusterAnnotation.swift create mode 100644 TBAnnotationClustering-Swift/TBClusterAnnotationView.swift create mode 100644 TBAnnotationClustering-Swift/TBCoordinateQuadTree.swift create mode 100644 TBAnnotationClustering-Swift/TBHotelCSVTreeBuilder.swift create mode 100644 TBAnnotationClustering-Swift/ViewController.swift create mode 100644 TBAnnotationClustering.xcodeproj/project.xcworkspace/xcuserdata/Ran.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 TBAnnotationClustering.xcodeproj/xcuserdata/Ran.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist create mode 100644 TBAnnotationClustering.xcodeproj/xcuserdata/Ran.xcuserdatad/xcschemes/TBAnnotationClustering.xcscheme create mode 100644 TBAnnotationClustering.xcodeproj/xcuserdata/Ran.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 TBAnnotationClustering/.DS_Store delete mode 100644 TBAnnotationClusteringTests/TBAnnotationClusteringTests-Info.plist delete mode 100644 TBAnnotationClusteringTests/TBAnnotationClusteringTests.m delete mode 100644 TBAnnotationClusteringTests/en.lproj/InfoPlist.strings create mode 100644 TBBoundingBox.swift create mode 100644 TBHotelInfo.swift create mode 100644 TBQuadTreeNode.swift create mode 100644 TBQuadTreeNodeData.swift rename TBAnnotationClustering/USA-HotelMotel.csv => USA-HotelMotel.csv (100%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/TBAnnotationClustering-Swift.xcodeproj/project.pbxproj b/TBAnnotationClustering-Swift.xcodeproj/project.pbxproj new file mode 100644 index 0000000..2f5b1f9 --- /dev/null +++ b/TBAnnotationClustering-Swift.xcodeproj/project.pbxproj @@ -0,0 +1,355 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 257D9E021C36DA57004B0025 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257D9E011C36DA57004B0025 /* AppDelegate.swift */; }; + 257D9E041C36DA57004B0025 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257D9E031C36DA57004B0025 /* ViewController.swift */; }; + 257D9E071C36DA57004B0025 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 257D9E051C36DA57004B0025 /* Main.storyboard */; }; + 257D9E091C36DA57004B0025 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 257D9E081C36DA57004B0025 /* Assets.xcassets */; }; + 257D9E0C1C36DA57004B0025 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 257D9E0A1C36DA57004B0025 /* LaunchScreen.storyboard */; }; + 257D9E151C36E095004B0025 /* TBQuadTreeNodeData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257D9E141C36E095004B0025 /* TBQuadTreeNodeData.swift */; }; + 257D9E171C36E1FA004B0025 /* TBBoundingBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257D9E161C36E1FA004B0025 /* TBBoundingBox.swift */; }; + 257D9E191C36E3D4004B0025 /* TBQuadTreeNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257D9E181C36E3D4004B0025 /* TBQuadTreeNode.swift */; }; + 257D9E1C1C36F59D004B0025 /* USA-HotelMotel.csv in Resources */ = {isa = PBXBuildFile; fileRef = 257D9E1B1C36F59D004B0025 /* USA-HotelMotel.csv */; }; + 257D9E211C36F72A004B0025 /* TBHotelCSVTreeBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257D9E201C36F72A004B0025 /* TBHotelCSVTreeBuilder.swift */; }; + 257D9E241C36F762004B0025 /* TBHotelInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257D9E231C36F762004B0025 /* TBHotelInfo.swift */; }; + 257D9E261C370377004B0025 /* TBCoordinateQuadTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257D9E251C370377004B0025 /* TBCoordinateQuadTree.swift */; }; + 257D9E281C371038004B0025 /* TBClusterAnnotation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257D9E271C371038004B0025 /* TBClusterAnnotation.swift */; }; + 257D9E2A1C371CD6004B0025 /* TBClusterAnnotationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257D9E291C371CD6004B0025 /* TBClusterAnnotationView.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 257D9DFE1C36DA57004B0025 /* TBAnnotationClustering-Swift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "TBAnnotationClustering-Swift.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 257D9E011C36DA57004B0025 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 257D9E031C36DA57004B0025 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 257D9E061C36DA57004B0025 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 257D9E081C36DA57004B0025 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = "TBAnnotationClustering-Swift/Assets.xcassets"; sourceTree = ""; }; + 257D9E0B1C36DA57004B0025 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 257D9E0D1C36DA57004B0025 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = "TBAnnotationClustering-Swift/Info.plist"; sourceTree = ""; }; + 257D9E141C36E095004B0025 /* TBQuadTreeNodeData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TBQuadTreeNodeData.swift; sourceTree = ""; }; + 257D9E161C36E1FA004B0025 /* TBBoundingBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TBBoundingBox.swift; sourceTree = ""; }; + 257D9E181C36E3D4004B0025 /* TBQuadTreeNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TBQuadTreeNode.swift; sourceTree = ""; }; + 257D9E1B1C36F59D004B0025 /* USA-HotelMotel.csv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "USA-HotelMotel.csv"; sourceTree = ""; }; + 257D9E201C36F72A004B0025 /* TBHotelCSVTreeBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TBHotelCSVTreeBuilder.swift; path = "TBAnnotationClustering-Swift/TBHotelCSVTreeBuilder.swift"; sourceTree = ""; }; + 257D9E231C36F762004B0025 /* TBHotelInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TBHotelInfo.swift; sourceTree = ""; }; + 257D9E251C370377004B0025 /* TBCoordinateQuadTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TBCoordinateQuadTree.swift; sourceTree = ""; }; + 257D9E271C371038004B0025 /* TBClusterAnnotation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TBClusterAnnotation.swift; sourceTree = ""; }; + 257D9E291C371CD6004B0025 /* TBClusterAnnotationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TBClusterAnnotationView.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 257D9DFB1C36DA57004B0025 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 257D9DF51C36DA57004B0025 = { + isa = PBXGroup; + children = ( + 257D9E1A1C36F56E004B0025 /* Supporting Files */, + 257D9E131C36E048004B0025 /* Data Structures */, + 257D9E221C36F742004B0025 /* Hotel Data */, + 257D9E001C36DA57004B0025 /* TBAnnotationClustering-Swift */, + 257D9DFF1C36DA57004B0025 /* Products */, + ); + sourceTree = ""; + }; + 257D9DFF1C36DA57004B0025 /* Products */ = { + isa = PBXGroup; + children = ( + 257D9DFE1C36DA57004B0025 /* TBAnnotationClustering-Swift.app */, + ); + name = Products; + sourceTree = ""; + }; + 257D9E001C36DA57004B0025 /* TBAnnotationClustering-Swift */ = { + isa = PBXGroup; + children = ( + 257D9E011C36DA57004B0025 /* AppDelegate.swift */, + 257D9E031C36DA57004B0025 /* ViewController.swift */, + 257D9E251C370377004B0025 /* TBCoordinateQuadTree.swift */, + 257D9E271C371038004B0025 /* TBClusterAnnotation.swift */, + 257D9E291C371CD6004B0025 /* TBClusterAnnotationView.swift */, + 257D9E051C36DA57004B0025 /* Main.storyboard */, + 257D9E0A1C36DA57004B0025 /* LaunchScreen.storyboard */, + ); + path = "TBAnnotationClustering-Swift"; + sourceTree = ""; + }; + 257D9E131C36E048004B0025 /* Data Structures */ = { + isa = PBXGroup; + children = ( + 257D9E141C36E095004B0025 /* TBQuadTreeNodeData.swift */, + 257D9E161C36E1FA004B0025 /* TBBoundingBox.swift */, + 257D9E181C36E3D4004B0025 /* TBQuadTreeNode.swift */, + ); + name = "Data Structures"; + sourceTree = ""; + }; + 257D9E1A1C36F56E004B0025 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 257D9E1B1C36F59D004B0025 /* USA-HotelMotel.csv */, + 257D9E081C36DA57004B0025 /* Assets.xcassets */, + 257D9E0D1C36DA57004B0025 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 257D9E221C36F742004B0025 /* Hotel Data */ = { + isa = PBXGroup; + children = ( + 257D9E201C36F72A004B0025 /* TBHotelCSVTreeBuilder.swift */, + 257D9E231C36F762004B0025 /* TBHotelInfo.swift */, + ); + name = "Hotel Data"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 257D9DFD1C36DA57004B0025 /* TBAnnotationClustering-Swift */ = { + isa = PBXNativeTarget; + buildConfigurationList = 257D9E101C36DA57004B0025 /* Build configuration list for PBXNativeTarget "TBAnnotationClustering-Swift" */; + buildPhases = ( + 257D9DFA1C36DA57004B0025 /* Sources */, + 257D9DFB1C36DA57004B0025 /* Frameworks */, + 257D9DFC1C36DA57004B0025 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "TBAnnotationClustering-Swift"; + productName = "TBAnnotationClustering-Swift"; + productReference = 257D9DFE1C36DA57004B0025 /* TBAnnotationClustering-Swift.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 257D9DF61C36DA57004B0025 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 0720; + ORGANIZATIONNAME = eyaldar; + TargetAttributes = { + 257D9DFD1C36DA57004B0025 = { + CreatedOnToolsVersion = 7.2; + DevelopmentTeam = CYF3A39EVW; + }; + }; + }; + buildConfigurationList = 257D9DF91C36DA57004B0025 /* Build configuration list for PBXProject "TBAnnotationClustering-Swift" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 257D9DF51C36DA57004B0025; + productRefGroup = 257D9DFF1C36DA57004B0025 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 257D9DFD1C36DA57004B0025 /* TBAnnotationClustering-Swift */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 257D9DFC1C36DA57004B0025 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 257D9E0C1C36DA57004B0025 /* LaunchScreen.storyboard in Resources */, + 257D9E091C36DA57004B0025 /* Assets.xcassets in Resources */, + 257D9E071C36DA57004B0025 /* Main.storyboard in Resources */, + 257D9E1C1C36F59D004B0025 /* USA-HotelMotel.csv in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 257D9DFA1C36DA57004B0025 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 257D9E211C36F72A004B0025 /* TBHotelCSVTreeBuilder.swift in Sources */, + 257D9E191C36E3D4004B0025 /* TBQuadTreeNode.swift in Sources */, + 257D9E2A1C371CD6004B0025 /* TBClusterAnnotationView.swift in Sources */, + 257D9E241C36F762004B0025 /* TBHotelInfo.swift in Sources */, + 257D9E041C36DA57004B0025 /* ViewController.swift in Sources */, + 257D9E021C36DA57004B0025 /* AppDelegate.swift in Sources */, + 257D9E261C370377004B0025 /* TBCoordinateQuadTree.swift in Sources */, + 257D9E151C36E095004B0025 /* TBQuadTreeNodeData.swift in Sources */, + 257D9E171C36E1FA004B0025 /* TBBoundingBox.swift in Sources */, + 257D9E281C371038004B0025 /* TBClusterAnnotation.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 257D9E051C36DA57004B0025 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 257D9E061C36DA57004B0025 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 257D9E0A1C36DA57004B0025 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 257D9E0B1C36DA57004B0025 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 257D9E0E1C36DA57004B0025 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 257D9E0F1C36DA57004B0025 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 257D9E111C36DA57004B0025 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = "TBAnnotationClustering-Swift/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.eyaldar.TBAnnotationClustering-Swift"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 257D9E121C36DA57004B0025 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = "TBAnnotationClustering-Swift/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.eyaldar.TBAnnotationClustering-Swift"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 257D9DF91C36DA57004B0025 /* Build configuration list for PBXProject "TBAnnotationClustering-Swift" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 257D9E0E1C36DA57004B0025 /* Debug */, + 257D9E0F1C36DA57004B0025 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 257D9E101C36DA57004B0025 /* Build configuration list for PBXNativeTarget "TBAnnotationClustering-Swift" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 257D9E111C36DA57004B0025 /* Debug */, + 257D9E121C36DA57004B0025 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 257D9DF61C36DA57004B0025 /* Project object */; +} diff --git a/TBAnnotationClustering-Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/TBAnnotationClustering-Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..a3084cf --- /dev/null +++ b/TBAnnotationClustering-Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/TBAnnotationClustering-Swift.xcodeproj/project.xcworkspace/xcuserdata/Ran.xcuserdatad/UserInterfaceState.xcuserstate b/TBAnnotationClustering-Swift.xcodeproj/project.xcworkspace/xcuserdata/Ran.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..8034bea275fe2381cea6583ed7bf9d5a33e792cd GIT binary patch literal 32523 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 + + + + + + + + diff --git a/TBAnnotationClustering-Swift.xcodeproj/xcuserdata/Ran.xcuserdatad/xcschemes/TBAnnotationClustering-Swift.xcscheme b/TBAnnotationClustering-Swift.xcodeproj/xcuserdata/Ran.xcuserdatad/xcschemes/TBAnnotationClustering-Swift.xcscheme new file mode 100644 index 0000000..d204d0d --- /dev/null +++ b/TBAnnotationClustering-Swift.xcodeproj/xcuserdata/Ran.xcuserdatad/xcschemes/TBAnnotationClustering-Swift.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TBAnnotationClustering-Swift.xcodeproj/xcuserdata/Ran.xcuserdatad/xcschemes/xcschememanagement.plist b/TBAnnotationClustering-Swift.xcodeproj/xcuserdata/Ran.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..aa5a1b2 --- /dev/null +++ b/TBAnnotationClustering-Swift.xcodeproj/xcuserdata/Ran.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + TBAnnotationClustering-Swift.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 257D9DFD1C36DA57004B0025 + + primary + + + + + diff --git a/TBAnnotationClustering-Swift/AppDelegate.swift b/TBAnnotationClustering-Swift/AppDelegate.swift new file mode 100644 index 0000000..1b3c646 --- /dev/null +++ b/TBAnnotationClustering-Swift/AppDelegate.swift @@ -0,0 +1,46 @@ +// +// AppDelegate.swift +// TBAnnotationClustering-Swift +// +// Created by Eyal Darshan on 1/1/16. +// Copyright © 2016 eyaldar. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + + func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + // Override point for customization after application launch. + return true + } + + func applicationWillResignActive(application: UIApplication) { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. + } + + func applicationDidEnterBackground(application: UIApplication) { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } + + func applicationWillEnterForeground(application: UIApplication) { + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. + } + + func applicationDidBecomeActive(application: UIApplication) { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + } + + func applicationWillTerminate(application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } + + +} + diff --git a/TBAnnotationClustering-Swift/Assets.xcassets/AppIcon.appiconset/Contents.json b/TBAnnotationClustering-Swift/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..36d2c80 --- /dev/null +++ b/TBAnnotationClustering-Swift/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/TBAnnotationClustering-Swift/Base.lproj/LaunchScreen.storyboard b/TBAnnotationClustering-Swift/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..2e721e1 --- /dev/null +++ b/TBAnnotationClustering-Swift/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TBAnnotationClustering-Swift/Base.lproj/Main.storyboard b/TBAnnotationClustering-Swift/Base.lproj/Main.storyboard new file mode 100644 index 0000000..e4f8e63 --- /dev/null +++ b/TBAnnotationClustering-Swift/Base.lproj/Main.storyboard @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TBAnnotationClustering-Swift/Info.plist b/TBAnnotationClustering-Swift/Info.plist new file mode 100644 index 0000000..40c6215 --- /dev/null +++ b/TBAnnotationClustering-Swift/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/TBAnnotationClustering-Swift/TBClusterAnnotation.swift b/TBAnnotationClustering-Swift/TBClusterAnnotation.swift new file mode 100644 index 0000000..dd98245 --- /dev/null +++ b/TBAnnotationClustering-Swift/TBClusterAnnotation.swift @@ -0,0 +1,35 @@ +// +// TBClusterAllocation.swift +// TBAnnotationClustering-Swift +// +// Created by Eyal Darshan on 1/1/16. +// Copyright © 2016 eyaldar. All rights reserved. +// + +import MapKit + +class TBClusterAnnotation: NSObject, MKAnnotation { + + let coordinate: CLLocationCoordinate2D + let count:Int + + var title:String? + var subtitle:String? + + init(coordinate:CLLocationCoordinate2D, count:Int) { + self.coordinate = coordinate + self.title = "\(count) hotels in this area" + self.count = count + + super.init() + } + + override func isEqual(object: AnyObject?) -> Bool { + if let other = object as? TBClusterAnnotation { + return coordinate.longitude == other.coordinate.longitude && + coordinate.latitude == other.coordinate.latitude + } + + return false + } +} diff --git a/TBAnnotationClustering-Swift/TBClusterAnnotationView.swift b/TBAnnotationClustering-Swift/TBClusterAnnotationView.swift new file mode 100644 index 0000000..57291f3 --- /dev/null +++ b/TBAnnotationClustering-Swift/TBClusterAnnotationView.swift @@ -0,0 +1,95 @@ +// +// TBClusterAnnotationView.swift +// TBAnnotationClustering-Swift +// +// Created by Eyal Darshan on 1/1/16. +// Copyright © 2016 eyaldar. All rights reserved. +// + +import MapKit + +class TBClusterAnnotationView: MKAnnotationView { + + let TBScaleFactorAlpha:Float = 0.3 + let TBScaleFactorBeta:Float = 0.4 + + private var count:Int? + private var countLabel:UILabel? + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + override init(annotation: MKAnnotation?, reuseIdentifier: String?) { + super.init(annotation: annotation, reuseIdentifier: reuseIdentifier) + + self.backgroundColor = UIColor.clearColor() + setupLabel() + setCount(1) + } + + func TBScaledValueForValue(value:Float, multiplier:Float) -> Float { + return multiplier * (1.0 / (1.0 + expf(-1 * TBScaleFactorAlpha * powf(value, TBScaleFactorBeta)))) + } + + func TBCenterRect(rect:CGRect, center: CGPoint) -> CGRect { + let r = CGRect(x: center.x - rect.size.width/2.0, y: center.y - rect.size.height/2.0, width: rect.size.width, height: rect.size.height) + return r + } + + func TBRectCenter(rect: CGRect) -> CGPoint { + return CGPoint(x: CGRectGetMidX(rect), y: CGRectGetMidY(rect)); + } + + func setupLabel() { + countLabel = UILabel(frame: self.frame) + countLabel?.backgroundColor = UIColor.clearColor() + countLabel?.textColor = UIColor.whiteColor() + countLabel?.textAlignment = NSTextAlignment.Center + countLabel?.shadowColor = UIColor(white: 0, alpha: 0.75) + countLabel?.shadowOffset = CGSize(width: 0, height: -1) + countLabel?.adjustsFontSizeToFitWidth = true + countLabel?.numberOfLines = 1 + countLabel?.font = UIFont.boldSystemFontOfSize(12) + countLabel?.baselineAdjustment = UIBaselineAdjustment.AlignCenters + + addSubview(countLabel!) + } + + func setCount(count:Int) { + self.count = count + let size = CGFloat(roundf(TBScaledValueForValue(Float(count), multiplier: 44.0))) + + let newBounds = CGRect(x: 0, y: 0, width: size, height: size) + frame = TBCenterRect(newBounds, center: self.center) + + let newLabelBounds:CGRect = CGRect(x: 0, y: 0, width: newBounds.size.width, height: newBounds.size.height) + countLabel?.frame = TBCenterRect(newLabelBounds, center: TBRectCenter(newBounds)) + countLabel?.text = String(count) + + self.setNeedsDisplay() + } + + override func drawRect(rect: CGRect) { + let context = UIGraphicsGetCurrentContext() + + CGContextSetAllowsAntialiasing(context, true) + + let outerCircleStrokeColor = UIColor(white: 0, alpha: 0.25) + let innerCircleStrokeColor = UIColor.whiteColor() + let innerCircleFillColor = UIColor(red: (255.0 / 255.0), green: (95.0 / 255.0), blue: (42.0 / 255.0), alpha: 1.0) + + let circleFrame = CGRectInset(rect, 4, 4) + + outerCircleStrokeColor.setStroke() + CGContextSetLineWidth(context, 5.0) + CGContextStrokeEllipseInRect(context, circleFrame) + + innerCircleStrokeColor.setStroke() + CGContextSetLineWidth(context, 4.0) + CGContextStrokeEllipseInRect(context, circleFrame) + + innerCircleFillColor.setFill() + CGContextStrokeEllipseInRect(context, circleFrame) + } +} diff --git a/TBAnnotationClustering-Swift/TBCoordinateQuadTree.swift b/TBAnnotationClustering-Swift/TBCoordinateQuadTree.swift new file mode 100644 index 0000000..f68f797 --- /dev/null +++ b/TBAnnotationClustering-Swift/TBCoordinateQuadTree.swift @@ -0,0 +1,117 @@ +// +// File.swift +// TBAnnotationClustering-Swift +// +// Created by Eyal Darshan on 1/1/16. +// Copyright © 2016 eyaldar. All rights reserved. +// + +import Foundation +import MapKit + +class TBCoordinateQuadTree : NSObject { + + weak var mapView: MKMapView! + let hotelTreeBuilder:TBHotelCSVTreeBuilder + private var root:TBQuadTreeNode? + + init(builder:TBHotelCSVTreeBuilder, mapView: MKMapView) { + self.hotelTreeBuilder = builder + self.mapView = mapView + } + + func buildTree(dataFileName:String, worldBounds:TBBoundingBox) { + root = hotelTreeBuilder.buildTree(dataFileName, worldBounds: worldBounds) + } + + func clusteredAnnotationWithinMapRect(rect:MKMapRect, zoomScale:MKZoomScale) -> [TBClusterAnnotation] { + let tbCellSize = TBCellSizeForZoomScale(zoomScale) + let zoomScaleDouble = Double(zoomScale) + let scaleFactor = zoomScaleDouble / tbCellSize + + let minX = floor(MKMapRectGetMinX(rect) * scaleFactor) + let maxX = floor(MKMapRectGetMaxX(rect) * scaleFactor) + let minY = floor(MKMapRectGetMinY(rect) * scaleFactor) + let maxY = floor(MKMapRectGetMaxY(rect) * scaleFactor) + + var clusteredAnnotations = [TBClusterAnnotation]() + + for var x:Double = minX; x <= maxX; x++ { + for var y:Double = minY; y <= maxY; y++ { + let mapRect = MKMapRectMake(x/scaleFactor, y/scaleFactor, 1.0/scaleFactor, 1.0/scaleFactor) + + var totalX = 0.0 + var totalY = 0.0 + + var names = [String]() + var phoneNumbers = [String]() + + root?.gatherDataInRange(getBoundingBox(mapRect), action: { (data) -> Void in + totalX += data.x + totalY += data.y + + let hotelInfo = data.data + names.append(hotelInfo.name) + + if let phoneNum = hotelInfo.phoneNumber! { + phoneNumbers.append(phoneNum) + } + }) + + let count = names.count + + if count > 1 { + let coordinate = CLLocationCoordinate2D(latitude: totalX / Double(count), longitude: totalY / Double(count)) + let annotation = TBClusterAnnotation(coordinate: coordinate, count: count) + clusteredAnnotations.append(annotation) + } + + if count > 1 { + let coordinate = CLLocationCoordinate2D(latitude: totalX, longitude: totalY) + let annotation = TBClusterAnnotation(coordinate: coordinate, count: count) + annotation.title = names.last! + annotation.subtitle = phoneNumbers.last! + clusteredAnnotations.append(annotation) + } + } + } + + return clusteredAnnotations + } + + func getBoundingBox(mapRect:MKMapRect) -> TBBoundingBox { + let topLeft = MKCoordinateForMapPoint(mapRect.origin) + let bottomRight = MKCoordinateForMapPoint(MKMapPoint(x: MKMapRectGetMaxX(mapRect), y: MKMapRectGetMaxY(mapRect))) + + let minLat = bottomRight.latitude + let maxLat = topLeft.latitude + + let minLong = topLeft.longitude + let maxLong = bottomRight.longitude + + return TBBoundingBox(x: minLat, y: minLong, xf: maxLat, yf: maxLong) + } + + func TBZoomScaleToZoomLevel(scale:MKZoomScale) -> Double { + let totalTilesAtMaxZoom = MKMapSizeWorld.width / 256.0; + let zoomLevelAtMaxZoom = log2(totalTilesAtMaxZoom); + let zoomLevel = max(0, zoomLevelAtMaxZoom + floor(log2(Double(scale)) + 0.5)); + + return zoomLevel; + } + + func TBCellSizeForZoomScale(zoomScale:MKZoomScale) -> Double { + let zoomLevel = TBZoomScaleToZoomLevel(zoomScale); + + switch (zoomLevel) { + case 13, 14, 15: + return 64 + case 16, 17, 18: + return 32 + case 19: + return 16 + default: + return 88 + } + } +} diff --git a/TBAnnotationClustering-Swift/TBHotelCSVTreeBuilder.swift b/TBAnnotationClustering-Swift/TBHotelCSVTreeBuilder.swift new file mode 100644 index 0000000..7282400 --- /dev/null +++ b/TBAnnotationClustering-Swift/TBHotelCSVTreeBuilder.swift @@ -0,0 +1,53 @@ +// +// TBCoordinateQuadTreeBuilder.swift +// TBAnnotationClustering-Swift +// +// Created by Eyal Darshan on 1/1/16. +// Copyright © 2016 eyaldar. All rights reserved. +// + +import Foundation + +class TBHotelCSVTreeBuilder { + + func buildTree(dataFileName:String, worldBounds:TBBoundingBox) -> TBQuadTreeNode { + let data = getFileContent(dataFileName) + let lines = data.componentsSeparatedByString("\n") + + var dataArray = [TBQuadTreeNodeData]() + + for line in lines { + if line != "" { + dataArray.append(dataFromLine(line)) + } + } + + return TBQuadTreeNode(boundary: worldBounds, capacity: 4, dataArr: dataArray) + } + + private func dataFromLine(line: NSString) -> TBQuadTreeNodeData { + let components = line.componentsSeparatedByString(",") + + let latitude = Double(components[1].stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()))! + let longitude = Double(components[0].stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()))! + + let hotelName = components[2].stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) + let hotelPhoneNumber = components.last!.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) + + let hotelInfo = TBHotelInfo(hotelName: hotelName, hotelPhoneNumber: hotelPhoneNumber) + + return TBQuadTreeNodeData(x: latitude, y: longitude, data: hotelInfo) + } + + private func getFileContent(fileName:String) -> String { + let bundle = NSBundle.mainBundle() + let path = bundle.pathForResource(fileName, ofType: "csv")! + var data = "" + + do { + data = try String(contentsOfFile: path, encoding: NSASCIIStringEncoding) + } catch {} + + return data + } +} \ No newline at end of file diff --git a/TBAnnotationClustering-Swift/ViewController.swift b/TBAnnotationClustering-Swift/ViewController.swift new file mode 100644 index 0000000..49860ce --- /dev/null +++ b/TBAnnotationClustering-Swift/ViewController.swift @@ -0,0 +1,105 @@ +// +// ViewController.swift +// TBAnnotationClustering-Swift +// +// Created by Eyal Darshan on 1/1/16. +// Copyright © 2016 eyaldar. All rights reserved. +// + +import UIKit +import Foundation +import MapKit + +class ViewController: UIViewController, MKMapViewDelegate { + @IBOutlet weak var mapView: MKMapView! + + let TBAnnotatioViewReuseID = "TBAnnotatioViewReuseID" + + // DEFINE THE TREE'S BOUNDS: + let world = TBBoundingBox(x: 19, y: -166, xf: 72, yf:-53)// x: 90, y: 180, xf: -90, yf: -180) + + let hotelTreeBuilder = TBHotelCSVTreeBuilder() + var tbCoordinateQuadTree:TBCoordinateQuadTree? + + override func viewDidLoad() { + super.viewDidLoad() + + mapView.delegate = self + + tbCoordinateQuadTree = TBCoordinateQuadTree(builder: hotelTreeBuilder, mapView: mapView) + tbCoordinateQuadTree!.buildTree("USA-HotelMotel", worldBounds: world) + } + + func updateMapViewAnnotations(annotations: [MKAnnotation]) { + let before = NSMutableSet(array: self.mapView.annotations) + let after = NSMutableSet(array: annotations) + + let toKeep = NSMutableSet(set: before) + toKeep.intersectsSet(after as Set) + + let toAdd = NSMutableSet(set: after) + toAdd.minusSet(toKeep as Set) + + let toRemove = NSMutableSet(set: before) + toRemove.minusSet(after as Set) + + dispatch_async(dispatch_get_main_queue()) { () -> Void in + self.mapView.addAnnotations(toAdd.allObjects as! [MKAnnotation]) + self.mapView.removeAnnotations(toRemove.allObjects as! [MKAnnotation]) + } + } + + func addBounceAnimationToView(view:UIView?) { + let bounceAnimation = CAKeyframeAnimation(keyPath: "transform.scale") + + bounceAnimation.values = [0.05, 1.1, 0.9, 1] + bounceAnimation.duration = 0.6 + + var timingFunctions = [CAMediaTimingFunction]() + + for _ in 0..<4 { + timingFunctions.append(CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)) + } + + bounceAnimation.timingFunctions = timingFunctions + bounceAnimation.removedOnCompletion = false + + view!.layer.addAnimation(bounceAnimation, forKey: "bounce") + } + + // MARK: MKMapViewDelegate + + func mapView(mapView: MKMapView, didAddAnnotationViews views: [MKAnnotationView]) { + for view in views { + addBounceAnimationToView(view) + } + } + + func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) { + dispatch_async(dispatch_get_main_queue()) { () -> Void in + let zoomScale = Double(self.mapView.bounds.size.width) / self.mapView.visibleMapRect.size.width + let annotations = self.tbCoordinateQuadTree!.clusteredAnnotationWithinMapRect(mapView.visibleMapRect, zoomScale: MKZoomScale(zoomScale)) + + self.updateMapViewAnnotations(annotations) + } + } + + func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? { + + var view:TBClusterAnnotationView? + if let dequeuedView = mapView.dequeueReusableAnnotationViewWithIdentifier(TBAnnotatioViewReuseID) as? TBClusterAnnotationView { + view = dequeuedView + } else { + view = TBClusterAnnotationView(annotation: annotation, reuseIdentifier: TBAnnotatioViewReuseID) + } + + view?.canShowCallout = true + + if let annotation = annotation as? TBClusterAnnotation { + view?.setCount(annotation.count) + } + + return view + } +} + diff --git a/TBAnnotationClustering.xcodeproj/project.pbxproj b/TBAnnotationClustering.xcodeproj/project.pbxproj index fc0803a..3e1b758 100644 --- a/TBAnnotationClustering.xcodeproj/project.pbxproj +++ b/TBAnnotationClustering.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 257D9E1E1C36F5D7004B0025 /* USA-HotelMotel.csv in Resources */ = {isa = PBXBuildFile; fileRef = 257D9E1D1C36F5D7004B0025 /* USA-HotelMotel.csv */; }; E44063B617FF44A500E3A194 /* TBClusterAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = E44063B517FF44A500E3A194 /* TBClusterAnnotationView.m */; }; E47A6E8D17F62C0700A468D1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E47A6E8C17F62C0700A468D1 /* Foundation.framework */; }; E47A6E8F17F62C0700A468D1 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E47A6E8E17F62C0700A468D1 /* CoreGraphics.framework */; }; @@ -18,9 +19,6 @@ E47A6EA617F62C0700A468D1 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E47A6EA517F62C0700A468D1 /* XCTest.framework */; }; E47A6EA717F62C0700A468D1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E47A6E8C17F62C0700A468D1 /* Foundation.framework */; }; E47A6EA817F62C0700A468D1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E47A6E9017F62C0700A468D1 /* UIKit.framework */; }; - E47A6EB017F62C0700A468D1 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = E47A6EAE17F62C0700A468D1 /* InfoPlist.strings */; }; - E47A6EB217F62C0700A468D1 /* TBAnnotationClusteringTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E47A6EB117F62C0700A468D1 /* TBAnnotationClusteringTests.m */; }; - E47A6EBC17F62C1000A468D1 /* USA-HotelMotel.csv in Resources */ = {isa = PBXBuildFile; fileRef = E47A6EBB17F62C1000A468D1 /* USA-HotelMotel.csv */; }; E480B06C1804F047006247FA /* TBClusterAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = E480B06B1804F047006247FA /* TBClusterAnnotation.m */; }; E4FB04C417F6302000FC288B /* TBQuadTree.m in Sources */ = {isa = PBXBuildFile; fileRef = E4FB04C317F6302000FC288B /* TBQuadTree.m */; }; E4FB04CD17F6320B00FC288B /* TBCoordinateQuadTree.m in Sources */ = {isa = PBXBuildFile; fileRef = E4FB04CC17F6320B00FC288B /* TBCoordinateQuadTree.m */; }; @@ -40,6 +38,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 257D9E1D1C36F5D7004B0025 /* USA-HotelMotel.csv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "USA-HotelMotel.csv"; sourceTree = SOURCE_ROOT; }; E44063B417FF44A500E3A194 /* TBClusterAnnotationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TBClusterAnnotationView.h; sourceTree = ""; }; E44063B517FF44A500E3A194 /* TBClusterAnnotationView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TBClusterAnnotationView.m; sourceTree = ""; }; E47A6E8917F62C0700A468D1 /* TBAnnotationClustering.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TBAnnotationClustering.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -55,10 +54,6 @@ E47A6E9E17F62C0700A468D1 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; E47A6EA417F62C0700A468D1 /* TBAnnotationClusteringTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TBAnnotationClusteringTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; E47A6EA517F62C0700A468D1 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; - E47A6EAD17F62C0700A468D1 /* TBAnnotationClusteringTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TBAnnotationClusteringTests-Info.plist"; sourceTree = ""; }; - E47A6EAF17F62C0700A468D1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - E47A6EB117F62C0700A468D1 /* TBAnnotationClusteringTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TBAnnotationClusteringTests.m; sourceTree = ""; }; - E47A6EBB17F62C1000A468D1 /* USA-HotelMotel.csv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "USA-HotelMotel.csv"; sourceTree = ""; }; E480B06A1804F047006247FA /* TBClusterAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TBClusterAnnotation.h; sourceTree = ""; }; E480B06B1804F047006247FA /* TBClusterAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TBClusterAnnotation.m; sourceTree = ""; }; E4FB04C217F6302000FC288B /* TBQuadTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TBQuadTree.h; sourceTree = ""; }; @@ -101,7 +96,6 @@ isa = PBXGroup; children = ( E47A6E9217F62C0700A468D1 /* TBAnnotationClustering */, - E47A6EAB17F62C0700A468D1 /* TBAnnotationClusteringTests */, E47A6E8B17F62C0700A468D1 /* Frameworks */, E47A6E8A17F62C0700A468D1 /* Products */, ); @@ -153,7 +147,7 @@ E47A6E9317F62C0700A468D1 /* Supporting Files */ = { isa = PBXGroup; children = ( - E47A6EBB17F62C1000A468D1 /* USA-HotelMotel.csv */, + 257D9E1D1C36F5D7004B0025 /* USA-HotelMotel.csv */, E47A6E9417F62C0700A468D1 /* TBAnnotationClustering-Info.plist */, E47A6E9517F62C0700A468D1 /* InfoPlist.strings */, E47A6E9817F62C0700A468D1 /* main.m */, @@ -162,24 +156,6 @@ name = "Supporting Files"; sourceTree = ""; }; - E47A6EAB17F62C0700A468D1 /* TBAnnotationClusteringTests */ = { - isa = PBXGroup; - children = ( - E47A6EB117F62C0700A468D1 /* TBAnnotationClusteringTests.m */, - E47A6EAC17F62C0700A468D1 /* Supporting Files */, - ); - path = TBAnnotationClusteringTests; - sourceTree = ""; - }; - E47A6EAC17F62C0700A468D1 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - E47A6EAD17F62C0700A468D1 /* TBAnnotationClusteringTests-Info.plist */, - E47A6EAE17F62C0700A468D1 /* InfoPlist.strings */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -225,7 +201,7 @@ isa = PBXProject; attributes = { CLASSPREFIX = TB; - LastUpgradeCheck = 0500; + LastUpgradeCheck = 0720; ORGANIZATIONNAME = "Theodore Calmes"; TargetAttributes = { E47A6EA317F62C0700A468D1 = { @@ -256,7 +232,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - E47A6EBC17F62C1000A468D1 /* USA-HotelMotel.csv in Resources */, + 257D9E1E1C36F5D7004B0025 /* USA-HotelMotel.csv in Resources */, E47A6E9717F62C0700A468D1 /* InfoPlist.strings in Resources */, E47A6E9F17F62C0700A468D1 /* Images.xcassets in Resources */, ); @@ -266,7 +242,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - E47A6EB017F62C0700A468D1 /* InfoPlist.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -291,7 +266,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - E47A6EB217F62C0700A468D1 /* TBAnnotationClusteringTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -314,14 +288,6 @@ name = InfoPlist.strings; sourceTree = ""; }; - E47A6EAE17F62C0700A468D1 /* InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - E47A6EAF17F62C0700A468D1 /* en */, - ); - name = InfoPlist.strings; - sourceTree = ""; - }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ @@ -329,7 +295,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -344,6 +309,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -368,7 +334,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -405,6 +370,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "TBAnnotationClustering/TBAnnotationClustering-Prefix.pch"; INFOPLIST_FILE = "TBAnnotationClustering/TBAnnotationClustering-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "thoughtbot.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -418,6 +384,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "TBAnnotationClustering/TBAnnotationClustering-Prefix.pch"; INFOPLIST_FILE = "TBAnnotationClustering/TBAnnotationClustering-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "thoughtbot.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -426,7 +393,6 @@ E47A6EB917F62C0700A468D1 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/TBAnnotationClustering.app/TBAnnotationClustering"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", @@ -449,7 +415,6 @@ E47A6EBA17F62C0700A468D1 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/TBAnnotationClustering.app/TBAnnotationClustering"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", diff --git a/TBAnnotationClustering.xcodeproj/project.xcworkspace/xcuserdata/Ran.xcuserdatad/UserInterfaceState.xcuserstate b/TBAnnotationClustering.xcodeproj/project.xcworkspace/xcuserdata/Ran.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..9eef907edee5701fdbca2a1789323b16826dafb1 GIT binary patch literal 20370 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 literal 0 HcmV?d00001 diff --git a/TBAnnotationClustering.xcodeproj/xcuserdata/Ran.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/TBAnnotationClustering.xcodeproj/xcuserdata/Ran.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..fe2b454 --- /dev/null +++ b/TBAnnotationClustering.xcodeproj/xcuserdata/Ran.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,5 @@ + + + diff --git a/TBAnnotationClustering.xcodeproj/xcuserdata/Ran.xcuserdatad/xcschemes/TBAnnotationClustering.xcscheme b/TBAnnotationClustering.xcodeproj/xcuserdata/Ran.xcuserdatad/xcschemes/TBAnnotationClustering.xcscheme new file mode 100644 index 0000000..95091d1 --- /dev/null +++ b/TBAnnotationClustering.xcodeproj/xcuserdata/Ran.xcuserdatad/xcschemes/TBAnnotationClustering.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TBAnnotationClustering.xcodeproj/xcuserdata/Ran.xcuserdatad/xcschemes/xcschememanagement.plist b/TBAnnotationClustering.xcodeproj/xcuserdata/Ran.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..341f744 --- /dev/null +++ b/TBAnnotationClustering.xcodeproj/xcuserdata/Ran.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,27 @@ + + + + + SchemeUserState + + TBAnnotationClustering.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + E47A6E8817F62C0700A468D1 + + primary + + + E47A6EA317F62C0700A468D1 + + primary + + + + + diff --git a/TBAnnotationClustering/.DS_Store b/TBAnnotationClustering/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..0b08b174f544f6fc058c9b1c1f16f500a8688e8f GIT binary patch literal 8196 zcmeI1!EVz)5QhIP6^aBBZ~&E?x%JXYyn#srQV&SbR-D_WrUbcml(?ctKL!uQ1Mmoa zi}26vQrT-qN)riHVm8_xXLtXd@#l@LaR9jC^~GCY2f%<;?DHpVdWwuo?Ub$1^Mck< z4@@ybiSLJbIquB14kKU$jDQg^0!H8=5a2Ug%3#TJ-;Y{r1dPCcNkHxo39HyN*xFmY zb+FMCfOebRT6oMnKs8CQX|T1oD&?9!dvHPOLW<$Moa2d1r%i*cz4dZ9FNX`BUC22RsH)*1mL&?O+b`v4gV>?3dH@8@}W&N2BpePG>PXyFm?42QVF87`@tQ+Io{P+>0Fe?$E%Qa@JhL_J=$=enb4?i-w7hY#`xCuptOFrX!&!Pa`uSY zob^)AB;yLPT4=4V?&H@~zf^v0R(&)(aX8_$-bztS!ov+3JYKID(-$(%@S~s6hAT!f z%D!u@_$tI$axcwrq5DhrUWU)yb!Y53(S6W!1%=$&YejJ>yPF0(e?31kf+_y;Induj z#du2YE!kbOCCt`aDT>JntL92imDOroR?$WNl)>#C182{Fxouf70vi)}GXMYp literal 0 HcmV?d00001 diff --git a/TBAnnotationClustering/TBAnnotationClustering-Info.plist b/TBAnnotationClustering/TBAnnotationClustering-Info.plist index 763c73b..5860c3f 100644 --- a/TBAnnotationClustering/TBAnnotationClustering-Info.plist +++ b/TBAnnotationClustering/TBAnnotationClustering-Info.plist @@ -9,7 +9,7 @@ CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier - thoughtbot.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/TBAnnotationClustering/TBClusterAnnotation.m b/TBAnnotationClustering/TBClusterAnnotation.m index e9d86c2..c41f6d2 100644 --- a/TBAnnotationClustering/TBClusterAnnotation.m +++ b/TBAnnotationClustering/TBClusterAnnotation.m @@ -15,7 +15,7 @@ - (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate count:(NSInteger)cou self = [super init]; if (self) { _coordinate = coordinate; - _title = [NSString stringWithFormat:@"%d hotels in this area", count]; + _title = [NSString stringWithFormat:@"%ld hotels in this area", (long)count]; _count = count; } return self; diff --git a/TBAnnotationClustering/TBCoordinateQuadTree.m b/TBAnnotationClustering/TBCoordinateQuadTree.m index 7028980..d3bdbf6 100644 --- a/TBAnnotationClustering/TBCoordinateQuadTree.m +++ b/TBAnnotationClustering/TBCoordinateQuadTree.m @@ -101,7 +101,7 @@ - (void)buildTree } TBBoundingBox world = TBBoundingBoxMake(19, -166, 72, -53); - _root = TBQuadTreeBuildWithData(dataArray, count, world, 4); + _root = TBQuadTreeBuildWithData(dataArray, (int)count, world, 4); } } diff --git a/TBAnnotationClusteringTests/TBAnnotationClusteringTests-Info.plist b/TBAnnotationClusteringTests/TBAnnotationClusteringTests-Info.plist deleted file mode 100644 index 7e7af8d..0000000 --- a/TBAnnotationClusteringTests/TBAnnotationClusteringTests-Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIdentifier - thoughtbot.${PRODUCT_NAME:rfc1034identifier} - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - - diff --git a/TBAnnotationClusteringTests/TBAnnotationClusteringTests.m b/TBAnnotationClusteringTests/TBAnnotationClusteringTests.m deleted file mode 100644 index 6c5e0a2..0000000 --- a/TBAnnotationClusteringTests/TBAnnotationClusteringTests.m +++ /dev/null @@ -1,34 +0,0 @@ -// -// TBAnnotationClusteringTests.m -// TBAnnotationClusteringTests -// -// Created by Theodore Calmes on 9/27/13. -// Copyright (c) 2013 Theodore Calmes. All rights reserved. -// - -#import - -@interface TBAnnotationClusteringTests : XCTestCase - -@end - -@implementation TBAnnotationClusteringTests - -- (void)setUp -{ - [super setUp]; - // Put setup code here. This method is called before the invocation of each test method in the class. -} - -- (void)tearDown -{ - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; -} - -- (void)testExample -{ - XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); -} - -@end diff --git a/TBAnnotationClusteringTests/en.lproj/InfoPlist.strings b/TBAnnotationClusteringTests/en.lproj/InfoPlist.strings deleted file mode 100644 index 477b28f..0000000 --- a/TBAnnotationClusteringTests/en.lproj/InfoPlist.strings +++ /dev/null @@ -1,2 +0,0 @@ -/* Localized versions of Info.plist keys */ - diff --git a/TBBoundingBox.swift b/TBBoundingBox.swift new file mode 100644 index 0000000..4274544 --- /dev/null +++ b/TBBoundingBox.swift @@ -0,0 +1,33 @@ +// +// TBBoundingBox.swift +// TBAnnotationClustering-Swift +// +// Created by Eyal Darshan on 1/1/16. +// Copyright © 2016 eyaldar. All rights reserved. +// + +struct TBBoundingBox { + let x0:Double + let y0:Double + let xf:Double + let yf:Double + + init(x:Double, y:Double, xf:Double, yf:Double) { + self.x0 = x + self.y0 = y + self.xf = xf + self.yf = yf + } + + func containsData(data:TBQuadTreeNodeData) -> Bool { + let containsX = x0 <= data.x && data.x <= xf + let containsY = y0 <= data.y && data.y <= yf + + return containsX && containsY + } + + func intersectWith(other:TBBoundingBox) -> Bool { + return (x0 <= other.xf && xf >= other.x0) && + (y0 <= other.yf && yf >= other.y0) + } +} diff --git a/TBHotelInfo.swift b/TBHotelInfo.swift new file mode 100644 index 0000000..e49cec2 --- /dev/null +++ b/TBHotelInfo.swift @@ -0,0 +1,19 @@ +// +// TBHotelInfo.swift +// TBAnnotationClustering-Swift +// +// Created by Eyal Darshan on 1/1/16. +// Copyright © 2016 eyaldar. All rights reserved. +// + +import Foundation + +class TBHotelInfo : NSObject{ + let hotelName:String + let hotelPhoneNumber:String + + init(hotelName:String, hotelPhoneNumber:String) { + self.hotelName = hotelName + self.hotelPhoneNumber = hotelPhoneNumber + } +} \ No newline at end of file diff --git a/TBQuadTreeNode.swift b/TBQuadTreeNode.swift new file mode 100644 index 0000000..5d001f2 --- /dev/null +++ b/TBQuadTreeNode.swift @@ -0,0 +1,113 @@ +// +// TBQuadTreeNode.swift +// TBAnnotationClustering-Swift +// +// Created by Eyal Darshan on 1/1/16. +// Copyright © 2016 eyaldar. All rights reserved. +// + +import Foundation + +class TBQuadTreeNode { + var northWest:TBQuadTreeNode? + var northEast:TBQuadTreeNode? + var southWest:TBQuadTreeNode? + var southEast:TBQuadTreeNode? + var boundingBox:TBBoundingBox + var bucketCapacity:Int + var points = [TBQuadTreeNodeData]() + + init(boundary:TBBoundingBox, capacity:Int, dataArr:[TBQuadTreeNodeData]? = nil) { + self.boundingBox = boundary + self.bucketCapacity = capacity + + if let dataArr = dataArr { + for data in dataArr { + insertData(data) + } + } + } + + var isLeaf: Bool { + return (northWest == nil) + } + + func subdivide() { + let xMid = (boundingBox.xf + boundingBox.x0) / 2.0 + let yMid = (boundingBox.yf + boundingBox.y0) / 2.0 + + let northWestBox = TBBoundingBox(x: boundingBox.x0, y: boundingBox.y0, xf: xMid, yf: yMid) + northWest = TBQuadTreeNode(boundary: northWestBox, capacity: bucketCapacity) + + let northEastBox = TBBoundingBox(x: xMid, y: boundingBox.y0, xf: boundingBox.xf, yf: yMid) + northEast = TBQuadTreeNode(boundary: northEastBox, capacity: bucketCapacity) + + let southWestBox = TBBoundingBox(x: boundingBox.x0, y: yMid, xf: xMid, yf: boundingBox.yf) + southWest = TBQuadTreeNode(boundary: southWestBox, capacity: bucketCapacity) + + let southEastBox = TBBoundingBox(x: xMid, y: yMid, xf: boundingBox.xf, yf: boundingBox.yf) + southEast = TBQuadTreeNode(boundary: southEastBox, capacity: bucketCapacity) + } + + func insertData(data:TBQuadTreeNodeData) -> Bool { + // Bail if our coordinate is not inside the boundingBox + if !boundingBox.containsData(data) { + return false + } + + // Add the coordinate to the points array + if points.count < bucketCapacity { + points.append(data) + return true + } + + // Check to see if the current node is a leaf, in case it is, split + if isLeaf { + subdivide() + } + + // Traverse the tree + if northWest!.insertData(data) { return true } + if northEast!.insertData(data) { return true } + if southWest!.insertData(data) { return true } + if southEast!.insertData(data) { return true } + + return false + } + + func gatherDataInRange(range: TBBoundingBox, action: (TBQuadTreeNodeData) -> Void) { + // If range is not contained in the node's boundingBox then bail + if boundingBox.intersectWith(range) { + return + } + + for point in points { + if range.containsData(point) { + action(point) + } + } + + // If node isn't leaf traverse down the tree + if !isLeaf { + northWest!.gatherDataInRange(range, action: action) + northEast!.gatherDataInRange(range, action: action) + southWest!.gatherDataInRange(range, action: action) + southEast!.gatherDataInRange(range, action: action) + } + } + + func traverse(action: (TBQuadTreeNode) -> Void) { + action(self) + + if !isLeaf { + northWest!.traverse(action) + northEast!.traverse(action) + southWest!.traverse(action) + southEast!.traverse(action) + } + } + + class func buildWithData(boundary:TBBoundingBox, bucketCapacity:Int) { + + } +} diff --git a/TBQuadTreeNodeData.swift b/TBQuadTreeNodeData.swift new file mode 100644 index 0000000..22ff3f3 --- /dev/null +++ b/TBQuadTreeNodeData.swift @@ -0,0 +1,19 @@ +// +// TBQuadTreeNodeData.swift +// TBAnnotationClustering-Swift +// +// Created by Eyal Darshan on 1/1/16. +// Copyright © 2016 eyaldar. All rights reserved. +// + +struct TBQuadTreeNodeData { + let x:Double + let y:Double + let data:AnyObject + + init(x:Double, y:Double, data:AnyObject) { + self.x = x + self.y = y + self.data = data + } +} diff --git a/TBAnnotationClustering/USA-HotelMotel.csv b/USA-HotelMotel.csv similarity index 100% rename from TBAnnotationClustering/USA-HotelMotel.csv rename to USA-HotelMotel.csv From 35837cbbe7b9da8a070cd7245ade6b5ab6078272 Mon Sep 17 00:00:00 2001 From: eyaldar Date: Sat, 2 Jan 2016 01:09:37 +0200 Subject: [PATCH 2/8] Fixed performance problem caused by using dispatch_async instead of NSOperationQueue --- TBAnnotationClustering-Swift/ViewController.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TBAnnotationClustering-Swift/ViewController.swift b/TBAnnotationClustering-Swift/ViewController.swift index 49860ce..fa90841 100644 --- a/TBAnnotationClustering-Swift/ViewController.swift +++ b/TBAnnotationClustering-Swift/ViewController.swift @@ -43,7 +43,7 @@ class ViewController: UIViewController, MKMapViewDelegate { let toRemove = NSMutableSet(set: before) toRemove.minusSet(after as Set) - dispatch_async(dispatch_get_main_queue()) { () -> Void in + NSOperationQueue().addOperationWithBlock() { self.mapView.addAnnotations(toAdd.allObjects as! [MKAnnotation]) self.mapView.removeAnnotations(toRemove.allObjects as! [MKAnnotation]) } @@ -76,7 +76,7 @@ class ViewController: UIViewController, MKMapViewDelegate { } func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) { - dispatch_async(dispatch_get_main_queue()) { () -> Void in + NSOperationQueue().addOperationWithBlock() { let zoomScale = Double(self.mapView.bounds.size.width) / self.mapView.visibleMapRect.size.width let annotations = self.tbCoordinateQuadTree!.clusteredAnnotationWithinMapRect(mapView.visibleMapRect, zoomScale: MKZoomScale(zoomScale)) From 47ebb73374db6ef3860adc571e14ff262e65ad42 Mon Sep 17 00:00:00 2001 From: Eyal Darshan Date: Sat, 2 Jan 2016 01:11:46 +0200 Subject: [PATCH 3/8] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index bc19cb4..ef25769 100644 --- a/README.md +++ b/README.md @@ -10,3 +10,8 @@ If you want to grab the quad tree you can get it from my [GitHub](https://github or just install using cocoapods ```pod 'TBQuadTree', '~> 0.0'``` + +Swift Version +-------------- +A try to migrate the Objective-C code to Swift, which so far failed miserably. +This doesn't work yet - although all the code has been migrated, for some reason the gatherDataInRange method won't find anything. From 7f18f55417a21533bff6b052e5b31cf05b35d764 Mon Sep 17 00:00:00 2001 From: Eyal Darshan Date: Sat, 2 Jan 2016 03:03:04 +0200 Subject: [PATCH 4/8] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ef25769..f271c01 100644 --- a/README.md +++ b/README.md @@ -13,5 +13,5 @@ or just install using cocoapods Swift Version -------------- -A try to migrate the Objective-C code to Swift, which so far failed miserably. -This doesn't work yet - although all the code has been migrated, for some reason the gatherDataInRange method won't find anything. +Added a Swift version of the code as an attempt at playing with Swift and figuring out Objective-C code. +Note: this is not an exemplary Swift code, I'm still trying to figure out the best way past all this explict casting hell and might missed some memory management problems. From be4bdcd3d80e114c42ebb161e24a54a3ec2ea410 Mon Sep 17 00:00:00 2001 From: eyaldar Date: Sat, 2 Jan 2016 02:58:28 +0200 Subject: [PATCH 5/8] Fixed a bug where the opposite condition was used on gatherDataInRange, also fixed a couple of other minor bugs with color and details (waste two hours on that stupid opposite condition bug) --- .../UserInterfaceState.xcuserstate | Bin 32523 -> 34745 bytes .../xcdebugger/Breakpoints_v2.xcbkptlist | 18 ------------------ .../Base.lproj/LaunchScreen.storyboard | 6 +++--- .../TBClusterAnnotationView.swift | 6 +++++- .../TBCoordinateQuadTree.swift | 18 ++++++++---------- .../ViewController.swift | 2 +- .../UserInterfaceState.xcuserstate | Bin 20370 -> 24509 bytes TBBoundingBox.swift | 3 +-- TBQuadTreeNode.swift | 2 +- 9 files changed, 19 insertions(+), 36 deletions(-) diff --git a/TBAnnotationClustering-Swift.xcodeproj/project.xcworkspace/xcuserdata/Ran.xcuserdatad/UserInterfaceState.xcuserstate b/TBAnnotationClustering-Swift.xcodeproj/project.xcworkspace/xcuserdata/Ran.xcuserdatad/UserInterfaceState.xcuserstate index 8034bea275fe2381cea6583ed7bf9d5a33e792cd..384401db1fb7a8d2840135420364590fd7ad1aed 100644 GIT binary patch literal 34745 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�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 P7)yUG-1@HPv{nCqi~=|X literal 32523 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 - - - - - - diff --git a/TBAnnotationClustering-Swift/Base.lproj/LaunchScreen.storyboard b/TBAnnotationClustering-Swift/Base.lproj/LaunchScreen.storyboard index 2e721e1..342c1ee 100644 --- a/TBAnnotationClustering-Swift/Base.lproj/LaunchScreen.storyboard +++ b/TBAnnotationClustering-Swift/Base.lproj/LaunchScreen.storyboard @@ -1,7 +1,8 @@ - + - + + @@ -15,7 +16,6 @@ - diff --git a/TBAnnotationClustering-Swift/TBClusterAnnotationView.swift b/TBAnnotationClustering-Swift/TBClusterAnnotationView.swift index 57291f3..be89da6 100644 --- a/TBAnnotationClustering-Swift/TBClusterAnnotationView.swift +++ b/TBAnnotationClustering-Swift/TBClusterAnnotationView.swift @@ -20,6 +20,10 @@ class TBClusterAnnotationView: MKAnnotationView { super.init(coder: aDecoder) } + override init(frame: CGRect) { + super.init(frame: frame) + } + override init(annotation: MKAnnotation?, reuseIdentifier: String?) { super.init(annotation: annotation, reuseIdentifier: reuseIdentifier) @@ -90,6 +94,6 @@ class TBClusterAnnotationView: MKAnnotationView { CGContextStrokeEllipseInRect(context, circleFrame) innerCircleFillColor.setFill() - CGContextStrokeEllipseInRect(context, circleFrame) + CGContextFillEllipseInRect(context, circleFrame) } } diff --git a/TBAnnotationClustering-Swift/TBCoordinateQuadTree.swift b/TBAnnotationClustering-Swift/TBCoordinateQuadTree.swift index f68f797..cccfd5c 100644 --- a/TBAnnotationClustering-Swift/TBCoordinateQuadTree.swift +++ b/TBAnnotationClustering-Swift/TBCoordinateQuadTree.swift @@ -50,11 +50,9 @@ class TBCoordinateQuadTree : NSObject { totalX += data.x totalY += data.y - let hotelInfo = data.data - names.append(hotelInfo.name) - - if let phoneNum = hotelInfo.phoneNumber! { - phoneNumbers.append(phoneNum) + if let hotelInfo = data.data as? TBHotelInfo { + names.append(hotelInfo.hotelName) + phoneNumbers.append(hotelInfo.hotelPhoneNumber) } }) @@ -66,7 +64,7 @@ class TBCoordinateQuadTree : NSObject { clusteredAnnotations.append(annotation) } - if count > 1 { + if count == 1 { let coordinate = CLLocationCoordinate2D(latitude: totalX, longitude: totalY) let annotation = TBClusterAnnotation(coordinate: coordinate, count: count) annotation.title = names.last! @@ -92,10 +90,10 @@ class TBCoordinateQuadTree : NSObject { return TBBoundingBox(x: minLat, y: minLong, xf: maxLat, yf: maxLong) } - func TBZoomScaleToZoomLevel(scale:MKZoomScale) -> Double { - let totalTilesAtMaxZoom = MKMapSizeWorld.width / 256.0; - let zoomLevelAtMaxZoom = log2(totalTilesAtMaxZoom); - let zoomLevel = max(0, zoomLevelAtMaxZoom + floor(log2(Double(scale)) + 0.5)); + func TBZoomScaleToZoomLevel(scale:MKZoomScale) -> Int { + let totalTilesAtMaxZoom = MKMapSizeWorld.width / 256.0 + let zoomLevelAtMaxZoom = Int(log2(totalTilesAtMaxZoom)) + let zoomLevel = Int(max(0, Double(zoomLevelAtMaxZoom) + floor(log2(Double(scale)) + 0.5))); return zoomLevel; } diff --git a/TBAnnotationClustering-Swift/ViewController.swift b/TBAnnotationClustering-Swift/ViewController.swift index fa90841..4f299b2 100644 --- a/TBAnnotationClustering-Swift/ViewController.swift +++ b/TBAnnotationClustering-Swift/ViewController.swift @@ -43,7 +43,7 @@ class ViewController: UIViewController, MKMapViewDelegate { let toRemove = NSMutableSet(set: before) toRemove.minusSet(after as Set) - NSOperationQueue().addOperationWithBlock() { + NSOperationQueue.mainQueue().addOperationWithBlock() { self.mapView.addAnnotations(toAdd.allObjects as! [MKAnnotation]) self.mapView.removeAnnotations(toRemove.allObjects as! [MKAnnotation]) } diff --git a/TBAnnotationClustering.xcodeproj/project.xcworkspace/xcuserdata/Ran.xcuserdatad/UserInterfaceState.xcuserstate b/TBAnnotationClustering.xcodeproj/project.xcworkspace/xcuserdata/Ran.xcuserdatad/UserInterfaceState.xcuserstate index 9eef907edee5701fdbca2a1789323b16826dafb1..5b8a7845a6092937733aa858105c92efe3a7f9cc 100644 GIT binary patch literal 24509 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 lMfJ|=eboo54^>1O==Ub3aGjGwx9Z#8q4O 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 z Bool { - return (x0 <= other.xf && xf >= other.x0) && - (y0 <= other.yf && yf >= other.y0) + return x0 <= other.xf && xf >= other.x0 && y0 <= other.yf && yf >= other.y0 } } diff --git a/TBQuadTreeNode.swift b/TBQuadTreeNode.swift index 5d001f2..d6120f8 100644 --- a/TBQuadTreeNode.swift +++ b/TBQuadTreeNode.swift @@ -77,7 +77,7 @@ class TBQuadTreeNode { func gatherDataInRange(range: TBBoundingBox, action: (TBQuadTreeNodeData) -> Void) { // If range is not contained in the node's boundingBox then bail - if boundingBox.intersectWith(range) { + if !boundingBox.intersectWith(range) { return } From d32c232d389d9c2b9e9b981be8a440a159c28f78 Mon Sep 17 00:00:00 2001 From: Ran Ovadia Date: Sat, 2 Jan 2016 15:05:31 +0200 Subject: [PATCH 6/8] Moved misplaced files to the correct place, Added custom color for items, changed csv reader from ASCII to UTF8 --- .../project.pbxproj | 32 +++++++++--------- .../UserInterfaceState.xcuserstate | Bin 34745 -> 35653 bytes .../TBBoundingBox.swift | 0 .../TBClusterAnnotationView.swift | 5 ++- .../TBHotelCSVTreeBuilder.swift | 2 +- .../TBHotelInfo.swift | 0 .../TBQuadTreeNode.swift | 0 .../TBQuadTreeNodeData.swift | 0 .../UserInterfaceState.xcuserstate | Bin 24509 -> 24857 bytes 9 files changed, 21 insertions(+), 18 deletions(-) rename TBBoundingBox.swift => TBAnnotationClustering-Swift/TBBoundingBox.swift (100%) rename TBHotelInfo.swift => TBAnnotationClustering-Swift/TBHotelInfo.swift (100%) rename TBQuadTreeNode.swift => TBAnnotationClustering-Swift/TBQuadTreeNode.swift (100%) rename TBQuadTreeNodeData.swift => TBAnnotationClustering-Swift/TBQuadTreeNodeData.swift (100%) diff --git a/TBAnnotationClustering-Swift.xcodeproj/project.pbxproj b/TBAnnotationClustering-Swift.xcodeproj/project.pbxproj index 2f5b1f9..6873d76 100644 --- a/TBAnnotationClustering-Swift.xcodeproj/project.pbxproj +++ b/TBAnnotationClustering-Swift.xcodeproj/project.pbxproj @@ -7,23 +7,27 @@ objects = { /* Begin PBXBuildFile section */ + 2557EE9C1C3801B5001A8883 /* TBHotelInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2557EE9B1C3801B5001A8883 /* TBHotelInfo.swift */; }; + 2557EEA21C3801DC001A8883 /* TBBoundingBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2557EE9F1C3801DC001A8883 /* TBBoundingBox.swift */; }; + 2557EEA31C3801DC001A8883 /* TBQuadTreeNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2557EEA01C3801DC001A8883 /* TBQuadTreeNode.swift */; }; + 2557EEA41C3801DC001A8883 /* TBQuadTreeNodeData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2557EEA11C3801DC001A8883 /* TBQuadTreeNodeData.swift */; }; 257D9E021C36DA57004B0025 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257D9E011C36DA57004B0025 /* AppDelegate.swift */; }; 257D9E041C36DA57004B0025 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257D9E031C36DA57004B0025 /* ViewController.swift */; }; 257D9E071C36DA57004B0025 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 257D9E051C36DA57004B0025 /* Main.storyboard */; }; 257D9E091C36DA57004B0025 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 257D9E081C36DA57004B0025 /* Assets.xcassets */; }; 257D9E0C1C36DA57004B0025 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 257D9E0A1C36DA57004B0025 /* LaunchScreen.storyboard */; }; - 257D9E151C36E095004B0025 /* TBQuadTreeNodeData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257D9E141C36E095004B0025 /* TBQuadTreeNodeData.swift */; }; - 257D9E171C36E1FA004B0025 /* TBBoundingBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257D9E161C36E1FA004B0025 /* TBBoundingBox.swift */; }; - 257D9E191C36E3D4004B0025 /* TBQuadTreeNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257D9E181C36E3D4004B0025 /* TBQuadTreeNode.swift */; }; 257D9E1C1C36F59D004B0025 /* USA-HotelMotel.csv in Resources */ = {isa = PBXBuildFile; fileRef = 257D9E1B1C36F59D004B0025 /* USA-HotelMotel.csv */; }; 257D9E211C36F72A004B0025 /* TBHotelCSVTreeBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257D9E201C36F72A004B0025 /* TBHotelCSVTreeBuilder.swift */; }; - 257D9E241C36F762004B0025 /* TBHotelInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257D9E231C36F762004B0025 /* TBHotelInfo.swift */; }; 257D9E261C370377004B0025 /* TBCoordinateQuadTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257D9E251C370377004B0025 /* TBCoordinateQuadTree.swift */; }; 257D9E281C371038004B0025 /* TBClusterAnnotation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257D9E271C371038004B0025 /* TBClusterAnnotation.swift */; }; 257D9E2A1C371CD6004B0025 /* TBClusterAnnotationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257D9E291C371CD6004B0025 /* TBClusterAnnotationView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 2557EE9B1C3801B5001A8883 /* TBHotelInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TBHotelInfo.swift; path = "TBAnnotationClustering-Swift/TBHotelInfo.swift"; sourceTree = ""; }; + 2557EE9F1C3801DC001A8883 /* TBBoundingBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TBBoundingBox.swift; path = "TBAnnotationClustering-Swift/TBBoundingBox.swift"; sourceTree = ""; }; + 2557EEA01C3801DC001A8883 /* TBQuadTreeNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TBQuadTreeNode.swift; path = "TBAnnotationClustering-Swift/TBQuadTreeNode.swift"; sourceTree = ""; }; + 2557EEA11C3801DC001A8883 /* TBQuadTreeNodeData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TBQuadTreeNodeData.swift; path = "TBAnnotationClustering-Swift/TBQuadTreeNodeData.swift"; sourceTree = ""; }; 257D9DFE1C36DA57004B0025 /* TBAnnotationClustering-Swift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "TBAnnotationClustering-Swift.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 257D9E011C36DA57004B0025 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 257D9E031C36DA57004B0025 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; @@ -31,12 +35,8 @@ 257D9E081C36DA57004B0025 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = "TBAnnotationClustering-Swift/Assets.xcassets"; sourceTree = ""; }; 257D9E0B1C36DA57004B0025 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 257D9E0D1C36DA57004B0025 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = "TBAnnotationClustering-Swift/Info.plist"; sourceTree = ""; }; - 257D9E141C36E095004B0025 /* TBQuadTreeNodeData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TBQuadTreeNodeData.swift; sourceTree = ""; }; - 257D9E161C36E1FA004B0025 /* TBBoundingBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TBBoundingBox.swift; sourceTree = ""; }; - 257D9E181C36E3D4004B0025 /* TBQuadTreeNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TBQuadTreeNode.swift; sourceTree = ""; }; 257D9E1B1C36F59D004B0025 /* USA-HotelMotel.csv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "USA-HotelMotel.csv"; sourceTree = ""; }; 257D9E201C36F72A004B0025 /* TBHotelCSVTreeBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TBHotelCSVTreeBuilder.swift; path = "TBAnnotationClustering-Swift/TBHotelCSVTreeBuilder.swift"; sourceTree = ""; }; - 257D9E231C36F762004B0025 /* TBHotelInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TBHotelInfo.swift; sourceTree = ""; }; 257D9E251C370377004B0025 /* TBCoordinateQuadTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TBCoordinateQuadTree.swift; sourceTree = ""; }; 257D9E271C371038004B0025 /* TBClusterAnnotation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TBClusterAnnotation.swift; sourceTree = ""; }; 257D9E291C371CD6004B0025 /* TBClusterAnnotationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TBClusterAnnotationView.swift; sourceTree = ""; }; @@ -89,9 +89,9 @@ 257D9E131C36E048004B0025 /* Data Structures */ = { isa = PBXGroup; children = ( - 257D9E141C36E095004B0025 /* TBQuadTreeNodeData.swift */, - 257D9E161C36E1FA004B0025 /* TBBoundingBox.swift */, - 257D9E181C36E3D4004B0025 /* TBQuadTreeNode.swift */, + 2557EE9F1C3801DC001A8883 /* TBBoundingBox.swift */, + 2557EEA01C3801DC001A8883 /* TBQuadTreeNode.swift */, + 2557EEA11C3801DC001A8883 /* TBQuadTreeNodeData.swift */, ); name = "Data Structures"; sourceTree = ""; @@ -109,8 +109,8 @@ 257D9E221C36F742004B0025 /* Hotel Data */ = { isa = PBXGroup; children = ( + 2557EE9B1C3801B5001A8883 /* TBHotelInfo.swift */, 257D9E201C36F72A004B0025 /* TBHotelCSVTreeBuilder.swift */, - 257D9E231C36F762004B0025 /* TBHotelInfo.swift */, ); name = "Hotel Data"; sourceTree = ""; @@ -189,14 +189,14 @@ buildActionMask = 2147483647; files = ( 257D9E211C36F72A004B0025 /* TBHotelCSVTreeBuilder.swift in Sources */, - 257D9E191C36E3D4004B0025 /* TBQuadTreeNode.swift in Sources */, 257D9E2A1C371CD6004B0025 /* TBClusterAnnotationView.swift in Sources */, - 257D9E241C36F762004B0025 /* TBHotelInfo.swift in Sources */, 257D9E041C36DA57004B0025 /* ViewController.swift in Sources */, 257D9E021C36DA57004B0025 /* AppDelegate.swift in Sources */, + 2557EE9C1C3801B5001A8883 /* TBHotelInfo.swift in Sources */, + 2557EEA31C3801DC001A8883 /* TBQuadTreeNode.swift in Sources */, + 2557EEA21C3801DC001A8883 /* TBBoundingBox.swift in Sources */, 257D9E261C370377004B0025 /* TBCoordinateQuadTree.swift in Sources */, - 257D9E151C36E095004B0025 /* TBQuadTreeNodeData.swift in Sources */, - 257D9E171C36E1FA004B0025 /* TBBoundingBox.swift in Sources */, + 2557EEA41C3801DC001A8883 /* TBQuadTreeNodeData.swift in Sources */, 257D9E281C371038004B0025 /* TBClusterAnnotation.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/TBAnnotationClustering-Swift.xcodeproj/project.xcworkspace/xcuserdata/Ran.xcuserdatad/UserInterfaceState.xcuserstate b/TBAnnotationClustering-Swift.xcodeproj/project.xcworkspace/xcuserdata/Ran.xcuserdatad/UserInterfaceState.xcuserstate index 384401db1fb7a8d2840135420364590fd7ad1aed..a03a3c73ec6b4a6483a7c363c84922eaf93068ee 100644 GIT binary patch delta 16960 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 Ll(Rp4HJ1H9VvCB4 diff --git a/TBBoundingBox.swift b/TBAnnotationClustering-Swift/TBBoundingBox.swift similarity index 100% rename from TBBoundingBox.swift rename to TBAnnotationClustering-Swift/TBBoundingBox.swift diff --git a/TBAnnotationClustering-Swift/TBClusterAnnotationView.swift b/TBAnnotationClustering-Swift/TBClusterAnnotationView.swift index be89da6..959ea87 100644 --- a/TBAnnotationClustering-Swift/TBClusterAnnotationView.swift +++ b/TBAnnotationClustering-Swift/TBClusterAnnotationView.swift @@ -81,7 +81,10 @@ class TBClusterAnnotationView: MKAnnotationView { let outerCircleStrokeColor = UIColor(white: 0, alpha: 0.25) let innerCircleStrokeColor = UIColor.whiteColor() - let innerCircleFillColor = UIColor(red: (255.0 / 255.0), green: (95.0 / 255.0), blue: (42.0 / 255.0), alpha: 1.0) + var innerCircleFillColor = UIColor(red: (255.0 / 255.0), green: (95.0 / 255.0), blue: (42.0 / 255.0), alpha: 1.0) + if(count == 1) { + innerCircleFillColor = UIColor(red: (95.0 / 255.0), green: (150.0 / 255.0), blue: (42.0 / 255.0), alpha: 1.0) + } let circleFrame = CGRectInset(rect, 4, 4) diff --git a/TBAnnotationClustering-Swift/TBHotelCSVTreeBuilder.swift b/TBAnnotationClustering-Swift/TBHotelCSVTreeBuilder.swift index 7282400..d87b1f5 100644 --- a/TBAnnotationClustering-Swift/TBHotelCSVTreeBuilder.swift +++ b/TBAnnotationClustering-Swift/TBHotelCSVTreeBuilder.swift @@ -45,7 +45,7 @@ class TBHotelCSVTreeBuilder { var data = "" do { - data = try String(contentsOfFile: path, encoding: NSASCIIStringEncoding) + data = try String(contentsOfFile: path, encoding: NSUTF8StringEncoding) } catch {} return data diff --git a/TBHotelInfo.swift b/TBAnnotationClustering-Swift/TBHotelInfo.swift similarity index 100% rename from TBHotelInfo.swift rename to TBAnnotationClustering-Swift/TBHotelInfo.swift diff --git a/TBQuadTreeNode.swift b/TBAnnotationClustering-Swift/TBQuadTreeNode.swift similarity index 100% rename from TBQuadTreeNode.swift rename to TBAnnotationClustering-Swift/TBQuadTreeNode.swift diff --git a/TBQuadTreeNodeData.swift b/TBAnnotationClustering-Swift/TBQuadTreeNodeData.swift similarity index 100% rename from TBQuadTreeNodeData.swift rename to TBAnnotationClustering-Swift/TBQuadTreeNodeData.swift diff --git a/TBAnnotationClustering.xcodeproj/project.xcworkspace/xcuserdata/Ran.xcuserdatad/UserInterfaceState.xcuserstate b/TBAnnotationClustering.xcodeproj/project.xcworkspace/xcuserdata/Ran.xcuserdatad/UserInterfaceState.xcuserstate index 5b8a7845a6092937733aa858105c92efe3a7f9cc..7f379f5de7025c1cb0cbcf2f3adb92e36c0a8469 100644 GIT binary patch delta 12765 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 XTPwGFUxNUIe4p$F-)Gm~${qh7+PZ19 delta 12591 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 kCC5unmYnI(zC*7L6&(h8u2T^5e6k Date: Sat, 2 Jan 2016 17:15:15 +0200 Subject: [PATCH 7/8] Now the quad tree includes the whole world, and intersection works for all parts of the world --- TBAnnotationClustering-Swift/TBBoundingBox.swift | 14 +++++++++++++- TBAnnotationClustering-Swift/ViewController.swift | 2 +- TBAnnotationClustering/TBCoordinateQuadTree.m | 4 ++-- TBAnnotationClustering/TBQuadTree.h | 2 ++ TBAnnotationClustering/TBQuadTree.m | 6 +++++- 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/TBAnnotationClustering-Swift/TBBoundingBox.swift b/TBAnnotationClustering-Swift/TBBoundingBox.swift index de61a13..ce10c3b 100644 --- a/TBAnnotationClustering-Swift/TBBoundingBox.swift +++ b/TBAnnotationClustering-Swift/TBBoundingBox.swift @@ -11,12 +11,22 @@ struct TBBoundingBox { let y0:Double let xf:Double let yf:Double + + private let height:Double + private let width:Double + private let centerX:Double + private let centerY:Double init(x:Double, y:Double, xf:Double, yf:Double) { self.x0 = x self.y0 = y self.xf = xf self.yf = yf + + height = abs(yf - y0) + width = abs(xf - x0) + centerX = x0 + (width / 2) + centerY = y0 + (height / 2) } func containsData(data:TBQuadTreeNodeData) -> Bool { @@ -27,6 +37,8 @@ struct TBBoundingBox { } func intersectWith(other:TBBoundingBox) -> Bool { - return x0 <= other.xf && xf >= other.x0 && y0 <= other.yf && yf >= other.y0 + let intersectsX = abs(centerX - other.centerX) * 2 < (width + other.width) + let intersectsY = abs(centerY - other.centerY) * 2 < (height + other.height) + return intersectsX && intersectsY } } diff --git a/TBAnnotationClustering-Swift/ViewController.swift b/TBAnnotationClustering-Swift/ViewController.swift index 4f299b2..200cae4 100644 --- a/TBAnnotationClustering-Swift/ViewController.swift +++ b/TBAnnotationClustering-Swift/ViewController.swift @@ -16,7 +16,7 @@ class ViewController: UIViewController, MKMapViewDelegate { let TBAnnotatioViewReuseID = "TBAnnotatioViewReuseID" // DEFINE THE TREE'S BOUNDS: - let world = TBBoundingBox(x: 19, y: -166, xf: 72, yf:-53)// x: 90, y: 180, xf: -90, yf: -180) + let world = TBBoundingBox(x: -90, y: -180, xf: 90, yf: 180) let hotelTreeBuilder = TBHotelCSVTreeBuilder() var tbCoordinateQuadTree:TBCoordinateQuadTree? diff --git a/TBAnnotationClustering/TBCoordinateQuadTree.m b/TBAnnotationClustering/TBCoordinateQuadTree.m index d3bdbf6..81b65af 100644 --- a/TBAnnotationClustering/TBCoordinateQuadTree.m +++ b/TBAnnotationClustering/TBCoordinateQuadTree.m @@ -90,7 +90,7 @@ @implementation TBCoordinateQuadTree - (void)buildTree { @autoreleasepool { - NSString *data = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"USA-HotelMotel" ofType:@"csv"] encoding:NSASCIIStringEncoding error:nil]; + NSString *data = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"USA-HotelMotel" ofType:@"csv"] encoding:NSUTF8StringEncoding error:nil]; NSArray *lines = [data componentsSeparatedByString:@"\n"]; NSInteger count = lines.count - 1; @@ -100,7 +100,7 @@ - (void)buildTree dataArray[i] = TBDataFromLine(lines[i]); } - TBBoundingBox world = TBBoundingBoxMake(19, -166, 72, -53); + TBBoundingBox world = TBBoundingBoxMake(-90, -180, 90, 180); _root = TBQuadTreeBuildWithData(dataArray, (int)count, world, 4); } } diff --git a/TBAnnotationClustering/TBQuadTree.h b/TBAnnotationClustering/TBQuadTree.h index a738ff3..f48cbde 100644 --- a/TBAnnotationClustering/TBQuadTree.h +++ b/TBAnnotationClustering/TBQuadTree.h @@ -18,6 +18,8 @@ TBQuadTreeNodeData TBQuadTreeNodeDataMake(double x, double y, void* data); typedef struct TBBoundingBox { double x0; double y0; double xf; double yf; + double centerX; double centerY; + double width; double height; } TBBoundingBox; TBBoundingBox TBBoundingBoxMake(double x0, double y0, double xf, double yf); diff --git a/TBAnnotationClustering/TBQuadTree.m b/TBAnnotationClustering/TBQuadTree.m index 842d443..ed4d508 100644 --- a/TBAnnotationClustering/TBQuadTree.m +++ b/TBAnnotationClustering/TBQuadTree.m @@ -19,6 +19,8 @@ TBQuadTreeNodeData TBQuadTreeNodeDataMake(double x, double y, void* data) TBBoundingBox TBBoundingBoxMake(double x0, double y0, double xf, double yf) { TBBoundingBox bb; bb.x0 = x0; bb.y0 = y0; bb.xf = xf; bb.yf = yf; + bb.width = fabs(xf - x0); bb.height = fabs(yf - y0); + bb.centerX = x0 + (bb.width / 2); bb.centerY = x0 + (bb.height / 2); return bb; } @@ -50,7 +52,9 @@ bool TBBoundingBoxContainsData(TBBoundingBox box, TBQuadTreeNodeData data) bool TBBoundingBoxIntersectsBoundingBox(TBBoundingBox b1, TBBoundingBox b2) { - return (b1.x0 <= b2.xf && b1.xf >= b2.x0 && b1.y0 <= b2.yf && b1.yf >= b2.y0); + bool intersectsX = fabs(b1.centerX - b2.centerX) * 2 < (b1.width + b2.width); + bool intersectsY = fabs(b1.centerY - b2.centerY) * 2 < (b1.height + b2.height); + return intersectsX && intersectsY; } #pragma mark - Quad Tree Functions From fbbd7a81200c15bb5b1893a3b264bca376c19588 Mon Sep 17 00:00:00 2001 From: eyaldar Date: Sat, 2 Jan 2016 18:50:56 +0200 Subject: [PATCH 8/8] Added comment to better explain the formula behind the scale of the annotationView --- TBAnnotationClustering-Swift/TBClusterAnnotationView.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/TBAnnotationClustering-Swift/TBClusterAnnotationView.swift b/TBAnnotationClustering-Swift/TBClusterAnnotationView.swift index 959ea87..02ef5ce 100644 --- a/TBAnnotationClustering-Swift/TBClusterAnnotationView.swift +++ b/TBAnnotationClustering-Swift/TBClusterAnnotationView.swift @@ -33,6 +33,7 @@ class TBClusterAnnotationView: MKAnnotationView { } func TBScaledValueForValue(value:Float, multiplier:Float) -> Float { + // Multiplier * (1/e^(-Alpha * X^(Beta))) return multiplier * (1.0 / (1.0 + expf(-1 * TBScaleFactorAlpha * powf(value, TBScaleFactorBeta)))) }