Задачи на сфере: линейная засечка: различия между версиями

Материал из GIS-Lab
Перейти к навигации Перейти к поиску
 
(не показано 15 промежуточных версий 2 участников)
Строка 1: Строка 1:
{{Статья|Черновик}}
{{Статья|Опубликована|sphere-geodesic-linear-resection}}


{{Аннотация|Линейная засечка — это нахождение положения точки по координатам двух исходных пунктов и расстояниям от этих пунктов до определяемой точки.}}
{{Аннотация|Линейная засечка — это нахождение положения точки по координатам двух исходных пунктов и расстояниям от этих пунктов до определяемой точки.}}
Строка 25: Строка 25:
== Алгоритм ==
== Алгоритм ==


[[Image:sph_lin.png|frame|c|right|Угловая засечка]]
[[Image:sphere-task-linear.png|frame|c|right|Линейная засечка]]


Решение любого вида засечек сводится к нахождению полярных координат искомой точки, т.е. начального направления и расстояния на неё с одного из исходных пунктов. На конечном этапе координаты находятся из решения прямой геодезической задачи. Поскольку в линейной засечке расстояния ''σ''₁₃ и ''σ''₂₃ уже заданы, остаётся определить направление ''α''₁₃ или ''α''₂₃.
Решение любого вида засечек сводится к нахождению полярных координат искомой точки, т.е. начального направления и расстояния на неё с одного из исходных пунктов. На конечном этапе координаты находятся из решения прямой геодезической задачи. Поскольку в линейной засечке расстояния ''σ''₁₃ и ''σ''₂₃ уже заданы, остаётся определить направление ''α''₁₃ или ''α''₂₃.


На рисунке синим цветом выделены заданные элементы сферического треугольника, красным цветом неизвестные, зелёным — вспомогательные элементы. Итак, в треугольнике ''Q''₁''Q''₂''Q''₃ известны только два элемента — стороны ''σ''₁₃ и ''σ''₂₃. Из решения обратной геодезической задачи для пунктов ''Q''₁, ''Q''₂ можно получить недостающий третий элемент — расстояние ''σ''₁₂, а также азимут ''α''₁₂.
На рисунке синим цветом выделены заданные элементы сферических треугольников, красным цветом неизвестные, зелёным — вспомогательные элементы. Итак, в треугольнике ''Q''₁''Q''₂''Q''₃ известны только два элемента — стороны ''σ''₁₃ и ''σ''₂₃. Из решения обратной геодезической задачи для пунктов ''Q''₁, ''Q''₂ можно получить недостающий третий элемент — расстояние ''σ''₁₂, а также азимут ''α''₁₂.


'''Последовательность действий:'''
'''Последовательность действий:'''
Строка 37: Строка 37:
# решить прямую геодезическую задачу для ''Q''₁, ''Q''₃: по ''φ''₁, ''λ''₁, ''α''₁₃, ''σ''₁₃ вычислить ''φ''₃, ''λ''₃.
# решить прямую геодезическую задачу для ''Q''₁, ''Q''₃: по ''φ''₁, ''λ''₁, ''α''₁₃, ''σ''₁₃ вычислить ''φ''₃, ''λ''₃.


