View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0001188 | SAS.Планета | Хотелка / Feature request | public | 26-02-2012 10:05 | 02-10-2012 18:26 |
| Reporter | vdemidov | Assigned To | zed | ||
| Priority | normal | Severity | minor | Reproducibility | N/A |
| Status | resolved | Resolution | fixed | ||
| Product Version | 110418 | ||||
| Target Version | 121010 | Fixed in Version | 121010 | ||
| Summary | 0001188: Алгоритм проецирования точки на эллипсоиде | ||||
| Description | Нужен алгоритм проецирования точки на эллипсоиде. То есть функция получает координаты исходной точки, азимут и расстояние в метрах, а возвращает координаты новой точки. | ||||
| Additional Information | http://ru.wikipedia.org/wiki/Ортодромия | ||||
| Tags | No tags attached. | ||||
| Attached Files | geo84.pas (7,462 bytes)
///////////////////////////////////////////////////////////////////////////////
//
// Thaddeus Vincenty's inverse formula for ellipsoids
// Geodesic (shortest distance) between two points
//
// Lat1, Lon1, Lat2, Lon2 in radians
//
// Notes and Java script ? 2002-2006 Chris Veness
//
// Delphi Translation May 2006 Charles Seitz
{ For the benefit of the terminally obsessive (as well as the genuinely needy),
Thaddeus Vincenty (?TV?) devised formulae for calculating geodesic distances
between a pair of latitude/longitude points on the earth?s surface, using an
accurate ellipsoidal model of the earth. When I looked up the references
(?Direct and Inverse Solutions of Geodesics on the Ellipsoid with application
of nested equations?), I discovered to my surprise that while the mathematics
is utterly beyond me, it is actually quite simple to program. Vincenty?s
formula is accurate to within 0.5mm, or 0.000015? (!), on the ellipsoid being
used. Calculations based on a spherical model, such as the (much simpler)
Haversine, are accurate to around 0.3% (which is still good enough for most
purposes, of course).
Note: the accuracy quoted by Vincenty applies to the theoretical ellipsoid
being used, which will differ (to varying degree) from the real earth geoid.
If you happen to be located in Colorado, 2km above msl, distances will be
0.03% greater. In the UK, if you measure the distance from Land?s End to
John O? Groats using WGS-84, it will be 28m ? 0.003% ? greater than using the
Airy ellipsoid, which provides a better fit for the UK.}
UNIT GEO84;
INTERFACE
// Lat1, Lon1, Lat2, Lon2 in radians; Result in km
// W and S are negative
// Calculates TC12 (True) in radians
function
Geodesic(const Lat1, Lon1, Lat2, Lon2: Double; out TC12: Double): Double;
procedure
GeoRadial(const Lat1, Lon1, Tc, D: Double; out Lat, Lon: Double);
IMPLEMENTATION
uses
SysUtils, Math;
const // WGS-84 (meters)
a0 = 6378137.0000; // Earth radius at equator
b0 = 6356752.3142; // Earth radius at poles
f0 = 1/298.257223563; // Flattening
r0 = 1-f0;
aa = a0*a0; bb = b0*b0;
procedure RaiseException(Msg: string);
begin raise Exception.Create(Msg) end;
function
GeoDesic(const Lat1, Lon1, Lat2, Lon2: Double; out TC12: Double): Double;
var
IterLimit: Integer;
L, U1, U2, SinU1, CosU1, SinU2, CosU2, Lambda, LambdaP, SinLambda, CosLambda,
Sigma, SinSigma, CosSigma, Cos2SigmaM, SinAlpha, CosSqAlpha, uSqr, A, B, C,
DeltaSigma, TC21: Extended;
begin
if (Lat1 = Lat2) and (Lon1 = Lon2) then // Coincident points
begin
Result := 0.0;
Exit;
end;
L := Lon2-Lon1;
if (Lat1 = 0) and (Lat2 = 0) then // Along equator
begin
Result := Abs(a0*L);
if (L > 0) then
TC12 := PI/2
else
TC12 := 3*PI/2;
Exit;
end;
U1 := ArcTan(r0 * Tan(Lat1));
U2 := ArcTan(r0 * Tan(Lat2));
SinCos(U1, SinU1, CosU1);
SinCos(U2, SinU2, CosU2);
Lambda := L;
LambdaP := 2*PI;
IterLimit := 20;
while (Abs(Lambda-LambdaP) > 1E-12) do
begin
SinCos(Lambda, SinLambda, CosLambda);
SinSigma :=
Sqrt((Sqr(CosU2*SinLambda)) + Sqr(CosU1*SinU2-SinU1*CosU2*CosLambda));
CosSigma := SinU1*SinU2 + CosU1*CosU2*CosLambda;
Sigma := ArcTan2(SinSigma, CosSigma);
SinAlpha := CosU1 * CosU2 * SinLambda / SinSigma;
CosSqAlpha := 1 - Sqr(SinAlpha);
Cos2SigmaM := CosSigma - 2*SinU1*SinU2/CosSqAlpha;
C := f0/16*CosSqAlpha*(4+f0*(4-3*CosSqAlpha));
LambdaP := Lambda;
Lambda := L + (1-C) * f0 * SinAlpha *
(Sigma + C*SinSigma*(Cos2SigmaM+C*CosSigma*(-1+2*Sqr(Cos2SigmaM))));
Dec(IterLimit, 1);
if (iterLimit<=0) then
RaiseException('GeoDis failed to converge');
end;
uSqr := CosSqAlpha * (aa-bb)/bb;
A := 1 + uSqr/16384*(4096+uSqr*(-768+uSqr*(320-175*uSqr)));
B := uSqr/1024 * (256+uSqr*(-128+uSqr*(74-47*uSqr)));
DeltaSigma :=
B*SinSigma*(Cos2SigmaM + B/4*(SinSigma*(-1+2*Sqr(Cos2SigmaM))-
B/6*Cos2SigmaM*(-3+4*SinSigma*SinSigma)*(-3+4*Sqr(Cos2SigmaM))));
Result := b0*A*(Sigma-DeltaSigma)/1000;
TC12 := ArcTan2(CosU2*SinLambda, CosU1*SinU2 - SinU1*CosU2*CosLambda);
if (TC12 < 0) then TC12 := 2*Pi + TC12;
TC21 := ArcTan2(cosU1*SinLambda, (-sinU1*cosU2 + cosU1*sinU2*cosLambda))-pi;
if (TC21 < 0) then TC21 := 2*Pi + TC21;
end; // Vincinty's inverse algorithm
///////////////////////////////////////////////////////////////////////////////
//
// Thaddeus Vincenty's direct formula for ellipsoids
//
// Lat1, Lon1, Lat, Lon, Tc in radians
// D in km
procedure GeoRadial(const Lat1, Lon1, Tc, D: Double; out Lat, Lon: Double);
var
SinTc, CosTc, U1, TanU1, SinU1, CosU1, SinAlpha, CosAlpha, Usqr, S, A, B, C,
Term1, Term2, Term3, Sigma, SinSigma, CosSigma, TanSigma1, DeltaSigma,
Sigma1, TwoSigmaM, c2sm, LastSigma, Lambda, Omega: Extended;
begin
if D = 0.0 then // Coincident points
begin
Lat := Lat1; // TC21 := 0.0;
Lon := Lon1;
Exit;
end;
S := D*1000;
TanU1 := r0 * Tan(Lat1);
TanSigma1 := TanU1/Cos(Tc); //eq 1
U1 := ArcTan(TanU1);
SinCos(U1, SinU1, CosU1);
SinAlpha := CosU1 * Sin(Tc); //eq 2
CosAlpha := Sqrt(1 - Sqr(SinAlpha));
Usqr := Sqr(CosAlpha) * (aa-bb)/bb;
Term1 := Usqr/16384;
Term2 := 4096 + Usqr*(-768 + Usqr*(320 - 175*Usqr));
A := 1 + Term1 * Term2;
B := Usqr / 1024*(256 + Usqr*(-128 + Usqr*(74 - 47*Usqr))); //eq 4
Sigma := S / (b0*a);
Sigma1 := ArcTan(TanSigma1);
repeat
Lastsigma := Sigma;
TwoSigmaM := 2*Sigma1 + Sigma; //eq 5
SinCos(Sigma, SinSigma, CosSigma);
SinCos(Tc, SinTc, CosTc);
c2sm := Cos(TwoSigmam);
DeltaSigma :=
B*SinSigma*(c2sm + b/4 * (CosSigma*(-1 + 2*Sqr(c2sm)) -
B / 6*c2sm * (-3 + 4*Sqr(SinSigma)) * (-3 + 4*Sqr(c2sm)))); //eq 6
Sigma := S / (b0*a) + DeltaSigma; //eq 7
until (Abs(Sigma - LastSigma) <= 1E-12);
TwoSigmam := 2*Sigma1 + Sigma; //eq 5
c2sm := Cos(TwoSigmaM);
SinCos(Sigma, SinSigma, CosSigma);
Term1 := SinU1*CosSigma + CosU1*SinSigma*CosTc;
Term2 := Sqr(SinAlpha) + Sqr(SinU1*SinSigma - CosU1*CosSigma*CosTc);
Term3 := r0*Sqrt(Term2);
Lat := ArcTan2(Term1, Term3);
Term1 := SinSigma*Sin(Tc);
Term2 := CosU1*CosSigma - SinU1*SinSigma*CosTc;
Lambda := ArcTan2(Term1, Term2);
C := f0/ 16*Sqr(CosAlpha) * (4 + f0*(4 - 3*Sqr(CosAlpha)));
Omega := Lambda - (1-c) * f0 * SinAlpha *
(Sigma + C*SinSigma*(c2sm + C*CosSigma*(-1 + 2*Sqr(c2sm))));
Lon := Lon1+Omega;
end; // Vincinty's direct algorithm
end. // GEO84 | ||||
| related to | 0002088 | resolved | zed | Добавить в IDatum функцию построения N промежуточных точек отрезка |
| child of | 0000713 | resolved | vdemidov | Настраиваемые кольца расстояния вокруг метки положения |
| child of | 0001116 | confirmed | При измерении расстояний отображать линии в виде дуг | |
| child of | 0000663 | resolved | zed | Создание круглых областей заданного радиуса |
| child of | 0000094 | resolved | vdemidov | Добавить создание точек по азимуту |
| child of | 0000099 | confirmed | Добавить инструмент - вычисление азимута между двумя существующими метками | |
| child of | 0000219 | resolved | zed | Отображение азимута в инструменте измерений расстояний |
| child of | 0000143 | confirmed | Навигация на точку(метку) | |
| child of | 0001051 | confirmed | Построение лучей азимутов | |
| child of | 0001021 | resolved | zed | Измерение растояния |
| child of | 0001616 | resolved | zed | Выделение квадратной области определяемый указанным радиусом вписанной окружности |
|
|
есть такое, куда залить или отдельно приложить? только не азимут, а смещение x и y. |
|
|
Нет. Нужен именно азимут. |
|
|
>расстояние в метрах о каких примерно величинах идёт речь? метры? сотни километров? о плюсах? в вики про локсодромию только на сфере написано ((( http://ru.wikipedia.org/wiki/%CB%EE%EA%F1%EE%E4%F0%EE%EC%E0 |
|
|
А я не про локсодромию, а про навигацию на большом круге. Соответственно расстояния могут быть любыми до половины длинны экватора. |
|
|
http://ru.wikipedia.org/wiki/Ортодромия Только все эти формулы на сфере, а нужно на эллипсоиде. |
|
|
>я не про локсодромию Вообще-то "координаты исходной точки, азимут и расстояние в метрах, а возвращает координаты новой точки" - именно движение по локсодромии. Или имелось ввиду что начальный азимут задаёт направление, а дальше по нему идём прямо и азимут меняется, вплоть за полюс? |
|
|
>начальный азимут задаёт направление, а дальше по нему идём прямо и азимут меняется, вплоть за полюс? Именно. Локсодромия интересна только при навигации по обычным бумажным картам. |
|
|
Нужны алгоритмы аналогичные используемым вот в этом онлайн калькуляторе: http://planetcalc.ru/722/ |
|
|
Наверно, и 0001116 можно сюда привязать? |
|
|
Вики про длину дуги даже эллипса говорит "Получившийся интеграл принадлежит семейству эллиптических интегралов, которые в элементарных функциях не выражаются, и сводится к эллиптическому интегралу второго рода E(t,e)." - т.е. или апроксимировать какой-то сферой (для малых расстояний почему бы нет? Или нужна офигительная точность?) или считать итерационно (разбивать отрезок на кусочки и каждый считать на своей приближенной сфере). Т.е. вопрос лишь в применении, какая точность необходима. Для всех связанных тикетов мне кажется достаточно будет и навигации по сфере, для которой есть точные формулы. Проверил по тому "идеальному" калькулятору, Москва - Владивосток, расстояние 6445км/6456км, погрешность менее 0.2%, азимуты отличаются менее 0.05° (WGS84 vs сфера). Неужели для чего-то нужна ещё бОльшая точность? |
|
|
Я ж не против. Реализуйте хоть на сфере. |
|
|
http://www.spywatcher.com.ua/forum/index.php?PHPSESSID=a35d32a4bfd512c148109fd622141327&topic=45.0 |
|
|
Нужно создать что-то похожее на то что появилось в API Яндекс-Карт http://api.yandex.ru/maps/doc/jsapi/2.x/ref/reference/coordSystem.geo.xml |
|
|
http://habrahabr.ru/post/143898/ Со своей стороны мы написали две стандартных реализации — для обычной декартовой плоскости и для референсного эллипсоида WGS 84. Для второй реализации мы использовали формулы Винсенти (http://en.wikipedia.org/wiki/Vincenty%27s_formulae). Кстати, непосредственно реализовывал эту логику runawayed (http://habrahabr.ru/users/runawayed/), передаём ему привет :). Постучись в гости к этому "runawayed", может он и для САСа такое сделает. Или хотя бы кинет исходники (если они не засекречены). |
|
|
Ну у меня на хабре аккаунта нету. Так что не смогу. Если кто постучится к runawayed буду благодарен. |
|
|
vdemidov >Нужны алгоритмы аналогичные используемым вот в этом онлайн калькуляторе: Немного покопался в теме: все расчёты базируются на алгоритме некого поляка Vincenty и непродолжительное гугление по имени вывело на исходники, реализующие этот алгоритм: http://www.programmersheaven.com/download/48584/19/ZipView.aspx Исходники на всякий случай приаттачил (geo84.pas). Необходимая нам реализация в процедуре: procedure GeoRadial(const Lat1, Lon1, Tc, D: Double; out Lat, Lon: Double); Оно? Только сейчас обратил внимание, что и на хабре оказывается про этого же поляка говорили, так что скорее всего оно. |
|
|
Стопудово оно. Только нужно убрать жесткую привязку к константам и загнать в класс TDatum. Еще хорошо бы сравнить результаты функции Geodesic с тем что сейчас реализовано. |
|
|
Сейчас попробую заняться. На сколько я понял, вот эта константа: > f0 = 1/298.257223563; // Flattening это тоже самое, что и FExct: Double; в TDatum? |
|
|
Тоже самое с точность может быть до обратного значения. Я точно не помню. Просто сравни значение для стандартного эллипсоида WGS84 |
|
|
Оказалось не тоже самое. |
|
|
На всякий случай, оставлю тут ссылку на калькулятор, которым я проверял правильность работы алгоритма: http://www.geomidpoint.com/destination/ |
|
|
>Еще хорошо бы сравнить результаты функции Geodesic с тем что сейчас реализовано. Сравнил. САС-овский алгоритм оказался немножко менее точный, поэтому переделал и его до кучи. |
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 26-02-2012 10:05 | vdemidov | New Issue | |
| 26-02-2012 10:16 | vdemidov | Relationship added | child of 0000713 |
| 26-02-2012 12:52 | vasketsov | Note Added: 0005659 | |
| 26-02-2012 13:23 | vdemidov | Note Added: 0005661 | |
| 26-02-2012 13:52 | vasketsov | Note Added: 0005664 | |
| 26-02-2012 14:20 | vdemidov | Note Added: 0005665 | |
| 26-02-2012 14:28 | vdemidov | Note Added: 0005666 | |
| 26-02-2012 14:35 | vasketsov | Note Added: 0005667 | |
| 26-02-2012 21:07 | vdemidov | Note Added: 0005670 | |
| 26-02-2012 21:14 | vdemidov | Note Edited: 0005670 | |
| 26-02-2012 21:26 | vdemidov | Additional Information Updated | |
| 26-02-2012 21:34 | vdemidov | Note Added: 0005671 | |
| 27-02-2012 04:14 | Tolik | Note Added: 0005672 | |
| 27-02-2012 08:56 | vdemidov | Relationship added | child of 0001116 |
| 27-02-2012 09:03 | vdemidov | Relationship added | child of 0000663 |
| 27-02-2012 16:13 | vdemidov | Status | new => confirmed |
| 27-02-2012 16:13 | vdemidov | Target Version | => 41xxxx |
| 05-03-2012 06:15 | vdemidov | Relationship added | child of 0000094 |
| 05-03-2012 06:15 | vdemidov | Relationship added | child of 0000099 |
| 05-03-2012 08:22 | vdemidov | Relationship added | child of 0000219 |
| 05-03-2012 10:13 | vdemidov | Relationship added | child of 0000143 |
| 05-03-2012 10:57 | vdemidov | Relationship added | child of 0001051 |
| 19-05-2012 07:48 | Dima2000 | Note Added: 0007118 | |
| 19-05-2012 22:09 | Dima2000 | Note Edited: 0007118 | |
| 21-05-2012 05:17 | vdemidov | Note Added: 0007141 | |
| 12-07-2012 05:29 | vdemidov | Note Added: 0007799 | |
| 02-08-2012 16:52 | vdemidov | Note Added: 0008050 | |
| 02-08-2012 19:49 | zed | Note Added: 0008053 | |
| 03-08-2012 06:34 | vdemidov | Note Added: 0008060 | |
| 02-10-2012 07:19 | zed | Note Added: 0009104 | |
| 02-10-2012 07:19 | zed | File Added: geo84.pas | |
| 02-10-2012 07:23 | zed | Note Edited: 0009104 | |
| 02-10-2012 07:33 | vdemidov | Note Added: 0009105 | |
| 02-10-2012 12:20 | zed | Note Added: 0009111 | |
| 02-10-2012 12:25 | vdemidov | Note Added: 0009112 | |
| 02-10-2012 15:50 | zed | Note Added: 0009124 | |
| 02-10-2012 15:50 | zed | Status | confirmed => resolved |
| 02-10-2012 15:50 | zed | Fixed in Version | => 121010 |
| 02-10-2012 15:50 | zed | Resolution | open => fixed |
| 02-10-2012 15:50 | zed | Assigned To | => zed |
| 02-10-2012 15:50 | zed | Target Version | 41xxxx => 121010 |
| 02-10-2012 15:59 | zed | Note Added: 0009125 | |
| 02-10-2012 18:26 | zed | Note Added: 0009126 | |
| 08-10-2012 14:09 | vdemidov | Relationship added | child of 0001021 |
| 09-10-2012 06:49 | vdemidov | Relationship added | child of 0001616 |
| 13-08-2013 12:46 | vdemidov | Relationship added | related to 0002088 |
| 08-08-2025 13:24 | zed | Category | Хотелка => Хотелка / Feature request |