I have a CLLocation defined, and I'd like to move that point x meters to the east and y meters to the south. How may I achieve that?
-
2Keep in mind that you can't always move north/south from all points on the globe -- for instance, if you're at the North Pole, you can only go south. What are you trying to do here? – Sep 02 '11 at 01:13
-
@duskwuff : To make it simple, I want my userPos to make 100 step to the right, and 100 step back :-) – Oliver Sep 02 '11 at 09:25
11 Answers
A conversion to Swift, taken from this answer:
func locationWithBearing(bearingRadians:Double, distanceMeters:Double, origin:CLLocationCoordinate2D) -> CLLocationCoordinate2D { let distRadians = distanceMeters / (6372797.6) // earth radius in meters let lat1 = origin.latitude * M_PI / 180 let lon1 = origin.longitude * M_PI / 180 let lat2 = asin(sin(lat1) * cos(distRadians) + cos(lat1) * sin(distRadians) * cos(bearingRadians)) let lon2 = lon1 + atan2(sin(bearingRadians) * sin(distRadians) * cos(lat1), cos(distRadians) - sin(lat1) * sin(lat2)) return CLLocationCoordinate2D(latitude: lat2 * 180 / M_PI, longitude: lon2 * 180 / M_PI) }
Morgan Chen wrote this:
All of the math in this method is done in radians. At the start of the method, lon1 and lat1 are converted to radians for this purpose as well. Bearing is in radians too. Keep in mind this method takes into account the curvature of the Earth, which you don't really need to do for small distances.
My comments (Mar. 25, 2021):
The calculation used in this method is called solving the "direct geodesic problem", and this is discussed in C.F.F. Karney's article "Algorithms for geodesics", 2012. The code given above uses a technique that is less accurate than the algorithms presented in Karney's article.

- 32,158
- 14
- 82
- 96
-
Dear Peter, thanks for the swift solution, but I need to correct one thing. Bearing should be in radian not double. I will post it as an answer since i can not paste the code here. – Koray Birand Jun 29 '15 at 23:59
-
18If it's unclear to anyone, bearing refers to the direction that you want to advance, in degrees, so for north: bearing = 0, for east: bearing = 90, for southwest: bearing = 225, etc... – Shaked Sayag Oct 18 '16 at 13:49
-
One note on this is that it doesn't wrap (i.e. 181 lat doesn't wrap to -181). – InkGolem Oct 28 '18 at 23:51
-
@ShakedSayag note that bearing in the current iteration of the answer is in radians, so it would be so for north: bearing = 0, for east: bearing = 0.5 pi, for south: bearing = pi; etc.. – Freek Sanders Mar 04 '19 at 12:33
-
Improved swift solution to Peters answer. Only correction is the bearing should be radian while calculation has been made.
func locationWithBearing(bearing:Double, distanceMeters:Double, origin:CLLocationCoordinate2D) -> CLLocationCoordinate2D {
let distRadians = distanceMeters / (6372797.6)
var rbearing = bearing * M_PI / 180.0
let lat1 = origin.latitude * M_PI / 180
let lon1 = origin.longitude * M_PI / 180
let lat2 = asin(sin(lat1) * cos(distRadians) + cos(lat1) * sin(distRadians) * cos(rbearing))
let lon2 = lon1 + atan2(sin(rbearing) * sin(distRadians) * cos(lat1), cos(distRadians) - sin(lat1) * sin(lat2))
return CLLocationCoordinate2D(latitude: lat2 * 180 / M_PI, longitude: lon2 * 180 / M_PI)
}

