Пользователь
0,1
рейтинг
25 июня 2012 в 19:54

Разработка → Структура данных проекта OpenStreetMap, заглянем под юбку сервису из песочницы

Пролог



Проект OpenStreetMap (OSM) открытых геоинформационных данных под свободной лицензией CC-BY-SA (а в скором времени под Open Database Licence) известен достаточно широко, что бы не тратить время на его подробное представление. Главной особенностью проекта и его основным преимуществом по сравнению с любыми другими аналогами являлся принцип полностью открытых географических данных, которые могут быть использованы кем угодно и и как угодно (в рамках лицензии CC-BY-SA) и могут свободно дополняться и уточняться любым участником проекта. Как и любые другие данные, географические данные точно так же подлежат структурированию при хранении и обработке. В данной статье я постараюсь описать основные части структуры данных OSM остановившись больше на принятых типах данных и представлении их в пространственном виде. Работая постоянно с данными проекта OSM очень часто приходится уточнять или пояснять не которые базовые аспекты, поэтому возникла необходимость кратко изложить их в виде одного текста.

В целом, всю структуру данных можно представить схематично на следующем рисунке:
рисунок 1. Структура данных OpenStreetMap
рисунок 1. Структура данных OpenStreetMap.

Все данные можно условно разбить на три основные группы:

  1. типы данных, описывающие в виде иерархической связи сам объект, как некую пространственную сущность, имеющую свой конечный результат — известные координаты всех частей объекта;
  2. информационная часть — это описательная характеристика объекта, не имеющая к пространственной географической структуре объекта прямого отношения (его название, физические, логические и прочие свойства);
  3. служебные атрибуты объекта, необходимые для организации процесса хранения и обработки информации в виде набора данных, такие как уникальный идентификатор, состояние объекта в базе, время последней правки объекта в базе и т.д.


Останавливаться на служебных атрибутах объектов я не буду, отмечу лишь, что ими обладает любой самостоятельный объект в OSM и их характеритики и обязательность тех или иных атрибутов определяет конкретная версия API проекта. На текущий момент это API версии 0.6.

Часть 1. Базовые типы географических данных в OpenStreetMap



Базовых типов по сути всего три: точка (node), линия (way) и отношение (relation). В данном случае я использую не перевод самих типов данных, а их фактическое свойство. Сами типы node, way и relation называются так, потому что именно так они были придуманы изначально. Все без исключения объекты в OSM описываются этими тремя типами данных, после чего информационно наполняются комбинациями тегов. Модель данных в OSM строится на иерархической ссылочной структуре, из чего следует, что любой последующий тип данных не содержит информацию содержащуюся в предыдущих типах а образует новую сущность, ссылаясь на некое множество объектов предыдущего типа. Так же следует упомянуть, что любой объект имеет в структуре данных OSM свой идентификатор (ID), уникальный в пределах данного типа объектов. Именно по этому идентификатору и происходит ссылка на сам объект. Рассмотрим структуру базовых типов по порядку.

Первый тип: точка (node) — это минимальный набор данных, который содержит в себе информацию о паре координат: широта, долгота (lat, lon) и является базовым в иерархической модели. Это единственный тип данных, который хранит саму географическую информацию — координаты, в виде широты и долготы. Модель данных OSM оперирует исключительно двухмерными данными в пределах проекции WGS84. В дальнейшем мы будем считать, что координаты — это не информационная составляющая объекта точки, а неотъемлемая часть его структуры. В XML нотации, объект данного типа будет выглядеть так:

<node id='19' lat='58.888047127548994' lon='49.747870758186764' />


Одна точка с уникальным id равным 19 и парой координат. Координаты в OSM используются в десятичной записи, поскольку это гораздо проще обрабатывать чем форматы координат с минутами и секундами. Сама по себе точка может быть самостоятельным объектом, описывающим какой-то точечный объект (геометрический примитив) или не иметь вовсе собственной информационной составляющей, а быть частью другого объекта (линии или отношения). При этом, забегая немного вперёд, отмечу, что точка одновременно может быть и самостоятельным объектом, несущим уникальную информацию и быть частью другого объекта.

Второй тип данных: линия (way) — это совокупность указателей на объекты типа точка (node). Как минимум, линия состоит из одной точки, т.е. должна содержать как минимум одну ссылку на уже существующий объект типа точка. Линия из одной точки не противоречит структуре данных OSM, но противоречит понятиям элементарной геометрии и вызывает обморок и панику у некоторых слишком ранимых алгоритмов обработки данных, поэтому правильная линия всегда содержит как минимум ссылки на два существующих объекта типа точка.

