How to Set UITabBar background image change? - ios

How can i sort the array based on distance from current location and show in tableview .when i use sorting am not getting any proper results ,am getting the array with random distance.can any one guide me for solve this issue

To sort locations based on distance from current location in best possible way would be have location points in form of struct
struct LocationPoints {
var latitude: CLLocationDegrees
var longitude: CLLocationDegrees
func distance(to currentLocation: CLLocation) -> CLLocationDistance {
return CLLocation(latitude: self.latitude, longitude: self.longitude).distance(from: currentLocation)
}
}
Let suppose you have an array of LocationPoints having latitude & longitude
var coordinates: [LocationPoints] = []
coordinates.append(LocationPoints(latitude: Double(25), longitude: Double(24)))
coordinates.append( LocationPoints(latitude: Double(23), longitude: Double(22)))
sort function
coordinates = sortLocationsWithCurrentLocation(locations: coordinates, currentLocation: CLLocation(latitude: Double(20), longitude: Double(21)))
func sortLocationsWithCurrentLocation(locations:[LocationPoints],currentLocation:CLLocation) -> [LocationPoints] {
//set here current position as current location
let currentPosition : CLLocation = CLLocation(latitude: 30, longitude: 24)
let sortedLocations = locations.sorted(by: { (point1 : LocationPoints, point2 :LocationPoints) -> Bool in
if point1.distance(to: currentPosition) < point2.distance(to: currentPosition)
{
return true
}
return false
})
return sortedLocations
}

Related

Calculating trip distance core location swift

I have an application where I calculate distance travelled like the Uber application. When a driver starts a trip, the location begins to change even though a start point has been specified in the search for a ride, a driver could decide to pass an alternative route or pass long places and routes because he/ she does not know the shortest route, how then do I calculate the total distance.
The starting location is the location the driver hits start button
The end location is the location the driver hits stop button
this is my code so far
public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
lastLocation = locations.last!
endTrip(locations.last)
if !hasSetInitialLocation {
let camera = GMSCameraPosition.camera(withTarget: lastLocation!.coordinate, zoom: 17)
self.mapView.animate(to: camera)
hasSetInitialLocation = true
endTrip(lastLocation)
MqttManager.instance.connectToServer()
}
}
func endTrip(endLoaction: CLLocation) {
guard let statusChange = source.getStatusChange() else{return}
var distanceTraveled: Double = 0.0
let initialLocation = CLLocation(latitude: (statusChange.meta?.location?.lat)!, longitude: (statusChange.meta?.location?.lng)!)
let distance = initialLocation.distance(from: endLoaction)
distanceTraveled += distance
let distanceInKM = Utility.convertCLLocationDistanceToKiloMeters(targetDistance: distanceTraveled)
}
How can i calculate the distance to reflect the total distance moved by the driver since there could be a change in route from the proposed start point and end point.
The driver hits a button called start trip, I want to get the distance from that moment till the moment he hits the button end trip
this implementation could be got from a similar working code like these but the only difference is that their is a start button which passes the coordinates at that point and a stop coordinate which is the end of the coordinate.
enum DistanceValue: Int {
case meters, miles
}
func calculateDistanceBetweenLocations(_ firstLocation: CLLocation, secondLocation: CLLocation, valueType: DistanceValue) -> Double {
var distance = 0.0
let meters = firstLocation.distance(from: secondLocation)
distance += meters
switch valueType {
case .meters:
return distance
case .miles:
let miles = distance
return miles
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if startLocation == nil {
startLocation = locations.first
} else if let location = locations.last {
runDistance += lastLocation.distance(from: location)
let calc = calculateDistanceBetweenLocations(lastLocation, secondLocation: location, valueType: .meters)
print("TOTAL LOC 1 \(calc)")
print("TOTAL LOC 2 \(runDistance)")
}
lastLocation = locations.last
}
as shown in my print statements print("TOTAL LOC 1 \(calc)")
print("TOTAL LOC 2 \(runDistance)") how can I make
calc the same with runDistance
here is what is printed in the console
TOTAL LOC 10.29331530774379
TOTAL LOC 2 10.29331530774379
TOTAL LOC 2.2655118031831587
TOTAL LOC 2 12.558827110926948
If you get the distance like this using the first and last coordinate it always returns the wrong value because it can't identify the actual traveling path.
I did resolve the same issue with using the following code.
use GoogleMaps
> pod 'GoogleMaps'
Make the coordinates array while the driver is moving on a route.
var arr = [Any]()
// Driving lat long co-ordinateds continues add in this array according to your expectation either update location or perticuler time duration.
// make GMSMutablePath of your co-ordinates
let path = GMSMutablePath()
for obj in arr{
print(obj)
if let lat = (obj as? NSDictionary)?.value(forKey: PARAMETERS.LET) as? String{
path.addLatitude(Double(lat)!, longitude: Double(((obj as? NSDictionary)?.value(forKey: PARAMETERS.LONG) as? String)!)!)
}
}
print(path) // Here is your traveling path
let km = GMSGeometryLength(path)
print(km) // your total traveling distance.
I did it in this app and it's working fine.
Hope it will helps you :)
OR without GoogleMaps
You have to come with locations, an array of CLLocationCoordinate2D, for yourself, as per your code, though.
class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
// MARK: - Variables
let locationManager = CLLocationManager()
// MARK: - IBOutlet
#IBOutlet weak var mapView: MKMapView!
// MARK: - IBAction
#IBAction func distanceTapped(_ sender: UIBarButtonItem) {
let locations: [CLLocationCoordinate2D] = [...]
var total: Double = 0.0
for i in 0..<locations.count - 1 {
let start = locations[i]
let end = locations[i + 1]
let distance = getDistance(from: start, to: end)
total += distance
}
print(total)
}
func getDistance(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D) -> CLLocationDistance {
// By Aviel Gross
// https://stackoverflow.com/questions/11077425/finding-distance-between-cllocationcoordinate2d-points
let from = CLLocation(latitude: from.latitude, longitude: from.longitude)
let to = CLLocation(latitude: to.latitude, longitude: to.longitude)
return from.distance(from: to)
}
}
Output
A simple function to calculate distance (in meters) given an array of CLLocationCoordinate2D. Uses reduce instead of array iteration.
func computeDistance(from points: [CLLocationCoordinate2D]) -> Double {
guard let first = points.first else { return 0.0 }
var prevPoint = first
return points.reduce(0.0) { (count, point) -> Double in
let newCount = count + CLLocation(latitude: prevPoint.latitude, longitude: prevPoint.longitude).distance(
from: CLLocation(latitude: point.latitude, longitude: point.longitude))
prevPoint = point
return newCount
}
}
I like to use an extension for that
extension Array where Element: CLLocation {
var distance: Double {
guard count > 1 else { return 0 }
var previous = self[0]
return reduce(0) { (result, location) -> Double in
let distance = location.distance(from: previous)
previous = location
return result + distance
}
}
}
Usage:
locations.distance