- 1,956
- 17
- 22
-
I've applied your solution. Mostly it works fine but there is some deflection happening as well. Why is that. Asked here: http://stackoverflow.com/questions/36382149/moving-gmsmarker-by-x-meters-deflects – Can Jun 13 '16 at 10:01
-
I have almost the same implementation (my implementation is equal with all of the answers ) but I have a problem for reverse the location again! as far as I know, we should add -(distance) but it has an error ( in Decimal numbers and point to a little bit far place ) and I can't extract the original location again! Any idea? – Mo Farhand Nov 02 '18 at 13:10
Great post, here's the Obj-C wrapper for those who love copy/paste:
- (CLLocationCoordinate2D) locationWithBearing:(float)bearing distance:(float)distanceMeters fromLocation:(CLLocationCoordinate2D)origin {
CLLocationCoordinate2D target;
const double distRadians = distanceMeters / (6372797.6); // earth radius in meters
float lat1 = origin.latitude * M_PI / 180;
float lon1 = origin.longitude * M_PI / 180;
float lat2 = asin( sin(lat1) * cos(distRadians) + cos(lat1) * sin(distRadians) * cos(bearing));
float lon2 = lon1 + atan2( sin(bearing) * sin(distRadians) * cos(lat1),
cos(distRadians) - sin(lat1) * sin(lat2) );
target.latitude = lat2 * 180 / M_PI;
target.longitude = lon2 * 180 / M_PI; // no need to normalize a heading in degrees to be within -179.999999° to 180.00000°
return target;
}

- 3,598
- 1
- 18
- 33

- 508
- 3
- 7
-
Does not work correctly. Gives different location for the different distance with the same bearing. – kirander Feb 03 '17 at 08:12
-
In a situation where a vehicle is moving and you want to know the location and distance at the precise moment, another useful addition/improvement would be a computation of distance since the last location based on an estimate of the speed of the moving vehicle. I think you would do this by computing time from the GPS signal, the timestamp variable, lagged behind the device clock time. Apple devices sample GPS location at 1 hz, but third-party GPS receivers that have APIs that interact with CLLocation sample at 4 to 10 hz (the Dual 150 and 160 models, for example). – Michael Young Nov 22 '19 at 22:05
Strange that nobody thought of using MKCoordinateRegion from MapKit to calculate that automatically.
import MapKit
extension CLLocation {
func movedBy(latitudinalMeters: CLLocationDistance, longitudinalMeters: CLLocationDistance) -> CLLocation {
let region = MKCoordinateRegion(center: coordinate, latitudinalMeters: abs(latitudinalMeters), longitudinalMeters: abs(longitudinalMeters))
let latitudeDelta = region.span.latitudeDelta
let longitudeDelta = region.span.longitudeDelta
let latitudialSign = CLLocationDistance(latitudinalMeters.sign == .minus ? -1 : 1)
let longitudialSign = CLLocationDistance(longitudinalMeters.sign == .minus ? -1 : 1)
let newLatitude = coordinate.latitude + latitudialSign * latitudeDelta
let newLongitude = coordinate.longitude + longitudialSign * longitudeDelta
let newCoordinate = CLLocationCoordinate2D(latitude: newLatitude, longitude: newLongitude)
let newLocation = CLLocation(coordinate: newCoordinate, altitude: altitude, horizontalAccuracy: horizontalAccuracy, verticalAccuracy: verticalAccuracy, course: course, speed: speed, timestamp: Date())
return newLocation
}
}

- 326
- 4
- 11
There is a C function that is close to what you are asking but it takes a bearing and distance. It's in my UtilitiesGeo class on github. You would pass the latitude and longitude from your CLLocation to it and then create a new CLLocation from the resulting lat2 and lon2 that it returns:
/*-------------------------------------------------------------------------
* Given a starting lat/lon point on earth, distance (in meters)
* and bearing, calculates destination coordinates lat2/lon2.
*
* all params in degrees
*-------------------------------------------------------------------------*/
void destCoordsInDegrees(double lat1, double lon1,
double distanceMeters, double bearing,
double* lat2, double* lon2);
If you can't use that, take a look at the algorithms that it was derived from here and here and perhaps you can modify it or those sites might have something closer to your needs.