Правильная XML нотация объекта типа линия будет заключаться в описании всех необходимых точек, после чего следует сама запись о линии, в которой перечисляются все её точки. В простейшем варианте это будет выглядеть так:

<node id='23' lat='58.875047918145675' lon='49.785240674006126' />
<node id='22' lat='58.86687448573524' lon='49.737090974777324' />

<way id='24'>
  <nd ref='22' />
  <nd ref='23' />
</way>


Порядок перечисления точек в линии важен, он характеризует последовательность точек в линии и направление самой линии, т.е. у линии всегда есть начало и конец, даже если она замкнутая (в этом случае они просто совпадают). В данном примере мы вначале описали две точки, задав их координаты, а потом описали линию, сославшись на id этих точек. Одна точка может входить в любое количество объектов линий, при этом должна быть описана только один раз, т.е. точка может быть общей для двух линий, в этом случае ссылка на неё содержится в обоих линиях. Таким образом строится цельный граф объектов (чаще всего дорожный граф для расчёта роутинга), который представляет из себя совокупность объектов (линий), имеющих связь через их общие члены (точки).

Если мы хотим создать ещё одну линию из уже существующих точек 19 и 23, то мы опишем её так:

<way id='48'>
  <nd ref='19' />
  <nd ref='23' />
</way>


В нашем случае точки 19 и 23 уже описаны выше, а точка 23 вошла в состав двух линий 24 и 48 и стала общей для них.

Наши линии 24 и 48 можно графически представить в проекции меркартора следующим образом:

рисунок 2. Две линии
рисунок 2. Две линии

Подписи на рисунке — id объектов: красные у точек, чёрные у линий; стрелкой указано направление линии, т.е. обе линии заканчиваются на точке 23.

Следующий тип данных: отношения (relation). По сути все объекты кроме точки — уже отношения, однако линии выделены в отдельный тип данных как наиболее распространённые, описывающие основные геометрические примитивы: линии, полилинии и полигоны. Для всех более сложных геометрических объектов, а так же для объектов являющихся не чисто геометрическими, а логическими (коллекции, списки, иерархии взаимосвязей) предназначен универсальный тип данных — отношения.

В целом, описание отношения отличается от линии тем, что линия — это всегда совокупность точек, а отношение — это совокупность любых объектов, как точек и линий, так и других отношений. Следовательно в отношениях указывается не только id объекта, но и его тип. В самом минимальном варианте отношение может содержать ссылку только на один объект. Оперируя объектами описанными в примерах выше, можно написать отношение:

<relation id='31'>
  <member type='way' ref='24' />
  <member type='node' ref='19' />
</relation>


Это фиктивное абстрактное отношение, описывающее, что в него входит два объекта (члены отношения) — точка 24 и линия 19 и более не несущее никакой другой информации. В реальном случае у отношения должен быть указан тип, как тег (информационная составляющая) самого объекта отношения, а у членов отношения должны быть указаны роли в ссылках на объекты.

Ниже приведён пример самого распространённого отношения типа «мультиполигон», которое описывает один замкнутый внешний полигон из трёх точек с вырезанным из него замкнутым полигоном тоже из трёх точек меньшего размера. О геометрических примитивах (замкнутых и не замкнутых полигонах) и тегах объектов речь пойдёт далее, а пока следует обратить внимание на параметры ролей (role) у объектов отношения и наличие тега описывающего тип.

<node id='1218' lat='58.870941122729505' lon='49.758021019729554' />
<node id='1216' lat='58.8704000725183' lon='49.74703196841415' />
<node id='1215' lat='58.879055860772034' lon='49.74964840920353' />
<node id='1209' lat='58.86471853452049' lon='49.780522410518245' />
<node id='1207' lat='58.863365649894774' lon='49.72453057762546' />
<node id='1206' lat='58.892035483174' lon='49.74755525657201' />
<way id='1217'>
  <nd ref='1215' />
  <nd ref='1216' />
  <nd ref='1218' />
  <nd ref='1215' />
</way>
<way id='1208'>
  <nd ref='1206' />
  <nd ref='1207' />
  <nd ref='1209' />
  <nd ref='1206' />
