Вычислить новую координату х метров и у градусов от одной координаты
Я, должно быть, что-то упустил в документах, я думал, что это должно быть легко...
Если у меня есть одна координата и я хочу получить новую координату на расстоянии х метров, в каком-то направлении. Как мне это сделать?
Я ищу что-то вроде
-(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)
}
}