Вычислить новую координату х метров и у градусов от одной координаты

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

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

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

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

Спасибо!

4 ответа

К сожалению, в 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.

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

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

-(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;

}

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

Используя 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;
}

Ответ Nicsoft фантастический и именно то, что мне нужно. Я создал Swift 3-й версии, которая немного более краткая и может быть вызвана непосредственно на 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)
  }

}
Другие вопросы по тегам