</way>
<relation id='1221'>
  <member type='way' ref='1208' role='outer' />
  <member type='way' ref='1217' role='inner' />
  <tag k='type' v='multipolygon' />
</relation>


Роль outer говорит о том, что данный объект будет наружным контуром графического объекта, а роль inner сообщает о том, что пространство внутри этого объекта необходимо исключить из площади результирующего объекта. Графически наш мультиполигон будет выглядеть так:

рисунок 3. Мультиполигон
рисунок 3. Мультиполигон

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

Объект relation может быть членом другого relation, при этом уровень вложенности и иерархия вверх ничем не ограничивается. Структурное ограничение заключается в том, что объект relation не может быть членом самого себя, т.е. содержать ссылок на самого себя. Рекурсия в структуре типов данных в OSM недопустима, хотя конечно ничто не мешает создать такой объект и даже вполне успешно воткнуть его в базу данных.

Определив три базовых типа объектов надо ввести понятие начального и конечного объекта. Начальным объектом является любой объект, который входит в состав любого другого объекта, т.е. является дочерним по отношению как минимум к одному объекту, но сам при этом ни включает ни одного другого объекта. В случае OSM это всегда точка. Либо другое его определение — начальный объект несёт в своей структуре (не в информационной части!) только географические координаты и не содержит ссылок на другие объекты.

Конечным объектом является максимальный по иерархии родительский объект, который не является дочерним по отношении ни к одному другому объекту, т.е. не входит в состав ни одного другого объекта. Это может быть любой из трёх перечисленных типов: точки, линии, отношения. Отдельный точечный объект, никуда не входящий, состоящий из одного объекта типа точка, не является начальным объектом, поскольку не является началом иерархии объектов, но является конечным объектом, поскольку на нём заканчивается пространственное описание объекта.

Часть 2. Информационная схема объектов



Тип объекта описывает географические (пространственные) свойства объекта, но ничего не говорит о свойствах самого объекта, его характеристиках, назначении и прочем. Для это существует информационная часть структуры данных OSM, основанная на принципах тегирования объектов, т.е. назначении им определённых меток и указанием свойств этих меток. Теги задаются в виде пары ключ=значение, что в нотации XML для нашей линии 24 выглядит так:

<way id='24'>
  <nd ref='22' />
  <nd ref='23' />
  <tag k='highway' v='primary' />
</way>


В данном случае мы добавили свойство нашей линии, а именно указали тег highway со значением primary, что в принятой схеме тегирования обозначает что наша линия является основной дорогой (дорога класса ниже магистрали, но выше второстепенной). Тегов у любого объекта может сколько угодно много, что позволяет задать все его основные свойства и описать все второстепенные параметры, а так же в произвольной форме дополнить объект любой информацией. Сама схема тегирования в OSM является одновременно самым главным её архитектурным преимуществом, поскольку позволяет описать фактически любые свойства объекта, т.к. реально никто не ограничивает вас в выборе новых тегов для новых свойств объектов; и одновременно самым больным её местом, поскольку любая свобода в выборе способов обозначения всегда порождает религиозные войны различных групп пользователей, так и не сошедшихся во мнении, как обозначать тот или иной спорный объект.

Если мы немного расширим информационное описание наших двух линий 24 и 48 из первой части, то можем получить что-то вроде:

<node id='23' lat='58.87753645355202' lon='49.79290110146539'>
  <tag k='highway' v='traffic_signals' />
</node>
<node id='22' lat='58.87456113991739' lon='49.73690926857261' />
<node id='19' lat='58.89362576054878' lon='49.7492065402827' />
<way id='48'>
  <nd ref='19' />
  <nd ref='23' />
  <tag k='embankment' v='yes' />
  <tag k='highway' v='secondary' />
  <tag k='incline' v='up' />
  <tag k='lanes' v='2' />
  <tag k='maxspeed' v='60' />
  <tag k='name' v='улица Пожарского' />
</way>
<way id='24'>
  <nd ref='22' />
  <nd ref='23' />
  <tag k='highway' v='primary' />
  <tag k='lanes' v='6' />
  <tag k='lit' v='yes' />
  <tag k='name' v='проспект Минина' />
  <tag k='oneway' v='yes' />
  <tag k='ref' v='М84' />
</way>


