воскресенье, 17 июня 2007 г.

PostGIS: Пространственный анализ в PostGIS с использованием множества координатных систем

В случае, если мы хотим воспользоваться функциями пространственного анализа в PostGIS, особых сложностей не возникает. Другое дело, если необходимо “на лету” выполнять различные трансформации координат. Рассмотрим следующий случай: в таблице house хранится пространственная информация в градусах WGS84 (идентификатор системы координат 4326), а мы ищем объект, заданный координатами в Пулково 1942-го года (идентификатор системы координат 28408).

Описания координатных систем хранятся в таблице spatial_ref_sys, по SRID=4326 можно найти информацию о мировой системе координат, а по SRID=28408 - российской. По умолчанию все координаты имеют SRID=-1, например: GeometryFromText('POINT(43 56)',-1) - точка с неопределенной системой координат. Функцией SETSRID можно указать систему координат, при этом просто меняется идентификатор SRID в записи, но никаких вычислений не происходит. Пересчет координат из одной системы координат в другую выполняет функция transform, при этом изменяется как числовое значение координаты, так и размерность (градусы, метры, футы, ярды и проч., в зависимости от принятого в текущей координатной системе). Выражение transform( SETSRID(GeometryFromText('POINT(43 56)',-1),4326), 28408 ) задает для точки 'POINT(43 56)' мировую систему координат (4326) функцией SETSRID и вычисляет координаты точки в российской системе (28408).

Далее предполагается, что наблюдатель 1 располагается в первой точке и обладает сферой видимости 100000 метров, а наблюдатель 2 расположен в точке 2 и имеет такую же сферу видимости.

Задача 1:
Поиск всех объектов в радиусе 100000 метров в российской системе координат Пулково 1942-го года от наблюдателя, расположенного в точке POINT(43 56), заданной в мировой системе координат, с выводом результата в мировой системе:
SELECT the_geom FROM house
WHERE
distance(
transform( SETSRID(the_geom,4326), 28408 ),
transform( SETSRID(GeometryFromText('POINT(43 56)',-1),4326), 28408 )
) < 100000;

Задача 2:
Поиск всех объектов в радиусе 100000 метров в российской системе координат Пулково 1942-го года от наблюдателя, расположенного в точке POINT(43 56), заданной в мировой системе координат, с выводом результата в российской системе:
SELECT transform( SETSRID(the_geom,4326), 28408 ) FROM house
WHERE
distance(
transform( SETSRID(the_geom,4326), 28408 ),
transform( SETSRID(GeometryFromText('POINT(43 56)',-1),4326), 28408 )
) < 100000;

Задача 3:
Поиск всех объектов в радиусе 100000 метров в российской системе координат Пулково 1942-го года от наблюдателя, расположенного в точке POINT(8434555.38952802 6235317.6754922), заданной в российской системе координат, с выводом результата в российской системе:
SELECT transform( SETSRID(force_3d(the_geom),4326), 28408 ) FROM house
WHERE
distance(
transform( SETSRID(the_geom,4326), 28408 ),
SETSRID(GeometryFromText('POINT(8434555.38952802 6235317.6754922)',-1),28408 )
) < 100000;

Задача 4:
Поиск всех объектов в радиусе 100000 метров в российской системе координат Пулково 1942-го года от наблюдателя, расположенного в точке POINT1=POINT(8434555.38952802 6235317.6754922), которые исчезнут из поля зрения при перемещении наблюдателя в точку POINT2=..., заданных в российской системе координат, с выводом результата в российской системе:
SELECT transform( SETSRID(force_3d(the_geom),4326), 28408 ) FROM house
WHERE
not
(
distance(
transform( SETSRID(the_geom,4326), 28408 ),
SETSRID(GeometryFromText('POINT2',-1),28408 )
) < 100000
and
distance(
transform( SETSRID(the_geom,4326), 28408 ),
SETSRID(GeometryFromText('POINT1',-1),28408 )
) < 100000
)
and
distance(
transform( SETSRID(the_geom,4326), 28408 ),
SETSRID(GeometryFromText('POINT1',-1),28408 )
) < 100000;

Задача 5:
Поиск всех объектов в радиусе 100000 метров в российской системе координат Пулково 1942-го года от наблюдателя, расположенного в точке POINT1=POINT(8434555.38952802 6235317.6754922), которые появятся в поле зрения при перемещении наблюдателя в точку POINT2=..., заданных в российской системе координат, с выводом результата в российской системе:
SELECT transform( SETSRID(force_3d(the_geom),4326), 28408 ) FROM house
WHERE
not
(
distance(
transform( SETSRID(the_geom,4326), 28408 ),
SETSRID(GeometryFromText('POINT2',-1),28408 )
) < 100000
and
distance(
transform( SETSRID(the_geom,4326), 28408 ),
SETSRID(GeometryFromText('POINT1',-1),28408 )
) < 100000
)
and
distance(
transform( SETSRID(the_geom,4326), 28408 ),
SETSRID(GeometryFromText('POINT2',-1),28408 )
) < 100000;