- 75,956
- 16
- 112
- 147
-
that looks very very close (near perfect in fact) of what I'm searching for. Bearing param will help :-) I'll try this tonight. – Oliver Sep 02 '11 at 09:26
-
Does this function use distanceMeters as meters on the surface of the sphere, or through the sphere ? – Oliver Sep 02 '11 at 10:01
-
-
normalize180 make the longitude so that it's always in the range of -180 to +180. – progrmr Aug 26 '13 at 15:12
-
I have almost the same implementation (my implementation is equal with all of the answers ) but I have a problem for reverse the location again! as far as I know, we should add -(distance) but it has an error ( in Decimal numbers and point to a little bit far place ) and I can't extract the original location again! Any idea? – Mo Farhand Nov 02 '18 at 13:09
Slight adjustment to @CocoaChris answer: now a category on CLLocation, and using the built-in units.
#import <CoreLocation/CoreLocation.h>
@interface CLLocation (Movement)
- (CLLocation *)locationByMovingDistance:(double)distanceMeters withBearing:(CLLocationDirection)bearingDegrees;
@end
@implementation CLLocation (Movement)
- (CLLocation *)locationByMovingDistance:(double)distanceMeters withBearing:(CLLocationDirection)bearingDegrees
{
const double distanceRadians = distanceMeters / (6372797.6); // earth radius in meters
const double bearingRadians = bearingDegrees * M_PI / 180;
float lat1 = self.coordinate.latitude * M_PI / 180;
float lon1 = self.coordinate.longitude * M_PI / 180;
float lat2 = asin(sin(lat1) * cos(distanceRadians) + cos(lat1) * sin(distanceRadians) * cos(bearingRadians));
float lon2 = lon1 + atan2(sin(bearingRadians) * sin(distanceRadians) * cos(lat1),
cos(distanceRadians) - sin(lat1) * sin(lat2) );
return [[CLLocation alloc] initWithLatitude:lat2 * 180 / M_PI
longitude:lon2 * 180 / M_PI];
}
@end

- 16,078
- 4
- 53
- 57
-
I have almost the same implementation (my implementation is equal with all of the answers ) but I have a problem for reverse the location again! as far as I know, we should add -(distance) but it has an error ( in Decimal numbers and point to a little bit far place ) and I can't extract the original location again! Any idea? – Mo Farhand Nov 02 '18 at 13:10
-
Hi @Mohamad, it could be a numerical precision error, have you tried using doubles instead of floats? – joerick Nov 07 '18 at 20:49
-
Hi @joerick I'm using double and it's happening even in the reference website https://www.movable-type.co.uk/scripts/latlong.html "Destination point given distance and bearing from start point" I don't know what's wrong. – Mo Farhand Nov 09 '18 at 18:44
A simpler solution is to use MKMapPoints.
Convert your original coordinates, and any offset distances you need to MKMapPoints using this:
let coordinatesInMapPoints = MKMapPointForCoordinate(CLLocationCoordinate2D)
let distancesInMapPoints = yourDistanceInMeters * MKMapPointsPerMeterAtLatitude(CLLocationDegrees) // Do this for both x and y directions if needed.
Then make a new MKMapPoint by simply adding your offset distances to your original coordinates:
let newCoordinatesInMapPoints = MKMapPointMake(coordinatesInMapPoints.x + distancesInMapPoints, coordinatesInMapPoints.y)
Finally, convert the new coordinates from a MKMapPoint back to CLLocationCoordinate2D:
let newCoordinate = MKCoordinateForMapPoint(newCoordinatesInMapPoints)
No complex conversion calculations needed.