Линия 48 у нас стала «улицей Пожарского», с ограничением скорости в 60 км/час, количеством полос равным двум, имеющей положительный градиент уклона в сторону от точки 19 к точке 23, являющейся второстепенной дорогой и поднятой относительно уровня земли на насыпь. А линия 24 у нас основная дорога (классом выше чем secondary) с 6-тю полосами движения, имеющей стационарное освещение и одностороннее движение разрешённое в направлении от точки 22 в сторону точки 23, носит название «проспект Минина» и является частью федеральной трассы М84. Обе дороги имеют общую точку 23, которая является перекрёстком со светофором.

Расписывать подробно текущие соглашения по тегированию не задача одной статьи, для этого есть отдельный проект вики-документации для фиксирования принятых соглашений [1]. Остановимся только на базовых принципах тегирования.

  • На любом конечном объекте обязательно должны быть теги, какова бы не была длинна иерархии. Любое географическое (пространственное) описание объекта должно заканчиваться хотя бы одним информационным свойством объекта. Тег «type=(multipolygon|*)» у объектов отношений является исключением, он не является информационным, он является частью структуры которой описываются отношения, т.е. кроме него должен быть ещё хотя бы один тег. Определение конечного объекта мы дали в первой части.
  • Теги могут быть совершенно на любых типах объектах. Наличие или отсутствие тегов на одном объекте в составе другого объекта никак не влияет на необходимость или запрет наличия тегов на другом объекте, если они конечно не противоречат друг другу логически и не являются избыточными. Например на линии может стоят тег, что это дорога, а на точках, являющихся частью этой дороги могут стоять теги описывающие точечные объекты на этих точках — светофоры, лежачие полицейские и т.д., т.е. точка не являясь конечным объектом (входит в состав дороги) тем не менее может описывать самостоятельно любой объект.
  • Теги одного объекта должны быть уникальными, т.е. объект не может содержать два одинаковых тега с разными значениями, например highway=primary и highway=secondary в пределах одного объекта недопустимо. Некоторый софт может использовать перечислимые типы значений, например highway=primary;secondary может интерпретироваться как highway=primary и highway=secondary одновременно, но большая часть софта интерпретирует как «highway» = «primary;secondary», где «primary;secondary» не будет соответствовать ни primary ни secondary.
  • Теги описывающие свойства объекта должны быть только на самом объекте. Звучит настолько логично, что даже немного глупо, но реально доставляет массу хлопот при обработке данных. Смысл в том, что никакие свойства объекта не должны дублироваться на членах этого объекта либо на родительских объектах. Если мы к примеру возьмём объект «лес», описанный в виде замкнутого полигона, у которого стоит свойство natural=wood, то, что не надо это свойство вписывать в каждую точку, из которой строится полигон ясно даже малому ребёнку, но куда сложнее дела обстоят с отношениями и мультиполигонами. Рассмотрим вариант с тем же лесом, но выполненным уже не в виде полигона, а в виде мультиполигона, т.е. в виде отношения, состоящего минимум из двух замкнутых полигонов: наружного (роль outer) и внутреннего (роль inner). В данном случае свойство natural=wood должно стоять не на полигоне с ролью outer, а на самом отношении. Если же в состав отношения входит несколько объектов как с одинаковыми свойствами, так и с разными, то все свойства общие для всех членов должны описываться в самом отношении, т.е. в их родительском объекте, а уникальные свойства на каждом объекте, чьи свойства они описывают. Возвращаясь к тому же лесу, допустим у нас в отношении несколько членов с ролью outer и сколько то (или вообще нет, такое тоже возможно) членов inner. При этом все члены outer — это лес, но каждый из них имеет своё название, таким образом тег natural=wood должен быть на самом отношении, а уникальные теги name на каждом из полигонов outer свои.


Часть 3. Геометрические примитивы



Основная или как минимум наиболее частая задача для любых географических пространственных данных — получение графического представления объектов, описанных этими данными. Проще говоря рендеринг самих карт, схем, планов. Сами алгоритмы, правила, стили и методы рендеринга карт — это задача уже прикладного софта, но всё сводится к отрисовке основных геометрических примитивов, которые получаются из объектов трёх типов данных, перечисленных в первой части.

Далее я буду ссылаться на типы данных в виде их нотации в OSM, т.е. node, way и relation, что бы не путать с геометрическими объектами точками, линиями, полилиниями и т.д., следовательно далее под линией я буду подразумевать не географический пространственный тип данных way в OSM, а геометрическую фигуру — линия, которая является кратчайшим расстоянием между двумя точками на плоскости.

