Вычислить новую координату х метров и у градусов от одной координаты - PullRequest
30 голосов
/ 09 июля 2011

Я, должно быть, что-то упустил в документах, я думал, что это должно быть легко ...

Если у меня есть одна координата и я хочу получить новую координату на расстоянии х метров, в каком-то направлении. Как мне это сделать?

Я ищу что-то вроде

-(CLLocationCoordinate2D) translateCoordinate:(CLLocationCoordinate2D)coordinate translateMeters:(int)meters translateDegrees:(double)degrees;

Спасибо!

Ответы [ 4 ]

32 голосов
/ 09 июля 2011

К сожалению, в API нет такой функции, поэтому вам придется написать свою собственную.

Этот сайт дает несколько вычислений, включающих широту / долготу и пример кода JavaScript.В частности, в разделе «Точка назначения с учетом расстояния и пеленга от начальной точки» показано, как рассчитать то, что вы просите.

Код JavaScript находится внизу этой страницы, и вот один из возможных способов его преобразования.в Objective-C:

- (double)radiansFromDegrees:(double)degrees
{
    return degrees * (M_PI/180.0);    
}

- (double)degreesFromRadians:(double)radians
{
    return radians * (180.0/M_PI);
}

- (CLLocationCoordinate2D)coordinateFromCoord:
        (CLLocationCoordinate2D)fromCoord 
        atDistanceKm:(double)distanceKm 
        atBearingDegrees:(double)bearingDegrees
{
    double distanceRadians = distanceKm / 6371.0;
      //6,371 = Earth's radius in km
    double bearingRadians = [self radiansFromDegrees:bearingDegrees];
    double fromLatRadians = [self radiansFromDegrees:fromCoord.latitude];
    double fromLonRadians = [self radiansFromDegrees:fromCoord.longitude];

    double toLatRadians = asin( sin(fromLatRadians) * cos(distanceRadians) 
        + cos(fromLatRadians) * sin(distanceRadians) * cos(bearingRadians) );

    double toLonRadians = fromLonRadians + atan2(sin(bearingRadians) 
        * sin(distanceRadians) * cos(fromLatRadians), cos(distanceRadians) 
        - sin(fromLatRadians) * sin(toLatRadians));

    // adjust toLonRadians to be in the range -180 to +180...
    toLonRadians = fmod((toLonRadians + 3*M_PI), (2*M_PI)) - M_PI;

    CLLocationCoordinate2D result;
    result.latitude = [self degreesFromRadians:toLatRadians];
    result.longitude = [self degreesFromRadians:toLonRadians];
    return result;
}

В коде JS он содержит эту ссылку , которая показывает более точный расчет для расстояний, превышающих 1/4 окружности Земли.

Также обратите внимание, что приведенный выше код допускает расстояние в км, поэтому перед проходом обязательно делите метры на 1000.0.

13 голосов
/ 09 июля 2011

Я нашел один способ сделать это, пришлось копать, чтобы найти правильные структуры и функции. В итоге я использовал не градусы, а метры для широты и долготы.

Вот как я это сделал:

-(CLLocationCoordinate2D)translateCoord:(CLLocationCoordinate2D)coord MetersLat:(double)metersLat MetersLong:(double)metersLong{

    CLLocationCoordinate2D tempCoord;

    MKCoordinateRegion tempRegion = MKCoordinateRegionMakeWithDistance(coord, metersLat, metersLong);
    MKCoordinateSpan tempSpan = tempRegion.span;

    tempCoord.latitude = coord.latitude + tempSpan.latitudeDelta;
    tempCoord.longitude = coord.longitude + tempSpan.longitudeDelta;

    return tempCoord;

}

И, конечно, если мне действительно понадобится использовать градусы в будущем, довольно легко (я думаю ...) внести некоторые изменения в вышеприведенное, чтобы заставить его работать так, как я и просил.

5 голосов
/ 21 июля 2012

Использование MKCoordinateRegion имеет некоторые проблемы - возвращаемую область можно отрегулировать так, чтобы она соответствовала, поскольку две дельты могут не точно отображаться в проекции на этой широте, если вы хотите, чтобы нулевая дельта для одной из осей вам не повезлои т. д.

Эта функция использует MKMapPoint для выполнения перевода координат, что позволяет перемещать точки в координатном пространстве проекции карты и затем извлекать координаты из этого.

CLLocationCoordinate2D MKCoordinateOffsetFromCoordinate(CLLocationCoordinate2D coordinate, CLLocationDistance offsetLatMeters, CLLocationDistance offsetLongMeters) {
    MKMapPoint offsetPoint = MKMapPointForCoordinate(coordinate);

    CLLocationDistance metersPerPoint = MKMetersPerMapPointAtLatitude(coordinate.latitude);
    double latPoints = offsetLatMeters / metersPerPoint;
    offsetPoint.y += latPoints;
    double longPoints = offsetLongMeters / metersPerPoint;
    offsetPoint.x += longPoints;

    CLLocationCoordinate2D offsetCoordinate = MKCoordinateForMapPoint(offsetPoint);
    return offsetCoordinate;
}
4 голосов
/ 20 октября 2016

Ответ Nicsoft фантастический и именно то, что мне было нужно. Я создал 3-летнюю версию Swift, которая является немного более лаконичной и может вызываться непосредственно на экземпляре CLLocationCoordinate2D:

public extension CLLocationCoordinate2D {

  public func transform(using latitudinalMeters: CLLocationDistance, longitudinalMeters: CLLocationDistance) -> CLLocationCoordinate2D {
    let region = MKCoordinateRegionMakeWithDistance(self, latitudinalMeters, longitudinalMeters)
    return CLLocationCoordinate2D(latitude: latitude + region.span.latitudeDelta, longitude: longitude + region.span.longitudeDelta)
  }

}
...