Can I rotate car using location in Google map? - ios

I got this data from the socket and I need to change the rotation of
car base on changed location. how can I rotate(left, right, top,
bottom) car?
{
carType = Sedan;
latitude = "41.738751";
longitude = "-88.274285";
}
I also try this but doesn't work:
float dy = newLocation.latitude - oldLocation.latitude;
float dx = cosf(M_PI/180*oldLocation.latitude)*(newLocation.longitude - oldLocation.longitude);
float angle = atan2f(dy, dx);
driverMarker.rotation = angle;

You can change the rotation like:
marker.rotation = angle value

You can use this to get the angle for rotating the car marker:
func angleBetween(oldLocation: CLLocation, newLocation: CLLocation) -> Double {
let originLocation = CLLocation(latitude: newLocation.coordinate.latitude - oldLocation.coordinate.latitude, longitude: newLocation.coordinate.longitude - oldLocation.coordinate.longitude)
let bearingRadians = atan2(originLocation.coordinate.latitude, originLocation.coordinate.longitude)
let bearingDegrees = bearingRadians * 180 / Double.pi
return bearingDegrees
}
And you can use it like this
let angle = angleBetween(oldLocation: oldLocation, newLocation: newLocation)
And you can use marker.rotation like #Daljeet said:
marker.rotation = angle

Use Core Location delegate method.
It will give the direction of your phone.
func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading)
{
let direction = newHeading.trueHeading as Double
print("Direction :- \(direction)");
currentLoaction.rotation = direction
}
Set those direction for your location marker.
here: currentLoaction is
var currentLoaction:GMSMarker = GMSMarker()
Hope this will help you if you used Google Map.

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

Converting two coordinate points to distance in west-east-facing and north-south-facing direction

I'm trying to find out how to calculate the "west-east-facing" distance and the "north-south-facing" distance between two points respectively given the coordinates of the two points (with latitude and longitude), in order to find out the degree in which the line differs from the northern direction.
In short I need to calculate x and y in meters in order to get the degree of alpha, when x and y are given by longitude and latitude.
I know CLLocation has a function to calculate the distance between two points:
distance(from location: CLLocation) -> CLLocationDistance
and I tried to open the source code of that function in order to figure out how to separate the two components but I did not find out how to open that code.
You can use this
func getDistanceAndAngle(positionA: CLLocation, positionB: CLLocation) -> (Float, Float, Float){
let distanceInMeters = Float(positionA.distance(from: positionB)) // result is in meters
print(distanceInMeters)
//search for the degree
let angle = bearingFromLocation(fromLocation: positionA.coordinate, toLocation: positionB.coordinate)
print("ANGLE", angle)
let xDistance = abs(distanceInMeters * cos(DegreesToRadians(degrees: angle)))
let yDistance = abs(distanceInMeters * sin(DegreesToRadians(degrees: angle)))
return (xDistance,yDistance,angle)
}
func bearingFromLocation(fromLocation:CLLocationCoordinate2D, toLocation: CLLocationCoordinate2D)-> Float{
let lat1 = DegreesToRadians(degrees: Float(fromLocation.latitude))
let lon1 = DegreesToRadians(degrees: Float(fromLocation.longitude))
let lat2 = DegreesToRadians(degrees: Float(toLocation.latitude))
let lon2 = DegreesToRadians(degrees: Float(toLocation.longitude))
let dLon = lon2 - lon1
let y = sin(dLon) * cos(lat2)
let x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon)
let radiansBearing = atan2(y, x)
print("radian", radiansBearing)
let degreesBearing = RadiansToDegrees(radians: radiansBearing)
print("deg", degreesBearing)
if (degreesBearing >= 0) {
return degreesBearing
} else {
return degreesBearing + 360.0
}
}
func DegreesToRadians(degrees: Float)->Float {return degrees * Float.pi / 180.0}
func RadiansToDegrees(radians: Float)->Float {return radians * 180.0/Float.pi}
notes:
the angle is from north to east
so north is 0 degree and east is 90 degree.
the X and Y is always positive. So if you want to make it negative to the left and down, you can try to put use degree to make it right.
You can convert point1 and point2 to MKMapPoint. It's gives you coordinates which is projected map in 2D plane. Then you can eaisily get difference of x's and y's.. And using simple math, you can calculate the alpha value. You can initialize MKMapPoint with CLLocationCoordinate2D.
https://developer.apple.com/documentation/mapkit/mkmappoint
Assuming we have:
let locationA = CLLocation(..)
let locationB = CLLocation(..)
I would probably still want to use Apple's provided functions and create new locations that only differ in latitude or longitude. Something like:
let latitudeA = CLLocation(latitude: locationA.latitude, longitude: locationA.longitude)
// notice I use latitude from B but KEEP longitude from A to keep them parallel)
let latitudeB = CLLocation(latitude: locationB.latitude, longitude: locationA.longitude)
let northSouthDistance = latitudeA.distance(from: latitudeB)
etc

How can can I get equidistant location on a MKPolyline?