Итак, из чего формируются основные геометрические примитивы.

Точка (point) — это один объект типа node. Положению её в заданной проекции на карте соответствует её пространственное положение в географических координатах. Одна пара координат lat/lon транслируется в координаты x/y карты с учётом проекции.

линейные объекты


Линия (line) — это, как мы уже сказали, кратчайшее растояние между двумя точками, соответствует объекту типа way, содержащему два объекта node. Любые два node, поскольку мы оперируем плоским пространством, а следовательно расстояние между любыми двумя точками всегда будет прямой линией.

Полилиния (polyline) — это связанная последовательность сегментов, где каждый сегмент представляет из себя одну линию, связанную своим концом с началом следующего сегмента. Вся последовательность является единым цельным объектом. Соответствует объекту way содержащему три и более node. Полилиния может быть объектом relation, содержащим последовательно включённые объекты way, где каждый следующий объект way начинается с объекта node, которым закончился предыдущий way. Полилиния может быть либо объектом way, содержащим node, либо relation, содержащим way, т.е. не может быть relation содержащим и way и node одновременно, однако может быть объектом relation, содержащим одновременно way и другие relation, содержащие только объекты way.

Виды полилиний:

рисунок 4. полилиния
рисунок 4. polyline = way(node1,node2,node3,node4)

рисунок 5. полилиния
рисунок 5. polyline = relation( way1(node1,node2), way2(node2,node3), way3(node3,node4) )

рисунок 6. полилиния
рисунок 6. polyline = relation2( way1(node1,node2), relation1( way2(node2,node3), way3(node3,node4) ) )

площадные объекты


Полигон (polygon) — это замкнутая полилиния, у которой последняя точка совпадает с первой. В типах данных OSM соответствует объекту way с несколькими (три и более) объектами node, при этом количество членов объекта way всегда больше на единицу, т.к. первый объект node повторяется дважды: в начале и в конце списка. Так же полигон может быть собран в виде relation, в который последовательно включаются way, образующие совместно замкнутый контур, т.е. началу каждого объекта way соответствует конец одного другого объекта way. В отличии от полигона в way, полигон в relation не дублирует последний объект в перечислении с первого, поскольку для way это необходимо в связи с тем, что он ссылается на объекты node и только по факту дублирования node как первого и последнего элемента списка членов можно судить о том что это замкнутый полигон, а не линейный объект полилиния. В полигоне собранном в виде relation последний объект node последнего включённого объекта way или relation содержащего way соответствует первому объекту node первого включённого way.

В случае полигона описываемого в виде relation, обязательно указывается тег type=multipolygon на самом объекте relation. Таким образом мы определяем, что речь идёт о площадном геометрическом, а не о линейном объекте.

Виды полигонов:

рисунок 7. полигон
рисунок 7. polygon = way(node1,node2,node3,node4,node1)

рисунок 8. полигон
рисунок 8. polygon = relation( way1(node1,node2,node3), way2(node3,node4), way3(node4,node1) )

рисунок 9. полигон
рисунок 9. polygon = relation3( relation1( way1(node1,node2,node3), way2(node3,node4), way3(node4,node5), way4(node5,node6,node7) ), relation2( way5(node7,node8), way6(node8,node1) ) )

составные объекты


Составные объекты — это объекты которые невозможно описать одним примитивом way, всегда строятся на базе объектов relation у которого type=multipolygon. Полигоны и полилинии описанные в виде relation всегда можно упростить до одного объекта way, в то время как составной объект в самом упрощённом случае даёт минимум два объекта way. Например это площадная фигура (полигон) из которой математически вычтена другая фигура (полигон меньшего размера). Пример мультиполигона, являющегося составным объектом, с иллюстрацией был приведён в первой части, в описании объектов relation.

Мультиполигоны для составных объектов, так же как и полигоны и полилинии могут собираться из простых way или из других relation, состоящих из любого количества way. Для такого мультиполигона обязательно указание роли для каждого входящего члена, будь то way или relation. Как минимум должен быть один член с ролью outer. Именно объект или объекты с этой ролью задают главный (внешний) геометрический контур результирующего объекта. Объектов с ролью inner может и не быть в частном случае, но тогда такой мультиполигон — это обычный полигон, просто описанный избыточно. Объекты с ролью inner указывают какие участки, находящиеся внутри внешнего контура, не являются частью результирующей фигуры. Например это поляна в лесу или внутренний двор дома, ограниченный со всех сторон стенами этого дома.

