feat: Add Intaleq Native Android Kotlin & iOS Swift SDKs, Incline slope routing, Topographic contours and modular tactical app
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
import Foundation
|
||||
|
||||
public struct InlqGeocodingPlace: Codable {
|
||||
public let id: String
|
||||
public let name: String
|
||||
public let nameAr: String?
|
||||
public let nameEn: String?
|
||||
public let category: String?
|
||||
public let city: String?
|
||||
public let neighbourhood: String?
|
||||
public let address: String?
|
||||
public let position: InlqLatLng
|
||||
}
|
||||
|
||||
/**
|
||||
* Commercial Geocoding & Reverse Geocoding Service calling Intaleq SaaS API on iOS (Swift).
|
||||
*/
|
||||
public class IntaleqGeocodingService {
|
||||
|
||||
public static let shared = IntaleqGeocodingService()
|
||||
|
||||
private init() {}
|
||||
|
||||
/**
|
||||
* Search for places, addresses, and POIs by text query.
|
||||
*/
|
||||
public func search(
|
||||
query: String,
|
||||
proximity: InlqLatLng? = nil,
|
||||
limit: Int = 10,
|
||||
completion: @escaping (Result<[InlqGeocodingPlace], Error>) -> Void
|
||||
) {
|
||||
guard let encoded = query.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {
|
||||
completion(.failure(NSError(domain: "IntaleqMaps", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid query"])))
|
||||
return
|
||||
}
|
||||
|
||||
var urlStr = "\(IntaleqMaps.shared.baseUrl)/api/geocoding/search?q=\(encoded)&limit=\(limit)"
|
||||
if let proximity = proximity {
|
||||
urlStr += "&lat=\(proximity.latitude)&lng=\(proximity.longitude)"
|
||||
}
|
||||
|
||||
guard let url = URL(string: urlStr) else {
|
||||
completion(.failure(NSError(domain: "IntaleqMaps", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid URL"])))
|
||||
return
|
||||
}
|
||||
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = "GET"
|
||||
request.setValue(IntaleqMaps.shared.apiKey, forHTTPHeaderField: "x-api-key")
|
||||
request.setValue("application/json", forHTTPHeaderField: "Accept")
|
||||
|
||||
URLSession.shared.dataTask(with: request) { data, _, error in
|
||||
if let error = error {
|
||||
completion(.failure(error))
|
||||
return
|
||||
}
|
||||
|
||||
guard let data = data else {
|
||||
completion(.success([]))
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
|
||||
let features = json["features"] as? [[String: Any]] {
|
||||
|
||||
let places: [InlqGeocodingPlace] = features.compactMap { f in
|
||||
guard let geom = f["geometry"] as? [String: Any],
|
||||
let coords = geom["coordinates"] as? [Double],
|
||||
coords.count >= 2 else { return nil }
|
||||
|
||||
let props = f["properties"] as? [String: Any] ?? [:]
|
||||
return InlqGeocodingPlace(
|
||||
id: f["id"] as? String ?? UUID().uuidString,
|
||||
name: props["name"] as? String ?? "موقع محدد",
|
||||
nameAr: props["name_ar"] as? String,
|
||||
nameEn: props["name_en"] as? String,
|
||||
category: props["category"] as? String,
|
||||
city: props["city"] as? String,
|
||||
neighbourhood: props["neighbourhood"] as? String,
|
||||
address: props["address"] as? String,
|
||||
position: InlqLatLng(latitude: coords[1], longitude: coords[0])
|
||||
)
|
||||
}
|
||||
completion(.success(places))
|
||||
} else {
|
||||
completion(.success([]))
|
||||
}
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
}
|
||||
}.resume()
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse geocode coordinate to get street and neighborhood name.
|
||||
*/
|
||||
public func reverseGeocode(
|
||||
position: InlqLatLng,
|
||||
completion: @escaping (Result<InlqGeocodingPlace?, Error>) -> Void
|
||||
) {
|
||||
let urlStr = "\(IntaleqMaps.shared.baseUrl)/api/geocoding/reverse?lat=\(position.latitude)&lng=\(position.longitude)"
|
||||
guard let url = URL(string: urlStr) else {
|
||||
completion(.failure(NSError(domain: "IntaleqMaps", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid URL"])))
|
||||
return
|
||||
}
|
||||
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = "GET"
|
||||
request.setValue(IntaleqMaps.shared.apiKey, forHTTPHeaderField: "x-api-key")
|
||||
request.setValue("application/json", forHTTPHeaderField: "Accept")
|
||||
|
||||
URLSession.shared.dataTask(with: request) { data, _, error in
|
||||
if let error = error {
|
||||
completion(.failure(error))
|
||||
return
|
||||
}
|
||||
|
||||
guard let data = data else {
|
||||
completion(.success(nil))
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
|
||||
let features = json["features"] as? [[String: Any]], let first = features.first,
|
||||
let geom = first["geometry"] as? [String: Any],
|
||||
let coords = geom["coordinates"] as? [Double], coords.count >= 2 {
|
||||
|
||||
let props = first["properties"] as? [String: Any] ?? [:]
|
||||
let place = InlqGeocodingPlace(
|
||||
id: first["id"] as? String ?? UUID().uuidString,
|
||||
name: props["name"] as? String ?? "موقع محدد",
|
||||
nameAr: props["name_ar"] as? String,
|
||||
nameEn: props["name_en"] as? String,
|
||||
category: props["category"] as? String,
|
||||
city: props["city"] as? String,
|
||||
neighbourhood: props["neighbourhood"] as? String,
|
||||
address: props["address"] as? String,
|
||||
position: InlqLatLng(latitude: coords[1], longitude: coords[0])
|
||||
)
|
||||
completion(.success(place))
|
||||
} else {
|
||||
completion(.success(nil))
|
||||
}
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
}
|
||||
}.resume()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user