How do you get a label to be read as a number?

My map annotation works well when physically putting the numbers in, but, how do I use it so,
for example, latitudelabel.text is read as the latitude rather than 38.897957?
Here is the code:
func showEmergenyOnMap() {
let emergency = MKPointAnnotation()
emergency.title = "Ongoing Emergency"
emergency.coordinate = CLLocationCoordinate2D(latitude: 38.897957, longitude: -77.036560)
Map.addAnnotation(emergency)
}
Covert string to double.
let lati = Double(label.text)
// do same for longi
Then init coordinate
let coords = CLLocationCoordinate2D(latitude: lati, longitude: longi)
UILabel's text property is an Optional variable so it can have a value or a nil. First of all you need to safely unwrap that value because CLLocationDegrees initializer takes a non-optional String. You can see the below example on how to convert labels text to CLLocationCoordinate2D,
var latitude: CLLocationDegrees = 0.0
var longitude: CLLocationDegrees = 0.0
if let latText = latitudelabel.text, let lat = CLLocationDegrees(latText) {
latitude = lat
}
if let longText = longitudelabel.text, let long = CLLocationDegrees(longText) {
longitude = long
}
let location = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)

How to make Text Show distance from The user current location to a certain Map annotation

Just wondering How to do that , really would like this in my custom cell in the table view in my app...
Will appreciate any help thank you !
You can calculate the distance between two CLLocation objects with the distanceFromLocation method:
let newYork = CLLocation(latitude: 40.725530, longitude: -73.996738)
let sanFrancisco = CLLocation(latitude: 37.768, longitude: -122.441)
let distanceInMeters = newYork.distanceFromLocation(sanFrancisco)
With an MKMapView object and an MKAnnotationView object, you can calculate the distance between the user's current location and the annotation as follows:
if let userLocation = mapView.userLocation.location, annotation = annotationView.annotation {
// Calculate the distance from the user to the annotation
let annotationLocation = CLLocation(latitude: annotation.coordinate.latitude, longitude: annotation.coordinate.longitude)
let distanceFromUserToAnnotationInMeters = userLocation.distanceFromLocation(annotationLocation)
...
}
The following function uses the NSNumberFormatter class to format a distance in meters or kilometres (if the number of meters is more than 1000):
func formatDistance(distanceInMeters: CLLocationDistance) -> String? {
// Set up a number formatter with two decimal places
let numberFormatter = NSNumberFormatter()
numberFormatter.numberStyle = .DecimalStyle
numberFormatter.maximumFractionDigits = 2
// Display as kilometers if the distance is more than 1000 meters
let distanceToFormat: CLLocationDistance = distanceInMeters > 1000 ? distanceInMeters/1000.0 : distanceInMeters
let units = distanceInMeters > 1000 ? "Km" : "m"
// Format the distance
if let formattedDistance = numberFormatter.stringFromNumber(distanceToFormat) {
return "\(formattedDistance)\(units)"
} else {
return nil
}
}
Putting all this together gives us the following:
if let userLocation = mapView.userLocation.location, annotation = annotationView.annotation {
// Calculate the distance from the user to the annotation
let annotationLocation = CLLocation(latitude: annotation.coordinate.latitude, longitude: annotation.coordinate.longitude)
let distanceFromUserToAnnotationInMeters = userLocation.distanceFromLocation(annotationLocation)
if let formattedDistance = formatDistance(distanceFromUserToAnnotationInMeters) {
// Now set the vaue of your label to formattedDistance
}
}