I need to find equidistant locations on a MKPolyline to add annotations as shown below.
My function to get locations on MKPolyline is given below, I have the values start and end coordinates of Polyline. But the locations are slightly ,moving out of polyline as shown in the image below
My function to find location is
func getEquidistantPoints(from startPoint: CLLocationCoordinate2D, to endPoint: CLLocationCoordinate2D, numberOfPoints: Int) -> [CLLocationCoordinate2D] {
var midPoints: [CLLocationCoordinate2D] = []
var newPoint: CLLocationCoordinate2D = CLLocationCoordinate2DMake(0, 0)
let count = numberOfPoints + 1
let latitudeModifier = (endPoint.latitude - startPoint.latitude) / Double(count)
let longitudeModifier = (endPoint.longitude - startPoint.longitude) / Double(count)
for i in 0..<count {
newPoint.latitude = CLLocationDegrees(startPoint.latitude + (latitudeModifier * Double(i)))
newPoint.longitude = CLLocationDegrees(startPoint.longitude + (longitudeModifier * Double(i)))
midPoints.append(newPoint)
}
return midPoints
}
In viewdidload
let coordinatesArray = getEquidistantPoints(from: sourceCoordinate, to: destinationCoordinate, numberOfPoints: 5)
for coordinate in coordinatesArray {
let annotation = MKPointAnnotation()
annotation.coordinate = coordinate
self.mapView.addAnnotation(annotation)
}
How can I solve this error in calculating locations?
The problem is that the earth is round. So your "line" is not a line; it is a curve traced out on the surface of a nominal sphere. You cannot find "equidistant" points along the line using your simple-minded method. You need to use some much more serious math than you are using. This will prove to be far from trivial.

Google Maps zoom out to GPS and markers

I am trying to show three things on map :
GPS (the current location) , Marker 1 , Marker 2, but I am not sure I am doing it right or not ! Here is my code :
self.startMarker.position = CLLocationCoordinate2D(latitude: self.startLatitude, longitude: self.startLongitude)
self.startMarker.icon = #imageLiteral(resourceName: "Pin Start")
self.startMarker.map = self.mapView
self.endMarker.position = CLLocationCoordinate2D(latitude: self.endLatitude, longitude: self.endLongitude)
self.endMarker.icon = #imageLiteral(resourceName: "Pin End")
self.endMarker.map = self.mapView
let southWest = CLLocationCoordinate2DMake(self.startLatitude,self.startLongitude)
let northEast = CLLocationCoordinate2DMake(self.endLatitude,self.endLongitude)
let bounds = GMSCoordinateBounds(coordinate: northEast, coordinate: southWest)
let camera = self.mapView.camera(for: bounds, insets:.zero)
self.mapView.camera = camera!
More Code :
// MARK: - Google Map
private func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status == CLAuthorizationStatus.authorizedWhenInUse {
mapView.isMyLocationEnabled = true
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let newLocation = locations.last
mapView.camera = GMSCameraPosition.camera(withTarget: newLocation!.coordinate, zoom: 14)
mapView.isMyLocationEnabled = true
}
The result is like this :
What I need :
EDITED
if let myLocation = self.mapView.myLocation {
let path = GMSMutablePath()
path.add(myLocation.coordinate)
path.add(self.startMarker.position)
path.add(self.endMarker.position)
let bounds = GMSCoordinateBounds(path: path)
self.mapView.animate(with: GMSCameraUpdate.fit(bounds, withPadding: 40))
}
Showing All Markers with screen bound:
Here I am trying to provide you one simple example, hope this will help you.
Using this, you can show any number of markers on screen.
Example:
let path = GMSMutablePath()
for var i in 0 ..< array.count //Here take your "array" which contains lat and long.
{
let marker = GMSMarker()
let lat = Double(array.objectAtIndex(i).valueForKey(lattitude) as! String)
let long = Double(arrayr.objectAtIndex(i).valueForKey(longitude) as! String)
marker.position = CLLocationCoordinate2DMake(lat!,long!)
path.addCoordinate(marker.position)
marker.map = self.mapView
}
let bounds = GMSCoordinateBounds(path: path)
self.mapView!.animateWithCameraUpdate(GMSCameraUpdate.fitBounds(bounds, withPadding: 30.0))
Can you try the below code, this is converted from ObjC code here is the documentation of includingCoordinate
let bounds = GMSCoordinateBounds()
bounds.includingCoordinate(self.startMarker.position)
bounds.includingCoordinate(self.endMarker.position)
bounds.includingCoordinate(yourCurrentLocationPosition)
self.mapView.animateWithCameraUpdate(GMSCameraUpdate(fitBounds:bounds, padding:20.0f))
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
showMarkers(locations)
//stop updating location when you find suitable
}
func showMarkers(userLocation: [CLLocation]){
let location1: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: self.startLatitude, longitude: self.startLongitude)
let location2: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: self.endLatitude, longitude: self.endLongitude)
let location3: CLLocationCoordinate2D = userLocation[0].coordinate
var locationArray = []
locationArray.append(location1)
locationArray.append(location2)
locationArray.append(location3)
var bounds = GMSCoordinateBounds()
for location in locationArray
{
let latitude = location.valueForKey("latitude")
let longitude = location.valueForKey("longitude")
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
marker.map = self.mapView
bounds = bounds.includingCoordinate(marker.position)
}
let update = GMSCameraUpdate.fitBounds(bounds, withPadding: 100)
mapView.animateWithCameraUpdate(update)
}
Note:
locationArray contains three locations ie. Marker 1, Marker 2, user location.
For someone who is looking for solution with Objective-C, This might help
//Locations
CLLocationCoordinate2D source = CLLocationCoordinate2DMake(19.2880, 72.1587);
CLLocationCoordinate2D userLocation = CLLocationCoordinate2DMake(19.1780, 72.9577);
CLLocationCoordinate2D destination = CLLocationCoordinate2DMake(19.0760, 72.8777);
//Create a GMSMutablePath
GMSMutablePath *path = [GMSMutablePath new];
[path addCoordinate:source];
[path addCoordinate:userLocation];
[path addCoordinate:destination];
//Create bounds
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc]initWithPath:path];
//Update the camera position
[mapview animateWithCameraUpdate:[GMSCameraUpdate fitBounds:bounds]];

