Moving a CLLocation by x meters

前端 未结 11 938
余生分开走
余生分开走 2020-11-30 04:54

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?

相关标签:
11条回答
  • 2020-11-30 05:12

    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.

    0 讨论(0)
  • 2020-11-30 05:14

    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.

    0 讨论(0)
  • 2020-11-30 05:15

    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
    
    0 讨论(0)
  • 2020-11-30 05:16

    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)
        }
    
    }
    
    0 讨论(0)
  • 2020-11-30 05:17

    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

    0 讨论(0)
  • 2020-11-30 05:27

    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
        }
    }
    
    0 讨论(0)
提交回复
热议问题