Все объекты с одной ролью в одном мультиполигоне должны собраться в один или несколько замкнутых не пересекающихся по границам контуров.

Ограничения и соглашения на использования графических примитивов описываемых как relation



Несмотря на простоту, логичность и масштабируемость конструкции объектов данных relation в реальном мире OSM у них есть огромное количество ограничений, связанных в первую очередь с ограничениями алгоритмов обработки данных текущего софта. Поэтому существует ряд соглашений на использование объектов relation в тех или иных ситуациях. Все их можно свести к следующим главным пунктам:

  1. все площадные объекты, описываемые relation являются мультиполигонами, т.е. имеют type=multipolygon и обязательное указание роли для членов outer|inner, т.о. полигоны на рисунках 8 и 9 — это всегда только мультиполигоны;
  2. линейных общепринятых объектов, описываемых через relation всего два: type=boundary для административных границ и type=route для маршрутов общественного транспорта, все остальные типы или relation без типов являются просто коллекциями или списками объектов и не обрабатываются как геометрические объекты; следовательно если полилинии на рисунках 5 и 6 являются дорогами или реками или любыми другими линейными объектами, кроме границ или маршрутов, и их теги расположены на самом relation, то они не будут обрабатываться и учитываться вообще;
  3. все остальные объекты relation, кроме type = multipolygon|boundary|route — не являются графическими объектами, а служат для объединения объектов в коллекции по каким-то произвольным общим признакам, которые тот или иной софт вправе учитывать или игнорировать по своему усмотрению.


Часть 4. Что сделать, чтобы стало лучше?



До сих пор я описывал существующую структуру данных OSM, дополняя что из теории в реальности не будет работать или не реализовано. Сейчас же я попытаюсь сформулировать наиболее важную структурную проблему формата данных OSM и что надо сделать, что бы это исправить.

Как не трудно увидеть из всего описанного выше, в OSM нет штатного типа данных для площадных объектов. Нет вообще, не предусмотрен как класс. Либо мы сооружаем объект relation с мультиполигоном, либо мы делаем way у которого последняя точка равна первой, но если в случае с мультиполигоном у нас есть определённость в том, что объект является площадным, то в случае простого way у нас нет единого способа на уровне структуры данных предположить, каким является объект, линейным или площадным. Территория школы является по определению объектом площадным, потому что описывает занимаемую площадь, в то время как забор вокруг территории школы, сам как объект, является исключительно линейным объектом. Но и тот и другой объект начинаются и заканчиваются одной и той же точкой. На уровне обработки данных мы можем только с вероятностью предполагать, о каком типе объекта идёт речь и уже анализируя не структурную, а информационную часть (теги) догадываться, что это площадной или линейный объект.

Такие угадывания сильно усложняют обработку данных, поскольку требуют уточнения по информационной части, а так же приводят часто к тому, что при хранении данных на этапе обработки часть данных всегда дублируется как линейный и как площадной объект. Для того что бы снизить необходимость угадывания, в OSM началась порочная практика дополнения в тегах типа объектов, например для площадного объекта указывается тег area=yes или для линейного объекта, но нарисованного замкнутой полилинией с area=no. Вроде бы не панацея, но вполне решение, однако это породило и порождает ещё большие проблемы, как например попытки отмечать территорию проезжей части дороги как площадной объект используя при этом теги для линейных дорог добавляя area=yes. В результате приходиться на этапе обработки данных, и в частности при построении роутингового дорожного графа, включать в обработку дополнительные условия, проверяя, действительно ли объект является требуемым линейным объектом маршрута, а не линией описывающей некоторый площадной объект.

Мультиполигоны и были придуманы как решение, для описания площадных объектов, но правда с ориентиром на сложные составные объекты. Что с одной стороны убивает сразу двух зайцев (вот вам и площадной объект type=multipolygon и одновременно операции с вычитанием геометрий объектов), но именно из-за этого этот универсальный тип данных не используется для описания составных линейных объектов, кроме очень редких исключений. К тому же мультиполигон не лишён структурного недостатка — возможности только по типу объекта данных предположить его геометрический тип.

