Calculate new coordinates with starting position and distance
Ok, after some more digging, I found this answer, which resolves my problem. Here is my complete solution in swift:
internal func moveToLocation(location: CLLocationCoordinate2D, distance: Double) {
let angle = self.calculateAngleBetweenLocations(self.currentLocation, targetLocation: location)
let newLocation = self.coordinates(self.currentLocation, atDistance: distance, atAngle: angle)
self.moveUser(newLocation: newLocation)
}
private func coordinates(startingCoordinates: CLLocationCoordinate2D, atDistance: Double, atAngle: Double) -> CLLocationCoordinate2D {
let distanceRadians = atDistance / 6371
let bearingRadians = self.degreesToRadians(atAngle)
let fromLatRadians = self.degreesToRadians(startingCoordinates.latitude)
let fromLonRadians = self.degreesToRadians(startingCoordinates.longitude)
let toLatRadians = asin(sin(fromLatRadians) * cos(distanceRadians) + cos(fromLatRadians) * sin(distanceRadians) * cos(bearingRadians))
var toLonRadians = fromLonRadians + atan2(sin(bearingRadians) * sin(distanceRadians) * cos(fromLatRadians), cos(distanceRadians) - sin(fromLatRadians) * sin(toLatRadians));
toLonRadians = fmod((toLonRadians + 3 * M_PI), (2 * M_PI)) - M_PI
let lat = self.radiansToDegrees(toLatRadians)
let lon = self.radiansToDegrees(toLonRadians)
return CLLocationCoordinate2D(latitude: lat, longitude: lon)
}
private func calculateAngleBetweenLocations(currentLocation: CLLocationCoordinate2D, targetLocation: CLLocationCoordinate2D) -> Double {
let fLat = self.degreesToRadians(currentLocation.latitude);
let fLng = self.degreesToRadians(currentLocation.longitude);
let tLat = self.degreesToRadians(targetLocation.latitude);
let tLng = self.degreesToRadians(targetLocation.longitude);
let deltaLng = tLng - fLng
let y = sin(deltaLng) * cos(tLat)
let x = cos(fLat) * sin(tLat) - sin(fLat) * cos(tLat) * cos(deltaLng)
let bearing = atan2(y, x)
return self.radiansToDegrees(bearing)
}
private func degreesToRadians(x: Double) -> Double {
return M_PI * x / 180.0
}
private func radiansToDegrees(x: Double) -> Double {
return x * 180.0 / M_PI
}
Calculate new coordinate with given coordinate and distance in meters
One way would be to define helper methods that make it easy to calculate new coordinates based on a coordinate given a distance in meters using the MapKit and CoreLoation like so:
// Create new coordinate with equal latitude and longitude distances (distance can be both positive and negative).
func coordinate(from coordinate: CLLocationCoordinate2D, distance: CLLocationDistance) -> CLLocationCoordinate2D {
return self.coordinate(from: coordinate, latitudeDistance: distance, longitudeDistance: distance)
}
// Create new coordinate with latitude and longitude distances (distances can be both positive and negative).
func coordinate(from coordinate: CLLocationCoordinate2D, latitudeDistance: CLLocationDistance, longitudeDistance: CLLocationDistance) -> CLLocationCoordinate2D {
let region = MKCoordinateRegionMakeWithDistance(coordinate, latitudeDistance, longitudeDistance)
let newLatitude = coordinate.latitude + region.span.latitudeDelta
let newLongitude = coordinate.longitude + region.span.longitudeDelta
return CLLocationCoordinate2D(latitude: newLatitude, longitude: newLongitude)
}
Then the above code would simply look like this:
let coordinate = CLLocationCoordinate2D(latitude: 9.0, longitude: 50.0)
let distance: CLLocationDistance = 5000 // 5km
let topLeftCoordinate = self.coordinate(from: coordinate, distance: -distance)
let bottomRightCoordinate = self.coordinate(from: coordinate, distance: distance)
Hope it helps someone out there when coming across this.
Precautious Info: Just in case someone thinks (as many seem to do) that a self-answered question isn't appropriate on SO, please read this first.
Calculate Coord from start point, endpoint, and distance
Thanks to @HansKilian and @cletus (Calculate distance between 2 GPS coordinates), I could find the solution
private const double EARTH_RADIUS = 6378.1;
private static double ConvertToRadians(double angle)
{
return (Math.PI / 180) * angle;
}
private static double ConvertToDegree(double angle)
{
return angle * (180.0 / Math.PI);
}
private static double CalculateBearing(CoordsDto from, CoordsDto to)
{
var from_lat_rad = ConvertToRadians(from.Latitud);
var to_lat_rad = ConvertToRadians(to.Latitud);
var dif_lng_rad = ConvertToRadians(to.Longitud - from.Longitud);
double x = Math.Cos(from_lat_rad) * Math.Sin(to_lat_rad) - Math.Sin(from_lat_rad) * Math.Cos(to_lat_rad) * Math.Cos(dif_lng_rad);
double y = Math.Sin(dif_lng_rad) * Math.Cos(to_lat_rad);
// Math.Atan2 can return negative value, 0 <= output value < 2*PI expected
return (Math.Atan2(y, x) + Math.PI * 2) % (Math.PI * 2);
}
public static CoordsDto GetPointFarAway(CoordsDto from, CoordsDto to, double meterAwayFromStart)
{
var resp = new CoordsDto();
var bearing_rad = CalculateBearing(from, to);
var d = meterAwayFromStart * 0.001; //KM
var input_lat1_rad = ConvertToRadians(from.Latitud);
var input_lon1_rad = ConvertToRadians(from.Longitud);
var newPoint_lat_rad = Math.Asin(
Math.Sin(input_lat1_rad) * Math.Cos(d / EARTH_RADIUS) + Math.Cos(input_lat1_rad) * Math.Sin(d / EARTH_RADIUS) * Math.Cos(bearing_rad)
);
var newPoint_lon_rad = input_lon1_rad + Math.Atan2(
Math.Sin(bearing_rad) * Math.Sin(d / EARTH_RADIUS) * Math.Cos(input_lat1_rad),
Math.Cos(d / EARTH_RADIUS) - Math.Sin(input_lat1_rad) * Math.Sin(newPoint_lat_rad)
);
resp.Latitud = ConvertToDegree(newPoint_lat_rad);
resp.Longitud = ConvertToDegree(newPoint_lon_rad);
return resp;
}
Create coordinate based on distance and direction
You can use formula from this excellent site (section Destination point given distance and bearing from start point)
var φ2 = Math.asin( Math.sin(φ1)*Math.cos(d/R) +
Math.cos(φ1)*Math.sin(d/R)*Math.cos(brng) );
var λ2 = λ1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(φ1),
Math.cos(d/R)-Math.sin(φ1)*Math.sin(φ2));
where φ is latitude, λ is longitude, θ is the bearing (clockwise from north), δ is the angular distance d/R; d being the distance travelled, R the earth’s radius
Calculate coordinate by distance from another coordinate
CLLocation Point1;
CLLocation Point2;
float targetDistance;
float length = sqrt((Point1.x-Point2.x)*(Point1.x-Point2.x) + (Point1.y-Point2.y)*(Point1.y-Point2.y));
CLLocation result;
result.x = Point1.x + (Point2.x-Point1.x)*(targetDistance/length);
result.y = Point1.y + (Point2.y-Point1.y)*(targetDistance/length);
Or in other words Point1 + normalized(Point2-Point1)*targetDistance
Since you have an angle you could also do:
Point1 + (cos(angle)*targetDistance, sin(angle)*targetDistance)
Find destination coordinates given starting coordinates, bearing, and distance
According to this page
math.sin(x)
... Return the sine of x radians.
So, you need to convert lat1 and lon1 to radians before your equation and then later you can convert lat2 and lon2 back into degrees.
Related Topics
Nsfilemanager Moveitem Throws Error Code=513
Admob Interstitial Alway Returns False
Avcapturevideopreviewlayer Add Overlays and Capture Photo in iOS
How to Turn Off Core Data Write-Ahead Logging in Swift Using Options Dictionary
Avaudioplayer Working on Simulator But Not on Real Device
Adding Firebase Data to an Array in iOS Swift
Keep a View Always on Top (Don't Scroll with Keyboard) in Iqkeyboardmanager
Ios-Charts How to Put Uiimage Beside a Point
Multiple Image Pickers in One Controller
The Meaning of "Withevent" in Swift, and Parameter Modifiers in General
Change Splash Screen Image Programmatically
How to Use Urlsession with Proxy in Swift 3
Find Delegate in a Swift Array of Delegates
Change Uipopoverview Background + Arrow Color
Get Section Number in Custom Cell Button Action
Change Push Notifications Programmatically in Swift
How to Update a Swiftui View State from Outside (Uiviewcontroller for Example)