Действия по первому и последнему пунктам рассмотрены в статьях [[Задачи на сфере: обратная геодезическая задача]] и [[Задачи на сфере: прямая геодезическая задача]].
Действия по первому и последнему пунктам рассмотрены в статьях [http://gis-lab.info/qa/sphere-geodesic-invert-problem.html Задачи на сфере: обратная геодезическая задача] и [http://gis-lab.info/qa/sphere-geodesic-direct-problem.html Задачи на сфере: прямая геодезическая задача].


Угол ''β''₁ и азимут ''α''₁₃ вычисляются по формулам:
Угол ''β''₁ и азимут ''α''₁₃ вычисляются по формулам:


: <math>\begin{array}{rcl}
: <math>\begin{align}
\cos \beta_1 & = & \dfrac{\cos \sigma_{23} - \cos \sigma_{12} \cos \sigma_{13}}{\sin \sigma_{12} \sin \sigma_{13}} \\
\cos \beta_1 & = \dfrac{\cos \sigma_{23} - \cos \sigma_{12} \cos \sigma_{13}}{\sin \sigma_{12} \sin \sigma_{13}} \\
\alpha_{13} & = & \alpha_{12} \mp \beta_1
\alpha_{13} & = \alpha_{12} \mp \beta_1
\end{array}</math>
\end{align}</math>


Если величина косинуса превышает единицу, задача поставлена некорректно, не выполняется закон «Длина стороны не может превышать сумму длин других сторон».
Если величина косинуса превышает единицу, задача поставлена некорректно, не выполняется закон «Длина стороны не может превышать сумму длин других сторон».
Строка 52: Строка 52:
== Пример программной реализации ==
== Пример программной реализации ==


Пример функции <tt>SphereAngular</tt> на языке Си, реализующей вышеизоложенный алгоритм:
Пример функции <tt>SphereLinear</tt> на языке Си, реализующей вышеизоложенный алгоритм:


<syntaxhighlight lang="c">
<syntaxhighlight lang="c">
/*
/*
  * Решение угловой засечки
  * Решение линейной засечки
  *
  *
  * Аргументы исходные:
  * Аргументы исходные:
  *    pt1   - {широта, долгота} пункта Q1
  *    pt1   - {широта, долгота} пункта Q1
  *    pt2   - {широта, долгота} пункта Q2
  *    pt2   - {широта, долгота} пункта Q2
  *    azi13 - азимут направления Q1-Q3
  *    dist13 - азимут направления Q1-Q3
  *    azi23 - азимут направления Q2-Q3
  *    dist23 - азимут направления Q2-Q3
*    clockwise - флаг направления:
*                0 - налево от линии Q1-Q2,
*                1 - направо от линии Q1-Q2
  *
  *
  * Аргументы определяемые:
  * Аргументы определяемые:
  *    pt3 - {широта, долгота} точки Q3
  *    pt3 - {широта, долгота} точки Q3
  */
  */
int SphereAngular(double pt1[], double pt2[], double azi13, double azi23,
int SphereLinear(double pt1[], double pt2[], double dist13, double dist23,
  double pt3[])
int right, double pt3[])
{
{
   double azi12, dist12, azi21, dist13;
   double azi12, dist12, azi13;
   double cos_beta1, sin_beta1, cos_beta2, sin_beta2, cos_dist12, sin_dist12;
   double cos_beta1;


   SphereInverse(pt2, pt1, &azi21, &dist12);
   if (dist13 == 0.) {       // Решение - точка Q1.
  SphereInverse(pt1, pt2, &azi12, &dist12);
  cos_beta1 = cos(azi13 - azi12);
  sin_beta1 = sin(azi13 - azi12);
  cos_beta2 = cos(azi21 - azi23);
  sin_beta2 = sin(azi21 - azi23);
  cos_dist12 = cos(dist12);
  sin_dist12 = sin(dist12);
 
  if (sin_beta1 == 0. && sin_beta2 == 0.)    // Решение - любая точка
    return -1;       //  на большом круге Q1-Q2.
  else if (sin_beta1 == 0.) {
    pt3[0] = pt2[0];       // Решение - точка Q2.
    pt3[1] = pt2[1];
    return 0;
  } else if (sin_beta2 == 0.) {       // Решение - точка Q1.
     pt3[0] = pt1[0];
     pt3[0] = pt1[0];
     pt3[1] = pt1[1];
     pt3[1] = pt1[1];
     return 0;
     return 0;
   } else if (sin_beta1 * sin_beta2 < 0.) {   // Лучи Q1-Q3 и Q2-Q3 направлены
   } else if (dist23 == 0.) {       // Решение - точка Q2.
     if (fabs(sin_beta1) >= fabs(sin_beta2)) { //  в разные полусферы.
     pt3[0] = pt2[0];
      cos_beta2 = -cos_beta2;       // Выберем ближайшее решение:
    pt3[1] = pt2[1];
      sin_beta2 = -sin_beta2;       //  развернём луч Q2-Q3 на 180°;
     return 0;
     } else {       //    иначе
      cos_beta1 = -cos_beta1;       //  развернём луч Q1-Q3 на 180°.
      sin_beta1 = -sin_beta1;
    }
   }
   }
   dist13 = atan2(fabs(sin_beta2) * sin_dist12,
 
cos_beta2 * fabs(sin_beta1)
  SphereInverse(pt1, pt2, &azi12, &dist12);
+ fabs(sin_beta2) * cos_beta1 * cos_dist12);
   cos_beta1 = (cos(dist23) - cos(dist12) * cos(dist13))
    / (sin(dist12) * sin(dist13));
  if (fabs(cos_beta1) > 1.)       // Решение не существует.
    return -1;
  azi13 = clockwise ? azi12 + acos(cos_beta1) : azi12 - acos(cos_beta1);
   SphereDirect(pt1, azi13, dist13, pt3);
   SphereDirect(pt1, azi13, dist13, pt3);


Строка 110: Строка 98:
</syntaxhighlight>
</syntaxhighlight>


Этот код находится в архиве [[Медиа:Sph.tar.gz|Sph.tar.gz]] в файле '''sph.c'''. Кроме того, в файл '''sph.h''' включены следующие определения:
Этот код находится в архиве [[Медиа:Sph.zip|Sph.zip]] в файле '''sph.c'''. Кроме того, в файл '''sph.h''' включены следующие определения:


<syntaxhighlight lang="c">
<syntaxhighlight lang="c">
Строка 118: Строка 106:
</syntaxhighlight>
</syntaxhighlight>


Теперь напишем программу, которая обращается к функции <tt>SphereAngular</tt> для решения угловой засечки:
Теперь напишем программу, которая обращается к функции <tt>SphereLinear</tt> для решения линейной засечки:


<syntaxhighlight lang="c">
<syntaxhighlight lang="c">
Строка 129: Строка 117:
   char buf[1024];
   char buf[1024];
   double pt1[2], pt2[2], pt3[2];
   double pt1[2], pt2[2], pt3[2];
   double lat1, lon1, lat2, lon2, azi13, azi23;
   double lat1, lon1, lat2, lon2, dist13, dist23;
  int clockwise;


   while (fgets(buf, 1024, stdin) != NULL) {
   while (fgets(buf, 1024, stdin) != NULL) {
     sscanf(buf, "%lf %lf %lf %lf %lf %lf",
     sscanf(buf, "%lf %lf %lf %lf %lf %lf %d",
  &lat1, &lon1, &lat2, &lon2, &azi13, &azi23);
  &lat1, &lon1, &lat2, &lon2, &dist13, &dist23, &clockwise);
     pt1[0] = Radians(lat1);
     pt1[0] = Radians(lat1);
     pt1[1] = Radians(lon1);
     pt1[1] = Radians(lon1);
     pt2[0] = Radians(lat2);
     pt2[0] = Radians(lat2);
     pt2[1] = Radians(lon2);
     pt2[1] = Radians(lon2);
     if (SphereAngular(pt1, pt2, Radians(azi13), Radians(azi23), pt3))
     if (SphereLinear(pt1, pt2, dist13 / A_E, dist23 / A_E, clockwise, pt3))
       puts("\t"); /* Бесконечно много решений на большом круге Q1-Q2 */
       puts("\t"); /* Решений нет */
     else
     else
       printf("%f\t%f\n", Degrees(pt3[0]), Degrees(pt3[1]));
       printf("%f\t%f\n", Degrees(pt3[0]), Degrees(pt3[1]));
Строка 147: Строка 136:
</syntaxhighlight>
</syntaxhighlight>


В архиве [[Медиа:Sph.tar.gz|Sph.tar.gz]] этот код находится в файле '''ang.c'''. Создадим исполняемый модуль '''ang''' компилятором '''gcc''':
В архиве [[Медиа:Sph.zip|Sph.zip]] этот код находится в файле '''lin.c'''. Создадим исполняемый модуль '''lin''' компилятором '''gcc''':


<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
$ gcc -o ang ang.c sph.c -lm
$ gcc -o lin lin.c sph.c -lm
</syntaxhighlight>
</syntaxhighlight>


Впрочем, в архиве есть '''Makefile'''. Для MS Windows готовую программу '''ang.exe''' можно найти в архиве [[Медиа:Sph-win32.zip|Sph-win32.zip]].
Впрочем, в архиве есть '''Makefile'''. Для MS Windows готовую программу '''lin.exe''' можно найти в архиве [[Медиа:Sph-win32.zip|Sph-win32.zip]].


Программа читает данные из стандартного ввода консоли и отправляет результаты на стандартный вывод. Для чтения и записи файлов используются символы перенаправления потока «&gt;» и «&lt;» соответственно. Из каждой строки ввода программа считывает координаты первого и второго пунктов ''φ''₁, ''λ''₁, ''φ''₂, ''λ''₂, начальные азимуты ''α''₁₃ и ''α''₂₃ в градусах; решает угловую засечку; выводит в строку вывода координаты третьей точки ''φ''₃, ''λ''₃ в градусах.
Программа читает данные из стандартного ввода консоли и отправляет результаты на стандартный вывод. Для чтения и записи файлов используются символы перенаправления потока «&gt;» и «&lt;» соответственно. Из каждой строки ввода программа считывает координаты первого и второго пунктов ''φ''₁, ''λ''₁, ''φ''₂, ''λ''₂ в градусах, расстояния ''σ''₁₃ и ''σ''₂₃ в километрах (точнее, в единицах константы <tt>A_E</tt>) и признак направления (0 — налево от линии ''Q''₁''Q''₂, 1 — направо); решает линейную засечку; выводит в строку вывода координаты третьей точки ''φ''₃, ''λ''₃ в градусах.


Создадим файл '''ang.dat''', содержащий одну строку данных:
Создадим файл '''lin.dat''', содержащий одну строку данных:


<pre>
<pre>
30 0 60 30 44.80406 110.389945
30 0 60 30 5001.1309 1722.9431 1
</pre>
</pre>


Строка 166: Строка 155:


<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
$ ang < ang.dat
$ lin < lin.dat
</syntaxhighlight>
</syntaxhighlight>


Строка 172: Строка 161:


<pre>
<pre>
52.000000 54.000000
52.000001 54.000000
</pre>
</pre>
В архиве [[Медиа:Sph-py.zip|Sph-py.zip]] находится код на языке Питон. Выполнение скрипта в командной консоли:
<syntaxhighlight lang="bash">
$ python lin.py lin.dat
</syntaxhighlight>


== Ссылки ==
== Ссылки ==
* [[Вычисление расстояния и начального азимута между двумя точками на сфере]]
* [http://gis-lab.info/qa/great-circles.html Вычисление расстояния и начального азимута между двумя точками на сфере]
* [http://gis-lab.info/qa/angles-sphere.html Вычисление угла образованного тремя точками на сфере]
* [http://gis-lab.info/qa/angles-sphere.html Вычисление угла образованного тремя точками на сфере]
* [[Задачи на сфере: обратная геодезическая задача]]
* [http://gis-lab.info/qa/sphere-geodesic-invert-problem.html Задачи на сфере: обратная геодезическая задача]
* [[Задачи на сфере: прямая геодезическая задача]]
* [http://gis-lab.info/qa/sphere-geodesic-direct-problem.html Задачи на сфере: прямая геодезическая задача]
* [[Задачи на сфере: угловая засечка]]
* [http://gis-lab.info/qa/sphere-geodesic-angular-resection.html Задачи на сфере: угловая засечка]
* [http://www.pm298.ru/sferich.php Краткий справочник по сферической тригонометрии]
* [http://en.wikipedia.org/wiki/Earth_radius Earth radius]
* [http://en.wikipedia.org/wiki/Earth_radius Earth radius]
* [http://gis-lab.info/docs/books/sphere-trigonometry/sphere-trigonometry.rar Степанов Н. Н. Сферическая тригонометрия]
* [http://gis-lab.info/docs/books/sphere-trigonometry/sphere-trigonometry.rar Степанов Н. Н. Сферическая тригонометрия]

Текущая версия от 08:43, 21 июня 2014

Эта страница опубликована в основном списке статей сайта
по адресу http://gis-lab.info/qa/sphere-geodesic-linear-resection.html


Линейная засечка — это нахождение положения точки по координатам двух исходных пунктов и расстояниям от этих пунктов до определяемой точки.

Общие положения

В качестве модели Земли принимается сфера с радиусом R, равным среднему радиусу земного эллипсоида. Аналогом прямой линии на плоскости является геодезическая линия на поверхности. На сфере геодезическая линия — дуга большого круга.

Введём следующие обозначения:

  • φ — географическая широта,
  • λ — географическая долгота,
  • α — азимут дуги большого круга,
  • σ — сферическое расстояние (длина дуги большого круга, выраженная в долях радиуса шара).

Линейное расстояние по дуге большого круга s связано со сферическим расстоянием σ формулой s = R σ.

Постановка задачи

Исходные данные
координаты пунктов Q₁, Q₂ — φ₁, λ₁, φ₂, λ₂,
расстояния от пунктов Q₁, Q₂ до точки Q₃ — σ₁₃, σ₂₃.
Определяемые величины
координаты точки Q₃ — φ₃, λ₃.

Алгоритм

Линейная засечка

Решение любого вида засечек сводится к нахождению полярных координат искомой точки, т.е. начального направления и расстояния на неё с одного из исходных пунктов. На конечном этапе координаты находятся из решения прямой геодезической задачи. Поскольку в линейной засечке расстояния σ₁₃ и σ₂₃ уже заданы, остаётся определить направление α₁₃ или α₂₃.

На рисунке синим цветом выделены заданные элементы сферических треугольников, красным цветом неизвестные, зелёным — вспомогательные элементы. Итак, в треугольнике QQQ₃ известны только два элемента — стороны σ₁₃ и σ₂₃. Из решения обратной геодезической задачи для пунктов Q₁, Q₂ можно получить недостающий третий элемент — расстояние σ₁₂, а также азимут α₁₂.

Последовательность действий:

  1. решить обратную геодезическую задачу для Q₁, Q₂: по φ₁, λ₁, φ₂, λ₂ получить α₁₂, σ₁₂;
  2. в треугольнике QQQ₃ по σ₁₂, σ₁₃, σ₂₃ вычислить угол β₁;
  3. вычислить азимут α₁₃;
  4. решить прямую геодезическую задачу для Q₁, Q₃: по φ₁, λ₁, α₁₃, σ₁₃ вычислить φ₃, λ₃.

Действия по первому и последнему пунктам рассмотрены в статьях Задачи на сфере: обратная геодезическая задача и Задачи на сфере: прямая геодезическая задача.

Угол β₁ и азимут α₁₃ вычисляются по формулам:

Если величина косинуса превышает единицу, задача поставлена некорректно, не выполняется закон «Длина стороны не может превышать сумму длин других сторон».

В общем случае имеется два решения, расположенных симметрично относительно большого круга QQ₂. Следует явно определить, с какой стороны от направления QQ₂ находится точка Q₃: если слева, как на рисунке, то в последней формуле ставим знак минус, если же справа — знак плюс.

Пример программной реализации

Пример функции SphereLinear на языке Си, реализующей вышеизоложенный алгоритм:

/*
 * Решение линейной засечки
 *
 * Аргументы исходные:
 *     pt1    - {широта, долгота} пункта Q1
 *     pt2    - {широта, долгота} пункта Q2
 *     dist13 - азимут направления Q1-Q3
 *     dist23 - азимут направления Q2-Q3
 *     clockwise - флаг направления:
 *                 0 - налево от линии Q1-Q2,
 *                 1 - направо от линии Q1-Q2
 *
 * Аргументы определяемые:
 *     pt3 - {широта, долгота} точки Q3
 */
int SphereLinear(double pt1[], double pt2[], double dist13, double dist23,
		 int right, double pt3[])
{
  double azi12, dist12, azi13;
  double cos_beta1;

  if (dist13 == 0.) {			      // Решение - точка Q1.
    pt3[0] = pt1[0];
    pt3[1] = pt1[1];
    return 0;
  } else if (dist23 == 0.) {		      // Решение - точка Q2.
    pt3[0] = pt2[0];
    pt3[1] = pt2[1];
    return 0;
  }

  SphereInverse(pt1, pt2, &azi12, &dist12);
  cos_beta1 = (cos(dist23) - cos(dist12) * cos(dist13))
    / (sin(dist12) * sin(dist13));
  if (fabs(cos_beta1) > 1.)		      // Решение не существует.
    return -1;
  azi13 = clockwise ? azi12 + acos(cos_beta1) : azi12 - acos(cos_beta1);
  SphereDirect(pt1, azi13, dist13, pt3);

  return 0;
}

Этот код находится в архиве Sph.zip в файле sph.c. Кроме того, в файл sph.h включены следующие определения:

#define A_E 6371.0				// радиус Земли в километрах
#define Degrees(x) (x * 57.29577951308232)	// радианы -> градусы
#define Radians(x) (x / 57.29577951308232)	// градусы -> радианы

Теперь напишем программу, которая обращается к функции SphereLinear для решения линейной засечки:

#include <stdio.h>
#include <stdlib.h>
#include "sph.h"

int main(int argc, char *argv[])
{
  char buf[1024];
  double pt1[2], pt2[2], pt3[2];
  double lat1, lon1, lat2, lon2, dist13, dist23;
  int clockwise;

  while (fgets(buf, 1024, stdin) != NULL) {
    sscanf(buf, "%lf %lf %lf %lf %lf %lf %d",
	   &lat1, &lon1, &lat2, &lon2, &dist13, &dist23, &clockwise);
    pt1[0] = Radians(lat1);
    pt1[1] = Radians(lon1);
    pt2[0] = Radians(lat2);
    pt2[1] = Radians(lon2);
    if (SphereLinear(pt1, pt2, dist13 / A_E, dist23 / A_E, clockwise, pt3))
      puts("\t"); /* Решений нет */
    else
      printf("%f\t%f\n", Degrees(pt3[0]), Degrees(pt3[1]));
  }
  return 0;
}

В архиве Sph.zip этот код находится в файле lin.c. Создадим исполняемый модуль lin компилятором gcc:

$ gcc -o lin lin.c sph.c -lm

Впрочем, в архиве есть Makefile. Для MS Windows готовую программу lin.exe можно найти в архиве Sph-win32.zip.

Программа читает данные из стандартного ввода консоли и отправляет результаты на стандартный вывод. Для чтения и записи файлов используются символы перенаправления потока «>» и «<» соответственно. Из каждой строки ввода программа считывает координаты первого и второго пунктов φ₁, λ₁, φ₂, λ₂ в градусах, расстояния σ₁₃ и σ₂₃ в километрах (точнее, в единицах константы A_E) и признак направления (0 — налево от линии QQ₂, 1 — направо); решает линейную засечку; выводит в строку вывода координаты третьей точки φ₃, λ₃ в градусах.

Создадим файл lin.dat, содержащий одну строку данных:

30 0 60 30 5001.1309 1722.9431 1

После запуска программы

$ lin < lin.dat

получим φ₃, λ₃:

52.000001 54.000000

В архиве Sph-py.zip находится код на языке Питон. Выполнение скрипта в командной консоли:

$ python lin.py lin.dat

Ссылки