Обсуждение: в примерах 4-5 выражение
(
distance(
transform( SETSRID(the_geom,4326), 28408 ),
SETSRID(GeometryFromText('POINT2',-1),28408 )
) < 100000
and
distance(
transform( SETSRID(the_geom,4326), 28408 ),
SETSRID(GeometryFromText('POINT1',-1),28408 )
) < 100000
)
задает объекты, входящие в сферу видимости обоих наблюдателей. Соответственно, объекты сферы видимости первого наблюдателя, не входящие в общую сферу видимости, пропадают из поля зрения (пример 4), а входящие в сферу видимости второго наблюдателя, не входящие в общую сферу видимости – появляются в поле зрения при перемещении наблюдателя из позиции 1 в позицию 2. Естественно, если сферы видимости обоих наблюдателей не перекрываются, решение задачи принимает вырожденный вид согласно примеру 3.

6 комментариев:

alexrush комментирует...

1.
transform( SETSRID(GeometryFromText('POINT(43 56)',-1),4326), 28408 )
Несколько запутанный пример. Для чего здесь SetSRID, если можно обойтесь GeometryFromText('POINT(43 56)',4326)?

2. Вы ничем не аргументируете использование force_3d (IMHO потому, что аргументировать нЕчем, ибо не нужна она здесь вовсе).

3. У Вас почему-то не сказано о том, что SRID, равный -1 - это крайняя мера, позволяющая работать с неструктурным картматериалом, а если материал соответствует той или иной проекции - ее нужно задавать явно на весь слой. (Приимущества Вы, безусловно, знаете. Или рассказать?)

4. Вы ни словом не обмолвильсб про возможность описания местных (в общем случае - произвольных) проекций.

4. Примеры в стиле "наблюдатель 1 располагается в первой точке и обладает сферой видимости 100000 метров, а наблюдатель 2 расположен..." слишком акдемичны. А вот "объекты сферы видимости первого наблюдателя, не входящие в общую сферу видимости, пропадают из поля зрения (пример 4), а входящие в сферу видимости второго наблюдателя, не входящие в общую сферу видимости – появляются в поле зрения при перемещении наблюдателя из позиции 1 в позицию 2." - читал из под стола и плакал. IMHO стиль надо упрощать. Сильно. Не забывайте, что на радиофизическом не все учились. Может что-то более насущное? Аренда земельных участков, недвижимость? Подальше от института, поближе к деньгам...

Печников Алексей комментирует...

Отвечаю:

1. SetSRID нужен для того, чтобы явно заданное значение координат потом в запросе заменить на значение из таблицы, для которой SRID = -1.

2. Пример из программы отображения навигации на трехмерной карте, естественно, нужны трехмерные данные, но тестовые данные были двумерными, пришлось делать их явное приведение к трехмерке, чтобы запросы на реальных данных потом работали корректно.

3. Приходилось разбираться после загрузки, в какой проекции какие данные и уже потом выправлять SRID. Ну а пока не проверил все слои (загружались неинтерактивно, скриптом) и не знал их проекцию естественно использовал SRID = -1. А проекцию, указанную в запросе, легко можно поправить непосредственно из приложения.

4. Надо рассказывать, как добавить запись в таблицу с описаниями координатных систем? Имхо тривиально.

P.S. О чем писать и как писать решает автор, удивительно видеть советы писать "о более насущном". Для меня этот проект просто хобби, работаю я в другой области, потому и писать буду на интересные мне темы.

alexrush комментирует...

если для Вас это хобби - no questions. Для меня это работа и хлеб насущный.
удивительно видеть советы писать "о более насущном" - вы же пишите не в свой локальный notepad на диск C: (или /home). Вы пишите в блогах. Для того, чтобы другие увидели, прочли и оценили. Чему же Вы удивляетесь?
Тем не менее, пишите еще. Буду читать, и естественно, комментировать.

Печников Алексей комментирует...

Если у Вас есть интересные идеи, предлагайте конкретные темы для рассмотрения. Если они будут интересны мне или читателям, исследуем их подробнее, а выбирать темы, которые кажутся более денежными не хочу. Уж не обессудьте :-)

alexrush комментирует...

++Я склоняюсь к "деньгам" именно потому, что человеческий интерес, основанный на деньгах - в большинстве случаев самый сильный и искренний.++
а "праздношатающаяся публика" {(с) Андропов Ю.В.} меня интересует мало.

Интересных тем много, я в настоящее время делаю ресурс на тему открытых ГИС и PostGIS в частности. Планирую в начале следующего конце месяца запустить в бету. инвайт гаратнтирую :)

Печников Алексей комментирует...

Ресурс по открытым ГИС это хорошо, а есть ли к ним интерес? Многих устраивает краденый MapInfo и ArcView. Сомневаюсь, что Вам удастся сделать продукт, который имеет функциональность и документацию лучше всех платных аналогов и стоит меньше, чем стоимость пиратского диска (3$ примерно).

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

Для заработка логичнее создать англоязычный сайт и торговать за бугром. Не думали?


(C) Alexey Pechnikov aka MBG, mobigroup.ru