convert string to array of cllocationcoordinate2d swift - swift

I am using an API that returns a String that contains coordinate. How do I convert this response:
"route_pins":
"#30.0539983,30.943465#30.0539033,30.9434167#30.05379,30.9434467#30.0536117,30.943865#30.0535133,30.9439867#30.0534633,30.9440967#30.05353,30.94428#30.053675,30.944525#30.0539933,30.9449667#30.0541517,30.9452317#30.0542917,30.9454717#30.054365,30.9455717#30.0544667,30.945725#30.05471,30.9460733#30.0548667,30.94631#30.0550417,30.9465683#30.0553733,30.9471133#30.0557133,30.9476383#30.0558667,30.947905#30.0560083,30.9481767#30.0562517,30.94872#30.0564917,30.9492217#30.0565783,30.9494567#30.056645,30.9496883#30.0566167,30.9501883"
into an Array of CLLocationCoordinate2D to draw a line using MapKit using:
let polyLine = MKPolyline(coordinates: Locations , count: Locations.count)
busMapView.add(polyLine)

You can do it with a combination of components(separatedBy and map
Split the string by character # and drop the first (empty) item.
Map each item to CLLocationCoordinate2D by splitting the string by the comma, convert the strings to CLLocationCoordinate2D and create the coordinate.
let routePins = "#30.0539983,30.943465#30.0539033,30.9434167#30.05379,30.9434467#30.0536117,30.943865#30.0535133,30.9439867#30.0534633,30.9440967#30.05353,30.94428#30.053675,30.944525#30.0539933,30.9449667#30.0541517,30.9452317#30.0542917,30.9454717#30.054365,30.9455717#30.0544667,30.945725#30.05471,30.9460733#30.0548667,30.94631#30.0550417,30.9465683#30.0553733,30.9471133#30.0557133,30.9476383#30.0558667,30.947905#30.0560083,30.9481767#30.0562517,30.94872#30.0564917,30.9492217#30.0565783,30.9494567#30.056645,30.9496883#30.0566167,30.9501883"
let coordinates = routePins.components(separatedBy: "#").dropFirst().map { (pin) -> CLLocationCoordinate2D in
let latLng = pin.components(separatedBy: ",").map{ CLLocationDegrees($0)! }
return CLLocationCoordinate2D(latitude: latLng[0], longitude: latLng[1])
}
The result is [CLLocationCoordinate2D].

let dic:Dictionary<String,Any> = ["route_pins": "#30.0539983,30.943465#30.0539033,30.9434167#30.05379,30.9434467#30.0536117,30.943865#30.0535133,30.9439867#30.0534633,30.9440967#30.05353,30.94428#30.053675,30.944525#30.0539933,30.9449667#30.0541517,30.9452317#30.0542917,30.9454717#30.054365,30.9455717#30.0544667,30.945725#30.05471,30.9460733#30.0548667,30.94631#30.0550417,30.9465683#30.0553733,30.9471133#30.0557133,30.9476383#30.0558667,30.947905#30.0560083,30.9481767#30.0562517,30.94872#30.0564917,30.9492217#30.0565783,30.9494567#30.056645,30.9496883#30.0566167,30.9501883"]
let strLatLng = dic["route_pins"] as! String
let arrayOflatLng = strLatLng.components(separatedBy: "#")
var testcoords = [CLLocationCoordinate2D]()
for latLngStr in arrayOflatLng {
if let strLat = latLngStr.components(separatedBy: ",") as? [String], strLat.count == 2 {
testcoords.append(CLLocationCoordinate2D(latitude: CLLocationDegrees(strLat[0])!, longitude: CLLocationDegrees(strLat[1])!))
}
}
print("testcoords \(testcoords.count)")
let polyLine = MKPolyline(coordinates: testcoords , count: testcoords.count)
busMapView.add(polyLine)

The API string is parsed using 2 levels of parsing ,first we split the API string to locations strings , then using for loop to split each location to its coordinates and save coordinates to CLLocationCoordinate2D and append it to result array
let routePins = "#30.0539983,30.943465#30.0539033,30.9434167#30.05379,30.9434467#30.0536117,30.943865#30.0535133,30.9439867#30.0534633,30.9440967#30.05353,30.94428#30.053675,30.944525#30.0539933,30.9449667#30.0541517,30.9452317#30.0542917,30.9454717#30.054365,30.9455717#30.0544667,30.945725#30.05471,30.9460733#30.0548667,30.94631#30.0550417,30.9465683#30.0553733,30.9471133#30.0557133,30.9476383#30.0558667,30.947905#30.0560083,30.9481767#30.0562517,30.94872#30.0564917,30.9492217#30.0565783,30.9494567#30.056645,30.9496883#30.0566167,30.9501883"
let pins = routePins.components(separatedBy: "#")//first step is splitting the fetched array to pins array
var LocationsArray = [CLLocationCoordinate2D]()//this is the result array
for location in pins {
if(location.contains(",")){//checking that the location is containing lat ,long separtor
let coordinates = location.components(separatedBy: ",")//splitting the location to lat ,long
//safe parsing the string value to double vale for coordinates
let lat = Double(coordinates[0]) ?? 0.0
let long = Double( coordinates[1]) ?? 0.0
LocationsArray.append(CLLocationCoordinate2D(latitude: lat
,longitude: long))// appending new coordinates to locations array
}
}

Related

Returning Asynchronous function then assigning a value swift

I'm attempting to return the value of an array and then assign its value to a variable, however when doing so, it returns a blank array. I'm assuming this is due to my lack of knowledge on how to use async in swift so was hoping someone could show me how to do so for this segment of code:
func assignWeights(){
var weightedList = [GMUWeightedLatLng]()
getCoords { coords in
self.coords = coords
for coord in coords {
let lat = Double(coords.location.latitude)!
let long = Double(coords.location.longitude)!
let coordinates = GMUWeightedLatLng(coordinate: CLLocationCoordinate2DMake(lat,long), intensity: 2.0)
weightedList.append(coordinates)
}
print(weightedList) //Array prints contents
}
print(weightedList) //Empty array
heatmapLayer.weightedData = weightedList //Sets to empty array [] as this is ran before getCoords{
}

Reverse a for loop of an array

I'm try to create a func that should calculate the coordinate at 90deg and 270deg from each of the given coordinate..
and save it in an array of arrayLocationOffset
var arrayLocations : [CLLocationCoordinate2D] =
[
CLLocationCoordinate2D(latitude: 45.15055543976834, longitude: 11.656891939801518 ),
CLLocationCoordinate2D(latitude: 45.154446871287924, longitude: 11.66058789179949),
]
// simplify only 2 coordinate
I use this for loop in order to perform the action:
func createCoordinatePoly() {
let polypoint = arrayLocations.count
for i in 0..<polypoint {
let coord = arrayLocations[i]
// calc LH
let lhCoord = coord270(coord: coord)
arrayLocationOffset.append(lhCoord)
}
for i in 0..<polypoint { // shuld revers this for loop and get first the last index
let coord = arrayLocations[i]
// calc LH
let RhCoord = coord90(coord: coord)
arrayLocationOffset.append(RhCoord)
}
debugPrint("aggiunto array poly \(arrayLocationOffset.count)")
}
The arrayLocationOffset must have a specific sequence otherwise I can't properly draw a polygon in the Mapkit.
In order get the specific order on the second forLoop (where I calculate RHside) I should start to calculate from last array index back to the first...
is this possible?
thanks
As the name implies you can reverse an array just with reversed().
Your code is rather objective-c-ish. A better way to enumerate the array is fast enumeration because you actually don't need the index.
for coord in arrayLocations { ...
and
for coord in arrayLocations.reversed() { ...
However there is a still swiftier way mapping the arrays
func createCoordinatePoly() {
arrayLocationOffset.append(contentsOf: arrayLocations.map{coord270(coord: $0)})
arrayLocationOffset.append(contentsOf: arrayLocations.reversed().map{coord90(coord: $0)})
debugPrint("aggiunto array poly \(arrayLocationOffset.count)")
}
solved:
var reversIndex = polypoint-1
for _ in 0..<polypoint {
let coord = arrayLocations[reversIndex]
// calc LH
let RhCoord = coord90(coord: coord)
arrayLocationOffset.append(RhCoord)
reversIndex -= 1
}
I use a reverse index to start from the end...

Firestore get array data at index 0

Below I have some data in firestore.
I have a an array in the _geoloc field. Each of those indexes have latitude and longitude coordinates. So using SWIFT I want to be able to only get the lat and lng coordinates at index 0 and pass them to individually to a string. I have been researching for days and I am stuck. I have tried to create a new array of strings or an AnyObject array and I just get stuck with retrieving the data I need at index 0, and passing only those 2 lat/lng coordinates to string values. I have several failed snippets of code I could post.
Here is a snippet of what I was attempting to do: (I am really new to firebase so the code is a bit ugly as I am just trying to figure this out)
Firestore.firestore().collection("users").document("626").getDocument { (document, error) in
if let document = document {
// let geo_array = document["_geoloc"]
var yourArray = [String]()
// let geo_location = [geo_array] as [AnyObject]
let array: [Any] = document["_geoloc"] as! [Any]
let tmpArray = array.map({ return String(describing: $0)})
let string = tmpArray.joined(separator: ",")
yourArray.append(string)
print(yourArray[0])
You just need to cast your object from Any to an array of dictionaries and get the first property:
Firestore.firestore().collection("users").document("626").getDocument { document, error in
if let document = document {
var yourArray: [String] = []
if let location = (document["_geoloc"] as? [[String:Double]])?.first,
let latitude = location["lat"],
let longitude = location["lon"] {
let coordinate2d = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
yourArray.append("Latitude: \(location.latitude), Longitude: \(location.Longitude)")
}
}
}
Maybe first declare this:
var firstPositionValues = [AnyObject]()
Then get it like this:
let db = Firestore.firestore().collection("users").document("626")
db.getDocument { (document, error) in
if let document = document {
let geo_location = document["_geoloc"] as [AnyObject] // <- this is all of them in the document
var initialValues = geo_location[0] // <- here are your lat and lng at position 0
self.firstPositionValues = initialValues
}
Hope I understood correctly good luck.

Swift3 loop dictionary to add value

I m new to programming I just playing around in playground, I am trying to loop in a dictionary to do some calculation and add them into new dictionary however, I can only add one dictionary value back. I am not sure why. Can anymore tell me and point out the point?
var name:String?
var popDict: [String: Array<Double>]?
var FinalDict: [String: Array<Double>]?
var mean: Double?
var elementSideArr: Array<Double>?
var nameArray = ["Olivia": [1,2,2,2,1,2,1,0.0001,0,1,2], "Amber": [52,52,65,66,57,63,62,0.0001,0,0,0]]
var doubleArr = [Double]()
for (key, value) in nameArray{
let thisValue = value
let arrayS = thisValue.prefix(7)
let slice = arrayS[0...6]
let popSideArr = Array(slice)
let average: Double = (popSideArr as NSArray).value(forKeyPath: "#avg.self") as! Double
mean = average
let thatValue = value
let arraySS = thatValue.suffix(3)
let sslice = arraySS[8...10]
elementSideArr = Array(sslice)
elementSideArr?.insert(average, at: 0)
let dict = ["\(key)": elementSideArr!]
for (key,value) in dict{
popDict = dict
}
}
print(popDict!)
["Olivia": [1.5714285714285714, 0.0, 1.0, 2.0]] // It is the only output but it should be 2 items.
Problem is in your inner for loop you are initializing whole new dictionary to popDict also you don't need for loop if you are having single key and value pair with your dictionary.
Replace line of codes:
let dict = ["\(key)": elementSideArr!]
for (key,value) in dict{
popDict = dict
}
With:
popDict["\(key)"] = elementSideArr!
Note: No need to cast swift array to NSArray to calculate average you can simply use reduce to get total and then divide the total with array count.
let array = popSideArr as? [Int] ?? []
let res = Double(array.reduce(0, +)) / Double(popSideArr.count)

Converting a single string with coordinates into an array of CLLocationCoordinate2D and use the array to generate Polygons in a mapView

I'm receiving this JSON:
JSON: {
"status_code" : 200,
"status" : "ok",
"data" : [
{
"zona" : "Narvarte",
"hora" : "",
"id_zona" : 1423,
"proxdia" : "Lunes 20 de Febrero, 2017",
"coor" : "(19.452187074041884, -99.1457748413086),(19.443769985032485, -99.14852142333984),(19.443446242121073, -99.13787841796875),(19.450244707639662, -99.13822174072266)",
"dias" : "Lunes"
}, ...]
Which I'm storing in this struct:
struct RutaItem {
var idZona: Int
var dias: String
var proxDia: String
var hora: String
var coor: String
var zona: String
}
then I created an array of [RutaItem] where I'm storing the structs
var rutaItemArray = [RutaItem]()
Once the data has been stored the structs inside rutaItemArray look like this:
[pixan.RutaItem(idZona: 1423, dias: "Lunes", proxDia: "Lunes 20 de Febrero, 2017", hora: "", coor: "(19.452187074041884, -99.1457748413086),(19.443769985032485, -99.14852142333984),(19.443446242121073, -99.13787841796875),(19.450244707639662, -99.13822174072266)", zona: "Narvarte")...]
What I need to do now is to use the String inside each index of rutaItemArray.coor to generate an MKPolygonObject, so first I would need to convert the long String into 4 CLLocationCoordinate2D objects and put those 4 coordinate objects inside an array for each item, then use the array indexes to generate the polygon.for the different areas.
Can somebody help me with this problem?
You can use regular expression pattern matching.
Explanations inline:
let coordString = "(19.452187074041884, -99.1457748413086), (19.443769985032485, -99.14852142333984),(19.443446242121073, -99.13787841796875),(19.450244707639662, -99.13822174072266)"
// Regular expression pattern for "( ... , ... )"
let pattern = "\\((.+?),(.+?)\\)"
let regex = try! NSRegularExpression(pattern: pattern)
// We need an NSString, compare http://stackoverflow.com/a/27880748/1187415
let nsString = coordString as NSString
// Enumerate all matches and create an array:
let coords = regex.matches(in: coordString, range: NSRange(location: 0, length: nsString.length))
.flatMap { match -> CLLocationCoordinate2D? in
// This closure is called for each match.
// Extract x and y coordinate from match, remove leading and trailing whitespace:
let xString = nsString.substring(with: match.rangeAt(1)).trimmingCharacters(in: .whitespaces)
let yString = nsString.substring(with: match.rangeAt(2)).trimmingCharacters(in: .whitespaces)
// Convert to floating point numbers, skip invalid entries:
guard let x = Double(xString), let y = Double(yString) else { return nil }
// Return CLLocationCoordinate2D:
return CLLocationCoordinate2D(latitude: x, longitude: y)
}
Here's what I came up with. You can adapt it to fit your structure.
import Foundation
let input = "(19.452187074041884, -99.1457748413086),(19.443769985032485, -99.14852142333984),(19.443446242121073, -99.13787841796875),(19.450244707639662, -99.13822174072266)"
// Remove leading `(` and trailing `)`
let trimmedInput = String(input.characters.dropLast().dropFirst())
let coordStrings = trimmedInput.components(separatedBy: "),(")
let coords: [CLLocationCoordinate2D] = coordStrings.map{ coordsString in
let coords = coordsString.components(separatedBy: ", ")
precondition(coords.count == 2, "There should be exactly 2 coords.")
guard let lat = Double(coords[0]),
let long = Double(coords[1]) else {
fatalError("One of the coords isn't a valid Double: \(coords)")
}
return CLLocationCoordinate2D(latitude: lat, longitude: long)
}
print(coords)