Pull to refresh

Поиск горнолыжных трасс из космоса

Reading time4 min
Views5.1K
Если вы любите кататься на горных лыжах или сноуборде по некатанным склонам, или же вам просто надоели скучные выглаженные склоны Сорочан и Волена с их безумными ценами на подъемники – то эта статья для вас.

image

В феврале 2000 года шатл Endeavour 11 дней снимал топологию земли с помощью Spaceborne Imaging Radar-C/X-band Synthetic Aperture Radar. См. подробности тут

Результатом этого проекта явилась публично доступная база с данными о топологии земли за исключением ее полярных областей.

Полный массив данных имеет огромный размер и оперировать с ним в рамках ПК довольно проблематично. К счастью на сайте проекта Consortium for Spatial Information можно скачать топологический файл для интересующей вас области.

Данные доступны в формате ESRI GRID(ARC ASCII), которые представляют собой простую матрицу высот. Каждая ячейка матрицы имеет одинаковую широту и долготу. Файл состоит из метаинформации и матрицы высот в 6001 строк и 6001 столбцов.

Скорее всего наиболее подходящим инструментом для решения такой задачи является Mathlab, но за неимением оного – я воспользовался подручными средствами: MSSQL, Dapper, и консольное приложение на .Net

В итоге задача разбивается на следующие шаги:

  1. Закачиваем данные из файла в таблицу, содержащую высоту, № ряда и столбца в исходной матрице и высоту.
  2. Запускаем SQL запрос на выборку соседних фрагментов, для которых перепад высот укладывается в интересующие нас критерии поиска.
  3. Запускаем запрос на поиск цепочек из полученных в пункте 2 фрагментов.
  4. Экспортируем цепочки нужной длины в KML.

Чтобы загрузка данных не заняла целый день – я воспользовался пакетным загрузчиком – SqlClient.SqlBulkCopy.

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

select * from Points p1 JOIN Points p2 ON p1.row<>p2.row and p1.[Column]<>p2.[Column] AND  p2.row between p1.row-1 and p1.Row+1 and p2.[Column] between p1.[Column]-1 and p1.[Column]+1

Однако на таблице из 36 000 000 записей такой запрос работает невыносимо медленно – много-много часов. Разные эксперименты с индексами не далм существенной прибавки производительности.

Как всегда это бывает – самое простое решение оказалось самым эффективным: если добавть в таблицу с точками поле со счетчиком – и далее, зная кол-во столбоцов в каждом ряде, можно можно расписать табличку для поиска соседних ID:
ID-6002 ID-6001 ID-6000
ID-1 ID ID+1
ID+6000 ID+6001 ID+6002

Что позволяет существенно упростить JOIN:

select * from Points  p1 join Points p2 on (p2.id in (p1.id-6000-2,p1.id-6000-1,p1.id-6000,p1.id-1,p1.id+1,p1.id+6000 ,p1.id+6000+1,p1.id+6000+2)) WHERE  p1.Elevation-p2.Elevation>X

При наличии индекса по полю ID такой запрос довольно эффективен и отрабатывается менее чем за 15 минут.

Для построения цепочек из найденных ранее фрагментов наиболее эффективным оказался рекурсивный CTE-запрос примерно такого вида:

with chains (id,id1,id2,level,parentID,alt)
AS
(
select c1.id,c1.id1,c1.id2,0 as level,c1.id as parentID, c1.alt1 as alt from candidates c1 where not exists (select * from  candidates c2 where c2.id2=c1.id1) and exists(select * from  candidates c2 where c2.id1=c1.id2)
UNION ALL
select c1.id,c1.id1,c1.id2, level+1 as level,c2.id as parentID,c1.alt2 as alt from candidates c1 join chains c2 on c1.id1=c2.id2
)
select distinct p.*,level,ParentID  from chains c1 join candidates c2 on c1.id=c2.id
join Points p on p.ID=c2.id1 or p.id=c2.id2

Экспорт в KML с использованием библиотеки SharpKml предельно прост. Создается объект Placemark, который имеет в своем составе объект LineString содержащий посчитанные ранее координаты и высоту.

Условия поиска


Чтобы лыжи или борд куда-то ехали, а не просто застревали в снегу, уклон должен быть не менее 10-12 градусов, а чтобы был хоть какой-то интерес длина склона должна быть не менее 200-300 метров.

С другой стороны – уклон более 35 градусов уже не подразумевает расслабленного катания — оставим такие кручи профессионалам.

В качестве примера можно привести характеристики тех-же Сорочан с сайта.

  • Протяженность трасс: от 500 до 1000 метров.
  • Ширина трасс: от 30 до 70 метров.
  • Перепад высот: от 70 до 90 метров.
  • Высота над уровнем моря: 230 метров.
  • Средний уклон:10-12 градусов.
  • Максимальный уклон: 25 градусов.

Результаты


Самая высока точка в московском регионе – 317 метров, находится в районе станции 147 км. Можайского направления (карта). Самая низкая точка -75 метров (карта), находится в черте Рыбинска в русле Волги.

Склон с самым большим перепадом в 60 м и длиной 250 м находится опять же на берегу Волги в районе деревни Чукавино Тверской области (карта).

К сожалению этот склон, как и большинство остальных с хорошим перепадом и уклоном находится по берегу реки и покрыт лесом, однако мне удалось найти несколько подходящих теоретически катабельных вариантов:
Перепад Длина склона Координаты Комментарий
51 300 56°16'4.70''С; 38°20'34.20''В Водопад «гремячий» очень красивое место
43 200 56°26'22.08''С; 37°50'37.35''В Деревня Старово, Дмитровского района
51 200 55°38'21.04''С; 37°51'37.99''В Дзержинский карьер
42 200 56°28'55.13''С; 38°11'55.16''В Напротив Загорской ГАЭС. Д. Выпуклово
59 250 55°17'28.08''С; 38°43'5.33''В Белая гора. Воскресенск

Само собой в выборку попали известные Гонолыжные курорты:
Курорт Высота, м Длина склона, м
Волен 42 200
Сорочаны 40 200
Чулково 46 200
Лоза 42 200
Парамоново 50 250

Следует принять во внимание, что указанные цифры неточные из-за дескретности данных: каждый «квадрат» в матрице высотот имеет сторону 92.7 м.

В качестве POC я выбран склон в окрестностях деревни Старово Дмитровского района.
Местные бабки рассказали, что тут, во времена царя гороха, работал горнолыжный подъемник. Склон пологий, зато довольно длинный, в низовьях заросший кустарником. Здесь же, в деревне, если верить wikimapia есть база дельтапланеристов.

Видео с тестированием этого склона можно посмотреть тут.

Адрес проекта на гитхабе
Примеры сгенерированных KML-файлов
Инсталлятор
Tags:
Hubs:
Total votes 18: ↑18 and ↓0+18
Comments5

Articles