- 59
- 2
-
-
If different offset distance, then repeat line 2 with a different "yourDistanceInMeters" and add that to "coordinatesInMapPoints.y". If same offset distance, then only need to add "distancesInMapPoints" to "coordinatesInMapPoints.y" – hubear Jan 17 '19 at 16:43
Swift implementation using Measurement
struct to do the conversions between degrees and radians.
class GPSLocation {
public class func degreesToRadians(degrees: Double) -> Double {
return Measurement(value: degrees, unit: UnitAngle.degrees).converted(to: .radians).value
}
public class func radiansToDegrees(radians: Double) -> Double {
return Measurement(value: radians, unit: UnitAngle.radians).converted(to: .degrees).value
}
public class func location(location: CLLocation, byMovingDistance distance: Double, withBearing bearingDegrees:CLLocationDirection) -> CLLocation {
let distanceRadians: Double = distance / 6372797.6
let bearingRadians: Double = GPSLocation.degreesToRadians(degrees: bearingDegrees)
let lat1 = GPSLocation.degreesToRadians(degrees: location.coordinate.latitude)
let lon1 = GPSLocation.degreesToRadians(degrees: location.coordinate.longitude)
let lat2 = GPSLocation.radiansToDegrees(radians:asin(sin(lat1) * cos(distanceRadians) + cos(lat1) * sin(distanceRadians) * cos(bearingRadians)))
let lon2 = GPSLocation.radiansToDegrees(radians:lon1 + atan2(sin(bearingRadians) * sin(distanceRadians * cos(lat1)), cos(distanceRadians) - sin(lat1) * sin(lat2)))
return CLLocation(latitude: lat2, longitude: lon2)
}
}

- 843
- 1
- 9
- 26
Swift 4.2 as a CGPoint extension
Derived from Peter O.'s solution
FloatingPoint extension: thanks to https://stackoverflow.com/a/29179878/2500428
extension FloatingPoint
{
var degreesToRadians: Self { return self * .pi / 180 }
var radiansToDegrees: Self { return self * 180 / .pi }
}
extension CGPoint
{
// NOTE: bearing is in radians
func locationWithBearing(bearing: Double, distanceMeters: Double) -> CGPoint
{
let distRadians = distanceMeters / (6372797.6) // earth radius in meters
let origLat = Double(self.y.degreesToRadians)
let origLon = Double(self.x.degreesToRadians)
let newLat = asin(sin(origLat) * cos(distRadians) + cos(origLat) * sin(distRadians) * cos(bearing))
let newLon = origLon + atan2(sin(bearing) * sin(distRadians) * cos(origLat), cos(distRadians) - sin(origLat) * sin(newLat))
return CGPoint(x: newLon.radiansToDegrees, y: newLat.radiansToDegrees)
}
}
Usage:
let loc = CGPoint(x: lon, y: lat)
let newLoc = loc.locationWithBearing(bearing: 90.degreesToRadians, distanceMeters: 500.0)

- 1,187
- 10
- 26
Swift 4
extension CLLocationCoordinate2D {
/// Get coordinate moved from current to `distanceMeters` meters with azimuth `azimuth` [0, Double.pi)
///
/// - Parameters:
/// - distanceMeters: the distance in meters
/// - azimuth: the azimuth (bearing)
/// - Returns: new coordinate
func shift(byDistance distanceMeters: Double, azimuth: Double) -> CLLocationCoordinate2D {
let bearing = azimuth
let origin = self
let distRadians = distanceMeters / (6372797.6) // earth radius in meters
let lat1 = origin.latitude * Double.pi / 180
let lon1 = origin.longitude * Double.pi / 180
let lat2 = asin(sin(lat1) * cos(distRadians) + cos(lat1) * sin(distRadians) * cos(bearing))
let lon2 = lon1 + atan2(sin(bearing) * sin(distRadians) * cos(lat1), cos(distRadians) - sin(lat1) * sin(lat2))
return CLLocationCoordinate2D(latitude: lat2 * 180 / Double.pi, longitude: lon2 * 180 / Double.pi)
}
}
Usage
let point: CLLocationCoordinate2D!
let north100 = point.shift(byDistance: 100, azimuth: 0) // 100m to North
let south100 = point.shift(byDistance: 100, azimuth: Double.pi) // 100m to South

- 7,904
- 1
- 47
- 44
-
This is answer is very clear. Can you please share the azimuth values for "100m to East" and "100m to West"? – thus Feb 18 '20 at 12:06
-
1
-
I posted an updated answer to a measurement question, which includes an answer to this plotting one. Here: CLLocation Category for Calculating Bearing w/ Haversine function

- 4,880
- 4
- 24
- 21