Я считаю, что в структуре OSM категорически необходим отдельный тип данных для обозначения площадных объектов и являющийся примитивом, объединяющим в себе только ссылки на базовые объекты node. Такой тип данных, area, должен однозначно описывать только объекты имеющие площадь и не являющиеся линейными и всегда являться замкнутым объектом, даже если первая и последняя точка не совпадают. В свою очередь ни один из линейных объектов way не может в этом случае описывать площадные объекты, а только линейные объекты. Это не избавит от необходимости делать отношения relation для сложных объектов, но зато позволит однозначно интерпретировать простые объекты, упрощая обработку данных и исключая дублирование данных в процессе обработки. А простых объектов в базе OSM подавляющее большинство по сравнению с relation.

По аналогии с area, все отношения должны так же быть разделены на линейные и площадные геометрические объекты и просто произвольные коллекции. Учитывая не большой процент relation как объектов, по сравнению со всей базой, можно конечно ввести это разделение по информационной части, в том же type, добавив например type=polyline по аналогии с multipolygon, но для линейных объектов, которые сейчас не обрабатываются, но это уже не так важно, как введение базового примитива area.

Надеюсь, что после прочтения у вас сложилось представление о структуре данных в проекте OpenStreetMap.

[1] — Основные правила тегирования объектов в OSM, оригинал: http://wiki.openstreetmap.org/wiki/Map_Features и перевод: http://wiki.openstreetmap.org/wiki/RU:Map_Features
Maks Vasilev @MaksVasilev
карма
16,0
рейтинг 0,1
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (12)

  • +2
    Топику крайне не хватает фото подстать названию.
    • +3
      А по делу отлично, спасибо.
  • +1
    Внести массово популярное изменение в osm весьма проблематично :)
    • +2
      Если вы про area, то это не так уж сложно и делается. Надо в api 0.7 ввести этот тип, но автоматом ничего не переделывать в поведении софта по умолчанию со старыми типами, а в версии api 0.8 сделать тип area как обязательный для полигонов, а way как тип только для полилиний. Учитывая период жизни одной версии api, вполне достаточно времени, что бы софт, работающий с данными OSM можно было адаптировать к версии 0.8 не спеша.

      В идеале даже весь софт, редактирующий данные (josm, онлайн редакторы, merkaartor и т.д.) начиная с версии api 0.7 должны автоматом преобразовывать полигоны в area при редактировании. А оставшееся в базе перед сменой api на 0.8 сконвертить прямо в базе. Как DBA, могу сказать, что это совсем не сложно в плане реализации и не займёт столько времени как перелицензирование :)
      • 0
        Лучше ничего не делать, чем такие полумеры. Коли ввели тип area — всё, way и multipolygon больше не работают, нужно всё переконвертировать. Переход на новую версию API в любом случае изменит структуру базы, почему бы не добавить алгоритм апгрейда типов данных.
        • 0
          Алгоритм апгрейда данных? Вспомним redaction bot.
          • 0
            Здесь всё таки проще, по факту сами данные не меняются и не выпиливаются, только меняется тип у некоторых, а все ноды остаются. Это гораздо проще, чем вырезать из базы то, что сам не знаешь.
        • 0
          Это не полумеры, а процесс нормального эволюционного внесения изменения в API, который позволит пользователям самим на первом этапе преобразовывать типы, точнее оно может преобразовываться автоматом в том же JOSM при редактировании, а уж остатки конвертить ботом на следующей смене API.

          Не надо делать революций, к которым окажется не готово 99% софта, работающего с данными да и среди пользователей придётся вести разъяснительную работу, это тоже время займёт. Разом в одном API объявить, что все way теперь только полилинии — это чревато бунтами.
  • +3
    Тем, кто осилил до конца, подскажу, что тип area — самый вероятный кандидат на реализацию (но только когда закончится затянувшееся перелицензирование). Очень много на этот счёт понаписано в разделе вики The Future of Areas и далее по ссылкам. Одна из не упомянутых там страниц — размышления и наброски алгоритмов Фредерика Рамма.
    • 0
      Спасибо. Как раз ссылок статье не хватает.
  • 0
    Спасибо за статью! Хоть я и не интересуюсь OSM (кроме самых меркантильных пользовательских нужд), но статью прочитал на одном дыхании! Очень познавательно и доходчиво.
    • 0
      Иногда как раз не хватает именно познавательных материалах о таких вещах, которые обычно не можешь объяснить, потому что это настолько основы, что даже и не знаешь как сформулировать, настолько они очевидны.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.