Change Pin direction in iOS Map

SWIFT 3.0
MKMAPVIEW
iOS
Note : - (Integrated AppleMap ,Not working with GoogleMap)
I have done the following :
Implemented map and Added custom Image to User Location Annotation
When map open , it shows User Location at right Place
My Requirement :
When User Move into different direction staying at same place (or
different place) the pin (at current location) should automatically
point the direction in which user points.
E.g : If Boat is showing at User Location position and its pointing toward North but if user move toward West then boat (User Location Pin) also should point to that direction.
Tried with following Code :
//MARK:Change Direction Methods
func angle(fromCoordinate first: CLLocationCoordinate2D, toCoordinate second: CLLocationCoordinate2D) -> Float {
let deltaLongitude = second.longitude - first.longitude
let deltaLatitude = second.latitude - first.latitude
let angle = (.pi * 0.5) - atan(deltaLatitude / deltaLongitude)
if deltaLongitude > 0 {
return Float(angle)
}
else if deltaLongitude < 0 {
return Float(angle) + .pi
}
else if deltaLatitude < 0 {
return .pi
}
return 0.0
}
//Animate direction of User Location
func animateUserLocation() {
//Old Coordinate (PLAT - Previous Lat , PLON - Previous Long)
let oldLocation = CLLocationCoordinate2D(latitude: UserDefaults.standard.value(forKey: "PLAT") as! CLLocationDegrees, longitude: UserDefaults.standard.value(forKey: "PLON") as! CLLocationDegrees)
//New Coordinate (PLAT - Current Lat , PLON - Current Long)
let newLocation = CLLocationCoordinate2D(latitude: UserDefaults.standard.value(forKey: "LAT") as! CLLocationDegrees, longitude: UserDefaults.standard.value(forKey: "LON") as! CLLocationDegrees)
let getAngle = angle(fromCoordinate:oldLocation, toCoordinate:newLocation)
var myAnnotation : RestaurantAnnotation?
if annotationArray.count > 0{
myAnnotation = annotationArray[0]
}
else {
return
}
UIView.animate(withDuration: 2, animations: {() -> Void in
myAnnotation?.coordinate = newLocation
let annotationView = self.map.view(for: myAnnotation!)
annotationView?.transform = CGAffineTransform(rotationAngle: CGFloat(getAngle))
})
//Save Previous lat long
UserDefaults.standard.set(UserDefaults.standard.value(forKey: "LAT"), forKey: "PLAT")
UserDefaults.standard.set(UserDefaults.standard.value(forKey: "LON"), forKey: "PLON")
UserDefaults().synchronize()
}
Called animateUserLocation method from didUpdateLocation Method but no Luck.
Kindly share your suggestion what i am doing wrong . Thanks in advance.
Understanding iOS's location concepts completely helps to resolve any issue regarding AppleMap.
To move map Pin or AnnotationView , we can use the CoreLocation framework which outputs data related to the users current location.
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
var locationManager:CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.startUpdatingHeading()
}
func locationManager(manager: CLLocationManager!, didUpdateHeading heading: CLHeading!) {
// This will print out the direction the device is heading
println(heading.magneticHeading) }
}
}
In the above example, "heading.magneticHeading" will output a value representing the direction the device is pointed at.
0 means north
90 means east
180 means south
270 means west
everything else in between
The next step is to use those values and rotate your AnnotationView or Pin accordingly.
CGAffineTransformMakeRotation can help with this.
For example if you want to rotate to imageview to point to northeast, which would require a degree value of 45, your code might look something like this.
float degrees = 45
imageView.transform = CGAffineTransformMakeRotation(degrees * M_PI/180)
Just be aware that CGAffineTransformMakeRotation() expects a radian value, in the example above we've converted degrees to radians by multiplying degrees with the number of half circles.
Following links really helpful :
https://stackoverflow.com/a/7634232/3400991
Finally Resolved my issue. Hope this complete answer helps other too.

Resources