Swift: Calling a function with parameters that may be nil

I'm trying to figure out if there is any shorter syntax in Swift for the last line here:
var startPosition: CLLocationCoordinate2D?
var latitude: Double?
var longitude: Double?
// ...
// Here I have skipped some code which may or may not assign values
// to "latitude" and "longitude".
// ...
if latitude != nil && longitude != nil {
startPosition = CLLocationCoordinate2DMake(latitude!, longitude!)
}
As you can see, I want to set the "startPosition" based on "latitude" and "longitude", if those values have been assigned. Otherwise, I accept that the "startPosition" will not be initialized.
I guess this must be possible with "if let" or something similar, but I have failed to figure out how. (I'm experienced in Objective-C, but have just started to learn Swift.)
This is not shorter, but you can simply do
if let latitude = latitude, let longitude = longitude {
startPosition = CLLocationCoordinate2D(latitude: latitude,
longitude: longitude)
}
Notice I used just CLLocationCoordinate2D, not CLLocationCoordinate2DMake. Swift provides constructors without the "make" to most common objects, so you shouldn't usually have to use "make" in constructors.
If you don't want to execute any code after if they are nil use a guard.
var startPosition: CLLocationCoordinate2D?
var latitude: Double?
var longitude: Double?
guard let latitude = latitude && longitude = longitude else {
return
}
startPosition = CLLocationCoordinate2DMake(latitude, longitude)
Clear way
if let latitude = latitude, longitude = longitude {
startPosition = CLLocationCoordinate2D(latitude: latitude,
longitude: longitude)
}
CLLocationCoordinate2D is a struct, it's better if you use the struct initializer. Notice there is only one "let" needed in the if statement.
If i understood the question correctly, you could say
var startPosition: CLLocationCoordinate2D?
var latitude: Double?
var longitude: Double?
if latitude != nil && longitude != nil {
startPosition = CLLocationCoordinate2DMake(latitude!, longitude!)
} else {
startPosition = nil
}

Swift CLLocationDistance error

I am building a learning app where i want to create pins and show the distance between current location and the pin but i get a really weird output
func createPin(){
var coord = CLLocationCoordinate2D(latitude: 51.50, longitude: -0.13)
var coord2 = CLLocation(latitude: coord.latitude, longitude: coord.longitude)
var kilometers:CLLocationDistance = coord2.distanceFromLocation(locNow)
var str = NSString(format: "%.2f", kilometers)
let pin = Annotation(coordinate: coord, title: "LocationAlfa", subtitle: "distance : \(str)" + " meters", dist: kilometers)
map.addAnnotation(pin)
println("\(kilometers)")
}
this is my create pin method and here i get my location distance
func locationManager(manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!){
let location = newLocation
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
var region: () = centerMapOnLocation(location)
// self.map.setRegion(region, animated: true)
println("Latitude = \(newLocation.coordinate.latitude)")
println("Longitude = \(newLocation.coordinate.longitude)")
locNow = newLocation
}
and this is the shown distance in meters on the map : 5718215.17 (when the pin is made next to the pointed location on the map as the device location)

Resources