Commit 44e7a2e8 authored by Robin's avatar Robin
Browse files

v1.4.12

- Sample for "POI Along The Route" API wrapper is added. API wrapper for "POI Along The Route" was released in version number 1.4.8 of `MapmyIndiaAPIKit`.
No related merge requests found
Showing with 271 additions and 437 deletions
+271 -437
# Changes to the MapmyIndia's Sample for available iOS SDKs
## 1.4.12 - 08 June, 2020
### Added
- Sample for "POI Along The Route" API wrapper is added. API wrapper for "POI Along The Route" was released in version number 1.4.8 of `MapmyIndiaAPIKit`.
### Changed
- Polyline file is removed from project to use it directly through `Polyline` library.
## 1.4.11 - 03 Sep, 2020
### Added
- Sample for Place Picker is added with settings page to check configuration of Place Picker at run time.
### Fixed
- Map SDK update for managing Global session.
- Map SDK update with version 5.7.10 to fix issue of memory consumption.
- Option to choose example of "Covid 19 Layers" was not exists in list of samples.
- README file is updated for version related and other information.
## 1.4.10 - 18 June, 2020
### Added
- A sample is added to demonstrate feature to show safety status on map.
## 1.4.9 - 08 June, 2020
### Added
- A sample is added in demo project to show interactive layers on map based on updated SDKs.
## 1.4.8 - 05 June, 2020
### Updated
- README file updated for updated information.
## 1.4.7 - 03 June, 2020
#### Fixed
- Made SDKs compatible to Xcode 11.5.
## 1.4.6 - 13 May, 2020
#### Changed
......
......@@ -47,12 +47,12 @@
18E87E4B21400FE700F1C866 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18E87E4621400FE700F1C866 /* Extensions.swift */; };
18E87E4E2140100300F1C866 /* Image.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 18E87E4D2140100300F1C866 /* Image.xcassets */; };
18E87E502140100F00F1C866 /* MapmyIndiaFeedbackUIKitManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18E87E4F2140100F00F1C866 /* MapmyIndiaFeedbackUIKitManager.swift */; };
18EF185E250A03EE0067182A /* POIsAlongTheRouteVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18EF185D250A03EE0067182A /* POIsAlongTheRouteVC.swift */; };
18F576D023FEA83B0009A2D9 /* TextInstructions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18F576CF23FEA83B0009A2D9 /* TextInstructions.swift */; };
18F576D223FEAA880009A2D9 /* TextInstructions.plist in Resources */ = {isa = PBXBuildFile; fileRef = 18F576D123FEAA880009A2D9 /* TextInstructions.plist */; };
68417CC5210B329100424A00 /* InitialVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68417CC4210B329100424A00 /* InitialVC.swift */; };
68417CC7210B32A700424A00 /* ListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68417CC6210B32A700424A00 /* ListVC.swift */; };
68417CCD210B48FB00424A00 /* MainC.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 68417CCC210B48FB00424A00 /* MainC.storyboard */; };
6844DDB921116907007FCD61 /* Polyline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6844DDB721116907007FCD61 /* Polyline.swift */; };
68534685210EDF59000ED395 /* ListVCOC.m in Sources */ = {isa = PBXBuildFile; fileRef = 68534684210EDF59000ED395 /* ListVCOC.m */; };
6853468A210EF14B000ED395 /* mapVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68534689210EF14B000ED395 /* mapVC.swift */; };
6853468D210EF161000ED395 /* mapVCOC.m in Sources */ = {isa = PBXBuildFile; fileRef = 6853468C210EF161000ED395 /* mapVCOC.m */; };
......@@ -165,14 +165,13 @@
18E87E4621400FE700F1C866 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
18E87E4D2140100300F1C866 /* Image.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Image.xcassets; sourceTree = "<group>"; };
18E87E4F2140100F00F1C866 /* MapmyIndiaFeedbackUIKitManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapmyIndiaFeedbackUIKitManager.swift; sourceTree = "<group>"; };
18EF185D250A03EE0067182A /* POIsAlongTheRouteVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = POIsAlongTheRouteVC.swift; sourceTree = "<group>"; };
18F576CF23FEA83B0009A2D9 /* TextInstructions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextInstructions.swift; sourceTree = "<group>"; };
18F576D123FEAA880009A2D9 /* TextInstructions.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = TextInstructions.plist; sourceTree = "<group>"; };
68417CC4210B329100424A00 /* InitialVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitialVC.swift; sourceTree = "<group>"; };
68417CC6210B32A700424A00 /* ListVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListVC.swift; sourceTree = "<group>"; };
68417CC8210B330D00424A00 /* MapDemo-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MapDemo-Bridging-Header.h"; sourceTree = "<group>"; };
68417CCC210B48FB00424A00 /* MainC.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = MainC.storyboard; sourceTree = "<group>"; };
6844DDB621116907007FCD61 /* Polyline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Polyline.h; sourceTree = "<group>"; };
6844DDB721116907007FCD61 /* Polyline.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Polyline.swift; sourceTree = "<group>"; };
68534683210EDF59000ED395 /* ListVCOC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ListVCOC.h; sourceTree = "<group>"; };
68534684210EDF59000ED395 /* ListVCOC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ListVCOC.m; sourceTree = "<group>"; };
68534689210EF14B000ED395 /* mapVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = mapVC.swift; sourceTree = "<group>"; };
......@@ -362,19 +361,11 @@
186D0209248E25F4006F1C84 /* CovidLayersExample.swift */,
186D020A248E25F4006F1C84 /* CovidLayersTableVC.swift */,
185A74ED249B4C5300081DAE /* CovidSafetyStatusExample.swift */,
18EF185D250A03EE0067182A /* POIsAlongTheRouteVC.swift */,
);
path = Swift;
sourceTree = "<group>";
};
6844DDB521116907007FCD61 /* Polyline */ = {
isa = PBXGroup;
children = (
6844DDB621116907007FCD61 /* Polyline.h */,
6844DDB721116907007FCD61 /* Polyline.swift */,
);
path = Polyline;
sourceTree = "<group>";
};
68A6BF0A2106E03C00547929 = {
isa = PBXGroup;
children = (
......@@ -401,7 +392,6 @@
children = (
18F576CE23FEA8100009A2D9 /* InstructionFormatterHelpers */,
185B7FBD214B8333000785FC /* metro-line.geojson */,
6844DDB521116907007FCD61 /* Polyline */,
68417CC3210B2DCE00424A00 /* Swift */,
68417CC2210B2DB800424A00 /* Objective C */,
68A6BF162106E03C00547929 /* AppDelegate.swift */,
......@@ -557,6 +547,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
18EF185E250A03EE0067182A /* POIsAlongTheRouteVC.swift in Sources */,
18778C5A24756C47006DE478 /* MultiplePolylinesExample.swift in Sources */,
186D020C248E25F4006F1C84 /* CovidLayersTableVC.swift in Sources */,
188AE97A21C7D92C00D2C866 /* CustomCalloutView.swift in Sources */,
......@@ -601,7 +592,6 @@
186D0212248E266F006F1C84 /* CovidLayersExample.m in Sources */,
185B7FC3214B848F000785FC /* MultipleShapesExample.m in Sources */,
18778C582475435C006DE478 /* UpdateCircleExample.swift in Sources */,
6844DDB921116907007FCD61 /* Polyline.swift in Sources */,
68A6BF172106E03C00547929 /* AppDelegate.swift in Sources */,
185A74F1249B4C7C00081DAE /* CovidSafetyStatusExample.m in Sources */,
6853468A210EF14B000ED395 /* mapVC.swift in Sources */,
......@@ -836,7 +826,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 21;
CURRENT_PROJECT_VERSION = 22;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 22L95D5KTZ;
FRAMEWORK_SEARCH_PATHS = (
......@@ -851,7 +841,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.4.11;
MARKETING_VERSION = 1.4.12;
PRODUCT_BUNDLE_IDENTIFIER = com.mmi.MapDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "MapDemo/Objective C/MapDemo-Bridging-Header.h";
......@@ -867,7 +857,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 21;
CURRENT_PROJECT_VERSION = 22;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 22L95D5KTZ;
FRAMEWORK_SEARCH_PATHS = (
......@@ -882,7 +872,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.4.11;
MARKETING_VERSION = 1.4.12;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.mmi.MapDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
......
// The MIT License (MIT)
//
// Copyright (c) 2015 Raphaël Mor
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#import <Foundation/Foundation.h>
// ! Project version number for Polyline.
FOUNDATION_EXPORT double PolylineVersionNumber;
// ! Project version string for Polyline.
FOUNDATION_EXPORT const unsigned char PolylineVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <Polyline/PublicHeader.h>
\ No newline at end of file
// Polyline.swift
//
// Copyright (c) 2015 Raphaël Mor
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import Foundation
import CoreLocation
import MapKit
// MARK: - Public Classes -
/// This class can be used for :
///
/// - Encoding an [CLLocation] or a [CLLocationCoordinate2D] to a polyline String
/// - Decoding a polyline String to an [CLLocation] or a [CLLocationCoordinate2D]
/// - Encoding / Decoding associated levels
///
/// it is aims to produce the same results as google's iOS sdk not as the online
/// tool which is fuzzy when it comes to rounding values
///
/// it is based on google's algorithm that can be found here :
///
/// :see: https://developers.google.com/maps/documentation/utilities/polylinealgorithm
public struct Polyline {
/// The array of coordinates (nil if polyline cannot be decoded)
public let coordinates: [CLLocationCoordinate2D]?
/// The encoded polyline
public let encodedPolyline: String
/// The array of levels (nil if cannot be decoded, or is not provided)
public let levels: [UInt32]?
/// The encoded levels (nil if cannot be encoded, or is not provided)
public let encodedLevels: String?
/// The array of location (computed from coordinates)
public var locations: [CLLocation]? {
return self.coordinates.map(toLocations)
}
#if !os(watchOS)
/// Convert polyline to MKPolyline to use with MapKit (nil if polyline cannot be decoded)
@available(tvOS 9.2, *)
public var mkPolyline: MKPolyline? {
guard let coordinates = self.coordinates else { return nil }
let mkPolyline = MKPolyline(coordinates: coordinates, count: coordinates.count)
return mkPolyline
}
#endif
// MARK: - Public Methods -
/// This designated initializer encodes a `[CLLocationCoordinate2D]`
///
/// - parameter coordinates: The `Array` of `CLLocationCoordinate2D` that you want to encode
/// - parameter levels: The optional `Array` of levels that you want to encode (default: `nil`)
/// - parameter precision: The precision used for encoding (default: `1e5`)
public init(coordinates: [CLLocationCoordinate2D], levels: [UInt32]? = nil, precision: Double = 1e5) {
self.coordinates = coordinates
self.levels = levels
encodedPolyline = encodeCoordinates(coordinates, precision: precision)
encodedLevels = levels.map(encodeLevels)
}
/// This designated initializer decodes a polyline `String`
///
/// - parameter encodedPolyline: The polyline that you want to decode
/// - parameter encodedLevels: The levels that you want to decode (default: `nil`)
/// - parameter precision: The precision used for decoding (default: `1e5`)
public init(encodedPolyline: String, encodedLevels: String? = nil, precision: Double = 1e5) {
self.encodedPolyline = encodedPolyline
self.encodedLevels = encodedLevels
coordinates = decodePolyline(encodedPolyline, precision: precision)
levels = self.encodedLevels.flatMap(decodeLevels)
}
/// This init encodes a `[CLLocation]`
///
/// - parameter locations: The `Array` of `CLLocation` that you want to encode
/// - parameter levels: The optional array of levels that you want to encode (default: `nil`)
/// - parameter precision: The precision used for encoding (default: `1e5`)
public init(locations: [CLLocation], levels: [UInt32]? = nil, precision: Double = 1e5) {
let coordinates = toCoordinates(locations)
self.init(coordinates: coordinates, levels: levels, precision:precision)
}
}
// MARK: - Public Functions -
/// This function encodes an `[CLLocationCoordinate2D]` to a `String`
///
/// - parameter coordinates: The `Array` of `CLLocationCoordinate2D` that you want to encode
/// - parameter precision: The precision used to encode coordinates (default: `1e5`)
///
/// - returns: A `String` representing the encoded Polyline
public func encodeCoordinates(_ coordinates: [CLLocationCoordinate2D], precision: Double = 1e5) -> String {
var previousCoordinate = IntegerCoordinates(0, 0)
var encodedPolyline = ""
for coordinate in coordinates {
let intLatitude = Int(round(coordinate.latitude * precision))
let intLongitude = Int(round(coordinate.longitude * precision))
let coordinatesDifference = (intLatitude - previousCoordinate.latitude, intLongitude - previousCoordinate.longitude)
encodedPolyline += encodeCoordinate(coordinatesDifference)
previousCoordinate = (intLatitude,intLongitude)
}
return encodedPolyline
}
/// This function encodes an `[CLLocation]` to a `String`
///
/// - parameter coordinates: The `Array` of `CLLocation` that you want to encode
/// - parameter precision: The precision used to encode locations (default: `1e5`)
///
/// - returns: A `String` representing the encoded Polyline
public func encodeLocations(_ locations: [CLLocation], precision: Double = 1e5) -> String {
return encodeCoordinates(toCoordinates(locations), precision: precision)
}
/// This function encodes an `[UInt32]` to a `String`
///
/// - parameter levels: The `Array` of `UInt32` levels that you want to encode
///
/// - returns: A `String` representing the encoded Levels
public func encodeLevels(_ levels: [UInt32]) -> String {
return levels.reduce("") {
$0 + encodeLevel($1)
}
}
/// This function decodes a `String` to a `[CLLocationCoordinate2D]?`
///
/// - parameter encodedPolyline: `String` representing the encoded Polyline
/// - parameter precision: The precision used to decode coordinates (default: `1e5`)
///
/// - returns: A `[CLLocationCoordinate2D]` representing the decoded polyline if valid, `nil` otherwise
public func decodePolyline(_ encodedPolyline: String, precision: Double = 1e5) -> [CLLocationCoordinate2D]? {
let data = encodedPolyline.data(using: String.Encoding.utf8)!
let byteArray = (data as NSData).bytes.assumingMemoryBound(to: Int8.self)
let length = Int(data.count)
var position = Int(0)
var decodedCoordinates = [CLLocationCoordinate2D]()
var lat = 0.0
var lon = 0.0
while position < length {
do {
let resultingLat = try decodeSingleCoordinate(byteArray: byteArray, length: length, position: &position, precision: precision)
lat += resultingLat
let resultingLon = try decodeSingleCoordinate(byteArray: byteArray, length: length, position: &position, precision: precision)
lon += resultingLon
} catch {
return nil
}
decodedCoordinates.append(CLLocationCoordinate2D(latitude: lat, longitude: lon))
}
return decodedCoordinates
}
/// This function decodes a String to a [CLLocation]?
///
/// - parameter encodedPolyline: String representing the encoded Polyline
/// - parameter precision: The precision used to decode locations (default: 1e5)
///
/// - returns: A [CLLocation] representing the decoded polyline if valid, nil otherwise
public func decodePolyline(_ encodedPolyline: String, precision: Double = 1e5) -> [CLLocation]? {
return decodePolyline(encodedPolyline, precision: precision).map(toLocations)
}
/// This function decodes a `String` to an `[UInt32]`
///
/// - parameter encodedLevels: The `String` representing the levels to decode
///
/// - returns: A `[UInt32]` representing the decoded Levels if the `String` is valid, `nil` otherwise
public func decodeLevels(_ encodedLevels: String) -> [UInt32]? {
var remainingLevels = encodedLevels.unicodeScalars
var decodedLevels = [UInt32]()
while remainingLevels.count > 0 {
do {
let chunk = try extractNextChunk(&remainingLevels)
let level = decodeLevel(chunk)
decodedLevels.append(level)
} catch {
return nil
}
}
return decodedLevels
}
// MARK: - Private -
// MARK: Encode Coordinate
private func encodeCoordinate(_ locationCoordinate: IntegerCoordinates) -> String {
let latitudeString = encodeSingleComponent(locationCoordinate.latitude)
let longitudeString = encodeSingleComponent(locationCoordinate.longitude)
return latitudeString + longitudeString
}
private func encodeSingleComponent(_ value: Int) -> String {
var intValue = value
if intValue < 0 {
intValue = intValue << 1
intValue = ~intValue
} else {
intValue = intValue << 1
}
return encodeFiveBitComponents(intValue)
}
// MARK: Encode Levels
private func encodeLevel(_ level: UInt32) -> String {
return encodeFiveBitComponents(Int(level))
}
private func encodeFiveBitComponents(_ value: Int) -> String {
var remainingComponents = value
var fiveBitComponent = 0
var returnString = String()
repeat {
fiveBitComponent = remainingComponents & 0x1F
if remainingComponents >= 0x20 {
fiveBitComponent |= 0x20
}
fiveBitComponent += 63
let char = UnicodeScalar(fiveBitComponent)!
returnString.append(String(char))
remainingComponents = remainingComponents >> 5
} while (remainingComponents != 0)
return returnString
}
// MARK: Decode Coordinate
// We use a byte array (UnsafePointer<Int8>) here for performance reasons. Check with swift 2 if we can
// go back to using [Int8]
private func decodeSingleCoordinate(byteArray: UnsafePointer<Int8>, length: Int, position: inout Int, precision: Double = 1e5) throws -> Double {
guard position < length else { throw PolylineError.singleCoordinateDecodingError }
let bitMask = Int8(0x1F)
var coordinate: Int32 = 0
var currentChar: Int8
var componentCounter: Int32 = 0
var component: Int32 = 0
repeat {
currentChar = byteArray[position] - 63
component = Int32(currentChar & bitMask)
coordinate |= (component << (5*componentCounter))
position += 1
componentCounter += 1
} while ((currentChar & 0x20) == 0x20) && (position < length) && (componentCounter < 6)
if (componentCounter == 6) && ((currentChar & 0x20) == 0x20) {
throw PolylineError.singleCoordinateDecodingError
}
if (coordinate & 0x01) == 0x01 {
coordinate = ~(coordinate >> 1)
} else {
coordinate = coordinate >> 1
}
return Double(coordinate) / precision
}
// MARK: Decode Levels
private func extractNextChunk(_ encodedString: inout String.UnicodeScalarView) throws -> String {
var currentIndex = encodedString.startIndex
while currentIndex != encodedString.endIndex {
let currentCharacterValue = Int32(encodedString[currentIndex].value)
if isSeparator(currentCharacterValue) {
let extractedScalars = encodedString[encodedString.startIndex...currentIndex]
encodedString = String.UnicodeScalarView(encodedString[encodedString.index(after: currentIndex)..<encodedString.endIndex])
return String(extractedScalars)
}
currentIndex = encodedString.index(after: currentIndex)
}
throw PolylineError.chunkExtractingError
}
private func decodeLevel(_ encodedLevel: String) -> UInt32 {
let scalarArray = [] + encodedLevel.unicodeScalars
return UInt32(agregateScalarArray(scalarArray))
}
private func agregateScalarArray(_ scalars: [UnicodeScalar]) -> Int32 {
let lastValue = Int32(scalars.last!.value)
let fiveBitComponents: [Int32] = scalars.map { scalar in
let value = Int32(scalar.value)
if value != lastValue {
return (value - 63) ^ 0x20
} else {
return value - 63
}
}
return Array(fiveBitComponents.reversed()).reduce(0) { ($0 << 5 ) | $1 }
}
// MARK: Utilities
enum PolylineError: Error {
case singleCoordinateDecodingError
case chunkExtractingError
}
private func toCoordinates(_ locations: [CLLocation]) -> [CLLocationCoordinate2D] {
return locations.map {location in location.coordinate}
}
private func toLocations(_ coordinates: [CLLocationCoordinate2D]) -> [CLLocation] {
return coordinates.map { coordinate in
CLLocation(latitude:coordinate.latitude, longitude:coordinate.longitude)
}
}
private func isSeparator(_ value: Int32) -> Bool {
return (value - 63) & 0x20 != 0x20
}
private typealias IntegerCoordinates = (latitude: Int, longitude: Int)
......@@ -17,7 +17,7 @@ class ListVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
@objc var placemark: MapmyIndiaPlacemark?
let listArr:[String]? = ["Zoom Level", "Zoom Level With Animation", "Center With Animation", "Current Location","Tracking Mode", "Add Marker", "Add Multiple Markers With Bounds", "Custom Marker", "Animate Marker", "Draggable Marker", "Clustering Markers", "Interactive Markers", "Polyline", "Multiple Polylines", "Polygons", "Circles", "Update Circle", "Autosuggest", "Geocoding (Forward Geocode)", "Atlas Geocode", "Reverse Geocoding", "Nearby Search", "Place/eLoc Detail", "Driving Distance", "Distance Matrix", "Distance Matrix ETA", "Route", "Route Advance", "Route Advance ETA", "Feedback", "GeoJson Multiple Shapes", "Dashed Polyline", "Geodesic Polyline", "Interior Polygons", "Default Indoor", "Custom Indoor", "Point On Map", "Safety Plugin", "Covid Layers", "COVID-19 Safety Status", "Place Picker"]
let listArr:[String]? = ["Zoom Level", "Zoom Level With Animation", "Center With Animation", "Current Location","Tracking Mode", "Add Marker", "Add Multiple Markers With Bounds", "Custom Marker", "Animate Marker", "Draggable Marker", "Clustering Markers", "Interactive Markers", "Polyline", "Multiple Polylines", "Polygons", "Circles", "Update Circle", "Autosuggest", "Geocoding (Forward Geocode)", "Atlas Geocode", "Reverse Geocoding", "Nearby Search", "Place/eLoc Detail", "Driving Distance", "Distance Matrix", "Distance Matrix ETA", "Route", "Route Advance", "Route Advance ETA", "Feedback", "GeoJson Multiple Shapes", "Dashed Polyline", "Geodesic Polyline", "Interior Polygons", "Default Indoor", "Custom Indoor", "Point On Map", "Safety Plugin", "Covid Layers", "COVID-19 Safety Status", "Place Picker", "POI along the Route"]
var placeDetails = [String]()
......@@ -153,6 +153,9 @@ class ListVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
let vc = PlacePickerViewExampleLauncherVC(nibName: nil, bundle: nil)
self.navigationController?.pushViewController(vc, animated: true)
break
case "POI along the Route":
let vc = POIsAlongTheRouteVC(nibName: nil, bundle: nil)
self.navigationController?.pushViewController(vc, animated: true)
default:
let vctrl = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "mapVC") as? mapVC
self.navigationController?.pushViewController(vctrl!, animated: true)
......
//
// POIsAlongTheRouteVC.swift
// MapDemo
//
// Created by Apple on 10/09/20.
// Copyright © 2020 MMI. All rights reserved.
//
import UIKit
import MapmyIndiaAPIKit
import Polyline
import MapmyIndiaMaps
import MapmyIndiaDirections
class POIsAlongTheRouteVC: UIViewController {
var mapView: MapmyIndiaMapView!
var routes = [Route]()
var selectedRoute:Route?
let point = MGLPointAnnotation()
var poiMarkers = [CustomPointAnnotation]()
override func viewDidLoad() {
super.viewDidLoad()
mapView = MapmyIndiaMapView(frame: view.bounds)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
mapView.delegate = self
view.addSubview(mapView)
// Do any additional setup after loading the view.
}
func getRoute() {
let origin = Waypoint(coordinate: CLLocationCoordinate2DMake(19.072919845581055,72.98474884033203), name: "MapmyIndia")
let destination = Waypoint(coordinate: CLLocationCoordinate2DMake(19.036991119384766,73.01266479492188), name: "")
origin.allowsArrivingOnOppositeSide = false
destination.allowsArrivingOnOppositeSide = false
let options = RouteOptions(waypoints: [origin, destination])
options.routeShapeResolution = .full
options.includesAlternativeRoutes = true
Directions(restKey: MapmyIndiaAccountManager.restAPIKey()).calculate(options) { (waypoints, routes, error) in
if let _ = error { return }
guard let allRoutes = routes, allRoutes.count > 0 else { return }
self.routes = allRoutes
DispatchQueue.main.async {
self.plotRouteOnMap(routeIndex: 0)
}
}
}
func plotRouteOnMap(routeIndex: Int) {
var polylines = [CustomPolyline]()
if self.routes.count > 0 {
for i in 0...self.routes.count - 1 {
let route = self.routes[i]
if let routeCoordinates = route.coordinates {
let myPolyline = CustomPolyline(coordinates: routeCoordinates, count: UInt(routeCoordinates.count))
myPolyline.routeIndex = i
polylines.append(myPolyline)
if i == routeIndex {
myPolyline.isSelected = true
self.selectedRoute = route
} else {
self.mapView.addAnnotation(myPolyline)
}
}
}
self.mapView.addAnnotation(polylines[routeIndex])
self.mapView.showAnnotations(polylines, edgePadding: UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20), animated: false, completionHandler: nil)
self.selectRoute(route: self.routes[0])
}
let selectedRoute = self.routes[routeIndex]
getPOIAlongTheRoute(coordinates: selectedRoute.coordinates!)
}
func selectRoute(route: Route) {
point.title = "\(route.expectedTravelTime) seconds"
if let routeCoordinates = route.coordinates, routeCoordinates.count > 0 {
if routeCoordinates.count > 2 {
let midIndex = (routeCoordinates.count/2) - 1
print("Route Midindex:- \(midIndex)")
point.coordinate = routeCoordinates[midIndex]
} else {
point.coordinate = routeCoordinates[0]
}
mapView.addAnnotation(point)
self.mapView.selectAnnotation(self.point, animated: false, completionHandler: nil)
}
}
func getPOIAlongTheRoute(coordinates: [CLLocationCoordinate2D]) {
if let markers = self.mapView.annotations, markers.count > 0, self.poiMarkers.count > 0 {
self.mapView.removeAnnotations(poiMarkers)
}
let routePath = Polyline(coordinates: coordinates, precision: 1e5).encodedPolyline
let poiAlongTheRouteOptions = MapmyIndiaPOIAlongTheRouteOptions(path: routePath, category: "FODCOF")
poiAlongTheRouteOptions.buffer = 1000
let poiAlongTheRouteManager = MapmyIndiaPOIAlongTheRouteManager(restKey: MapmyIndiaAccountManager.restAPIKey(), clientId: MapmyIndiaAccountManager.atlasClientId(), clientSecret: MapmyIndiaAccountManager.atlasClientSecret(), grantType: MapmyIndiaAccountManager.atlasGrantType())
let _ = poiAlongTheRouteManager.getPOIsAlongTheRoute(poiAlongTheRouteOptions) { (suggestions, error) in
if let error = error {
print("\(error.localizedDescription)")
} else if let suggestions = suggestions {
DispatchQueue.main.async {
self.plotPOIMarkers(suggestions: suggestions)
}
} else {
print("NO Results")
}
}
}
func plotPOIMarkers(suggestions: [MapmyIndiaPOISuggestion]) {
var markers = [CustomPointAnnotation]()
for suggestion in suggestions {
if let latitude = suggestion.latitude, let longitude = suggestion.longitude {
let markerTitle = "\([suggestion.poi ?? "", suggestion.address ?? ""].joined(separator: ","))"
let marker = CustomPointAnnotation(coordinate: CLLocationCoordinate2DMake(latitude, longitude), title: markerTitle, subtitle: nil)
markers.append(marker)
}
}
self.poiMarkers = markers
self.mapView.addAnnotations(self.poiMarkers)
}
}
extension POIsAlongTheRouteVC: MapmyIndiaMapViewDelegate {
func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) {
getRoute()
}
func mapView(_ mapView: MGLMapView, strokeColorForShapeAnnotation annotation: MGLShape) -> UIColor {
// Give our polyline a unique color by checking
if annotation is MGLPolyline {
if let customPolyline = annotation as? CustomPolyline, customPolyline.isSelected {
return .blue
}
return .red
}
return mapView.tintColor
}
func mapView(_ mapView: MGLMapView, fillColorForPolygonAnnotation annotation: MGLPolygon) -> UIColor {
return UIColor.red
}
func mapView(_ mapView: MGLMapView, lineWidthForPolylineAnnotation annotation: MGLPolyline) -> CGFloat {
// Set the line width for polyline annotations
return 10.0
}
func mapView(_ mapView: MGLMapView, alphaForShapeAnnotation annotation: MGLShape) -> CGFloat {
// Set the alpha for all shape annotations to 1 (full opacity)
return 0.7
}
func mapView(_ mapView: MGLMapView, didSelect annotation: MGLAnnotation) {
if annotation is MGLPolyline {
if let customPolyline = annotation as? CustomPolyline, !customPolyline.isSelected {
let polylineAnnotations = mapView.annotations?.filter({ (annotation) -> Bool in
if annotation is MGLPolyline {
return true
}
return false
})
if let polylines = polylineAnnotations {
self.mapView.removeAnnotations(polylines)
}
if self.routes.count > 0 {
plotRouteOnMap(routeIndex: customPolyline.routeIndex)
let selectedRoute = self.routes[customPolyline.routeIndex]
self.selectRoute(route: selectedRoute)
}
}
}
}
func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
return true
}
func mapView(_ mapView: MGLMapView, calloutViewFor annotation: MGLAnnotation) -> MGLCalloutView? {
if let _ = annotation as? CustomPointAnnotation {
// For POI markers, show callout
return nil
} else {
// For polyline, show custom callout
return CustomCalloutViewForPolyline(representedObject: annotation)
}
}
func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? {
if let _ = annotation as? CustomPointAnnotation {
// For POI markers, show default marker
return nil
} else {
// For polyline, show no marker
let annotationView = MGLAnnotationView()
annotationView.isOpaque = true
return annotationView
}
}
}
......@@ -7,6 +7,7 @@
//
import UIKit
import Polyline
import MapmyIndiaMaps
import MapmyIndiaAPIKit
import MapmyIndiaDirections
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment