Создание векторных полигонов с производительностью рендеринга, как GISCloud?


59

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

Насколько мне известно, есть 3 варианта для достижения этой цели с помощью Canvas, SVG, Flash.

Похоже, что Flash будет лучшим решением, если он будет работать на Apple iPhone / iPad, так как он обеспечивает самый быстрый рендеринг и самый чистый дисплей. Canvas, кажется, второй лучший выбор, но он занимает ОЧЕНЬ много времени, если на карте отображаются сотни полигонов, тогда как SVG визуализируется еще дольше.

Я почти потерял надежду в поиске решения этой проблемы, но сегодня я наткнулся на компанию GISCloud http://www.giscloud.com (в настоящее время в бета-версии с бесплатной регистрацией).

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

Посмотрите сами на это удивительное демо: http://www.giscloud.com/map/284/africa

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

Что я заметил, глядя на запросы с firebug, так это то, что карта запрашивает определенные файлы json. Кажется, что в зависимости от уровня / области масштабирования запрашиваются несколько файлов json.


Я должен также упомянуть, что когда giscloud загружает данные на странице, нависающей над вектором, немедленно меняет цвет, не создавая новый запрос.

ПРИМЕРЫ:

Я предполагаю, что структура URL соответствует стандартной логике службы листов (например, папка с 3-й по последнюю очередь является уровнем масштабирования ...).

В любом случае я проанализировал фактические данные этих файлов json, и кажется, что логика, которую они используют, следует некоторой логике, с помощью которой они создают свои векторы, основываясь только на этих значениях данных:

  • ширина / высота: они определяют ширину и высоту данных, обслуживаемых в каждом запросе json
  • пиксели: здесь они определяют значения пикселей, которые, как я предполагаю, как-то связаны с некоторыми общими координатами пикселей x / y для обобщенных уровней точек? Я предполагаю, что у них есть способ автоматически упростить регион в зависимости от уровня масштабирования. Я предполагаю, что они используют координаты пикселей. Я предполагаю, что они значительно уменьшают размер данных, которые должны быть загружены, по сравнению с данными широты / долготы.
  • стили: здесь они определяют два значения RGB CSS. «F» представляет цвет файла полигона и «S» представляет цвет границы полигона.
  • geom: здесь я предполагаю, что они каким-то образом определяют конкретное определение каждого полигона в загружаемом тайле, где такие данные определяются на основе окна контейнера карты. Также интересно то, что каждая запись имеет значение «S», которое, как я полагаю, используется в качестве необязательного значения атрибута или ссылки на функцию, и в конце каждой записи здесь есть область, которая, кажется, определяет конкретный идентификатор для каждого вектора вместе с идентификатор слоя, который, как я догадываюсь, используется для того, чтобы каким-то образом объединить данные из каждого вызываемого запроса мозаики json.

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

Вот извлеченная разбивка одного из этих запросов:

{"width":256,"height":256,"tile":
{"pixels":
[0,6461,-1,0,5,148,0,509,-1,10715,-1,1,-1,251,-1,1,-1,1,-1,251,-2,3,-1,255,-1,249,-2,5,-2,247,-1,509,-3,251,-1,2,-2,253,-2,252,-2,254,-1,255,-1,254,-1,255,-1,1276,-2,13,-1,233,-1,2,-1,253,-1,1,-1,255,-1,247,-1,1306,-1,1533,-1,1269,-1,1276,-1,2303,-1]},

"styles":
[{"f":"rgb(99,230,101)","s":"rgb(5,148,0)","lw":"0"}],

"geom":
[
{"s":0,"p":[4,143,5,144,3,146,1,146,2,143,4,143],"c":"layer1156_5098"},
{"s":0,"p":[-2,143,0,140,2,141,2,144,1,146,-2,144,-2,143],"c":"layer1156_5067"},
{"s":0,"p":[7,143,5,144,4,143,2,143,2,141,5,138,6,139,5,141,7,143],"c":"layer1156_5051"},
{"s":0,"p":[10,141,11,137,12,137,14,137,12,142,9,143,9,142,10,141],"c":"layer1156_5041"},
{"s":0,"p":[1,136,0,140,-2,143,-2,136,1,136],"c":"layer1156_5038"},
{"s":0,"p":[8,143,5,141,5,137,8,136,10,137,10,141,8,143],"c":"layer1156_5033"},
{"s":0,"p":[5,137,2,141,0,140,1,136,1,136,2,135,3,136,5,137],"c":"layer1156_5028"},
{"s":0,"p":[10,134,12,136,11,138,8,135,10,134],"c":"layer1156_5020"},
{"s":0,"p":[-2,133,0,136,-2,136,-2,133],"c":"layer1156_5005"},
{...}
...
]
}

Как мы можем воспроизвести такой же (или похожий) тип скорости, используя postgis (который, как мне кажется, они также используют)?


Ах! Не смотрите на файл JSON, посмотрите на другие, казалось бы, неважные изображения, которые передаются :) Смотрите мой ответ ниже.
Раги Язер Бурхум

«Есть 3 конкретных варианта» ... Так что же такое Silverlight, рубленая печень ?
Кирк Кайкендалл

Silverlight требует, чтобы его плагин работал, и я не думаю, что он на самом деле быстрее, чем решение, используемое в giscloud, но я не проводил никаких прямых сравнений.
NetConstructor.com

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

@RagiYaserBurhum Есть хорошее объяснение того, как это использовалось для картирования изохрон путешествий с использованием аналогичной техники: mysociety.org/2012/11/08/…
djq

Ответы:


56

Я видел эту технику в прошлом. Это объяснил мне Зейн Мемон (из Trulia), который помог мне внести свой вклад, когда Михал Мигурски создавал TileStache. Заин рассказал об этом в своей демонстрации Trulia, которая использует эту технику на одном из наших старых совещаний SF GeoMeetup . На самом деле, если вы будете в SF на следующей неделе (это моя неудачная попытка подключиться к сети, он затронет это , так что не стесняйтесь появляться :)

Хорошо, теперь к объяснению.

Во-первых, вы смотрите немного не в том месте, когда смотрите на файлы json выше.

Позвольте мне объяснить (так коротко, как я могу), почему.

Плитки передаются так же, как и обычные отрисованные плитки, ничего страшного в этом нет, мы знаем, как это сделать, и поэтому мне не нужно это объяснять.

Если вы проверите его в Firebug, вы увидите, что вы также получите целую кучу изображений, которые кажутся пустыми, как этот .

Почему это пусто? Это не так. Пиксели содержат данные - просто не традиционные данные видимого изображения. Они используют очень умную технику для передачи данных, закодированных в самих пикселях.

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

Возьмите этот пример данных примера xml:

<data>

  <feature>
    <point>
      <x> -32.1231 </x>
      <y> 10.31243 </y>
    </point>
    <type> 
      sold
    </type>
   </feature>

  <feature>
    <point>
      <x> -33.1231 </x>
      <y> 11.31243 </y>
    </point>
    <type> 
      available
    </type>
   </feature>

</data>

Хорошо, сколько укусов, чтобы передать это? При условии, что мы имеем utf8 (1 байт на символ при работе с этим контентом). Ну, у нас есть около 176 символов (без учета табуляции или пробелов), что составляет 176 байтов (это оптимистично по разным причинам, которые я опущу для простоты). Имейте в виду, это за 2 балла!

Тем не менее, какая-то умная задница, которая где-то не понимает, о чем говорит, будет утверждать, что «json дает вам более высокое сжатие».

Хорошо, давайте поместим ту же ерунду xml, что и json:

{ "data": [
            "feature" : { "x" : -32.1231, "y" : 10.31243 , "type": "sold" },
            "feature" : { "x" : -33.1231, "y" :11.31243, "type": "avail" },
          ]
}

Сколько здесь байтов? Скажите ~ 115 символов. Я даже немного обманул и сделал его меньше.

Скажем, моя область покрывает 256x256 пикселей, и я нахожусь на таком высоком уровне масштабирования, что каждая функция отображается как один пиксель, а у меня так много функций, что она заполнена. Сколько данных мне нужно, чтобы показать, что 65 536 функций?

54 символа (или UTF-байтов - и я даже игнорирую некоторые другие вещи) на каждую «функциональную» запись умножается на 65 536 = 3 538 944 или около 3,3 МБ

Я думаю, вы поняли картину.

Но так мы транспортируем данные в сервис-ориентированной архитектуре. Читаемая раздутая чушь.

Что если бы я хотел перенести все в бинарную схему, которую сам придумал? Скажем, вместо этого я закодировал эту информацию в одноканальном изображении (то есть в черно-белом). И я решил, что 0 означает продано, а 1 означает наличие, а 2 означает, что я не знаю. Черт, в 1 байте у меня есть 256 опций, которые я могу использовать - и я использую только 2 или три из них для этого примера.

Какова стоимость хранения этого? 256x256x 1 (только одна полоса). 65 536 байт или 0,06 МБ. И это даже не принимает во внимание другие методы сжатия, которые я получаю бесплатно после нескольких десятилетий исследований в области сжатия изображений.

На этом этапе вы должны спросить себя, почему люди не просто отправляют данные, закодированные в двоичном формате, вместо сериализации в json? Ну, во-первых, оказывается, javascript отнимает много времени для транспортировки двоичных данных , поэтому люди исторически этого не делали.

Некоторые люди использовали удивительную работу вокруг, когда появились новые функции HTML5, в частности, canvas . Так что же это за крутой обходной путь? Оказывается, вы можете отправлять данные по проводам, закодированным на то, что выглядит как изображение, а затем вы можете вставить это изображение в холст HTML5, что позволяет вам напрямую манипулировать пикселями ! Теперь у вас есть способ получить эти данные, декодировать их на стороне клиента и сгенерировать объекты json на клиенте.

Остановись и подумай об этом.

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

Холст HTML даже не нужно использовать для рисования, он используется только как механизм двоичного декодирования!

Вот о чем все эти изображения, которые вы видите в Firebug. Одно изображение с данными, закодированными для каждой загружаемой плитки. Они очень маленькие, но у них есть значимые данные.

Итак, как вы кодируете их на стороне сервера? Что ж, вам нужно обобщить данные на стороне сервера и создать значимую плитку для каждого уровня масштабирования, в котором закодированы данные. В настоящее время для этого вам нужно развернуть свое собственное решение - готового решения с открытым исходным кодом не существует, но у вас есть все инструменты, необходимые для этого. PostGIS выполнит обобщение через GEOS, TileCache можно использовать для кеширования и помочь вам запустить генерацию плиток. На клиентской стороне вам нужно будет использовать HTML5 Canvas для передачи специальных «поддельных плиток», а затем вы можете использовать OpenLayers для создания реальных клиентских JavaScript-объектов, которые представляют векторы с эффектами наведения мыши.

Если вам нужно кодировать больше данных, помните, что вы всегда можете генерировать изображения RGBA на пиксель (что дает вам 4 байта на пиксель или 4 294 967 296 чисел, которые вы можете представить на пиксель ). Я могу придумать несколько способов использовать это :)

Обновление : ответ на вопрос QGIS ниже.

QGIS, как и большинство других настольных ГИС , не имеет фиксированного набора уровней масштабирования. У них есть гибкость масштабирования в любом масштабе и просто рендеринга. Могут ли они отображать данные из источников на основе WMS или тайлов? Конечно, они могут, но в большинстве случаев они действительно глупы: увеличьте масштаб в другой степени, вычислите ограничивающую рамку, вычислите требуемые плитки, возьмите их, покажите их. Большую часть времени они игнорируют другие вещи, такие как кэши заголовков http, которые делают это так, чтобы им не приходилось обновляться. Иногда они реализуют простой механизм кэширования (сохраните плитку, если вы просите ее, проверьте плитку, не просите ее). Но этого недостаточно.

С этой техникой плитки и векторы должны быть повторно получены на каждом уровне масштабирования . Почему? Потому что векторы были обобщены, чтобы приспособить уровни масштабирования.

Что касается всего трюка с размещением плиток на холсте HTML5, чтобы вы могли получить доступ к буферам, то в этом нет необходимости. QGIS позволяет вам писать код на Python и C ++, оба языка имеют отличную поддержку для обработки двоичных буферов, поэтому этот обходной путь действительно не имеет значения для этой платформы.

* ОБНОВЛЕНИЕ 2 **:

Возник вопрос о том, как в первую очередь создать обобщенные векторные плитки (шаг 1, прежде чем можно будет сериализовать результаты в изображения). Возможно, я не уточнил достаточно. Tilestache позволит вам создавать эффективные «векторные плитки» ваших данных на каждом уровне масштабирования (у него даже есть опция, которая позволяет либо обрезать, либо не обрезать данные, когда они пересекают границу плитки). Это позволяет разделить векторы на плитки с различными уровнями масштабирования. Я бы выбрал опцию «не обрезать» (но она выберет произвольную плитку там, где она занимает большую площадь). Затем вы можете подать каждый вектор через опцию GEOS generalize с большим числом, фактически вы хотите, чтобы он был достаточно большим, чтобы полилинии и полигоны сваливались на себя, потому что если они это сделают, вы можете удалить их с уровня масштабирования, поскольку для этого этапа они не имеет значения. Tilestache даже позволяет вам писать простых питонических поставщиков данных, где вы можете использовать эту логику. На этом этапе вы можете использовать их как файлы json (как они делают с некоторыми образцами африканских карт) или как сериализованные геометрии в pngs, как они делают в других образцах (или Trulia), которые я дал выше.


2
До сих пор каждый человек, которого я видел, используя эту технику, не опубликовал код. ИМХО, потому что важная часть действительно происходит на сервере, и для этого нет «стандарта» и потому что выбор значения каждого пикселя (1 = продано, 2 = доступно и т. Д.) Настолько специфичен для вашей текущей карты, что этот код скорее всего не "универсальный".
Раги Язер Бурхум

1
Что касается QGIS, ответ немного сложнее, я буду обновлять свой ответ по дороге на работу. Не волнуйтесь, я сижу на поезде, поэтому не езжу, отвечая на GIS.SE для меня :)
Ragi Yaser Burhum

12
+1 Спасибо, что не
сжимаете

1
Вы можете сделать это с Silverlight или Flash наверняка. Тем не менее, помните, что важная часть происходит на сервере, поэтому Flash или Silverlight не очень- то помогут.
Раги Язер Бурхум

2
Четыре года спустя появилось много вещей, и это текстовое поле содержит всего ~ 500 символов, чтобы объяснить это. Суть в том, что WebGL является зрелым и, помимо методов сериализации, люди применяют дельта-кодирование с фиксированной точностью (как мы привыкли в 60-х годах) в таких форматах, как Topojson. Это хорошая вещь. Я хотел бы видеть некоторые из этих вещей в стандартах OGC ... тем не менее, политика вокруг OGC была очень сложной в последнее время. Вот мои чувства двухлетней давности: blog.burhum.com/post/50036141569/the-ogc-is-stuck-in-1999
Раги Язер Бурхум

23

Непосредственно от разработчика Дино Равника в недавнем сообщении списка рассылки :

Не секрет, как мы это сделали, поэтому я был бы рад поделиться этим с вами .. ключ кроется в двух вещах:

  1. удаление из плитки всех векторов, которые должны быть малы, чтобы быть видимыми, т.е. их площадь при расчете в пиксели составляет менее 1 пикселя. поэтому мы отбрасываем такой вектор и вместо него помещаем пиксель, следовательно, в нашей плитке json есть свойство «пиксели»

  2. векторы, которые будут фактически видны, обобщаются, а затем записываются в плитку с координатами в пикселях

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

Наш движок бэкэнд-карты выполняет всю тяжелую работу, потому что мы не используем предварительное кэширование, и все плитки генерируются на лету. Для нас очень важно иметь карту, которую можно быстро обновить.

Похоже, что клиентская часть - это легкая часть. Впечатляет, что данные отображаются без кеширования.

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


Часть, которая меня смущает, заключается в том, что кажется, что запросы отправляются в postgis, и вместо того, чтобы вернуть стандартный геоджон со значениями lat / long, они, кажется, (в реальном времени) преобразуют значения lat / long в координаты xyz и выплевывают их в зависимости от уровня масштабирования и требуемых листов карты. Как вы думаете, что используется для получения этих скоростей?
NetConstructor.com

@netconstructor Может быть, геометрия уже сохранена в геометрии XYZ, поэтому нет необходимости конвертировать?
география

Относительные координаты XYZ, вероятно, короче, чем относительные широта / долгота, для которых требуется меньшая ширина полосы
Мэтью Снейп,

верно, но они конвертируют эти данные на лету
NetConstructor.com

17

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

На бэкэнде находится настоящий тяжелый груз. Мы не используем TileStache или какой-либо другой движок карт, так как мы написали наш собственный, который может с помощью ряда оптимизаций производить такую ​​векторную графику в режиме реального времени.

Сначала мы начали с доставки листов карты в виде SWF-файлов, а в последнее время мы просто включили вывод в JSON, чтобы мы могли использовать HTML5 Canvas для визуализации графики. Ниже вы можете найти тест, сравнивающий этот вид векторной технологии с растровой технологией (mapnik). Для достоверного сравнения ищите результаты только в режиме CGI.

http://www.giscloud.com/blog/realtime-map-tile-rendering-benchmark-rasters-vs-vectors/

Мы планируем предоставить эту технологию в качестве хостинга картографических плиток. Идея состоит в том, чтобы разместить ваши геоданные в облаке и с помощью HTML5 доставить их в любой клиент карты на высокой скорости, без необходимости предварительно кэшировать плитки. Если вы заинтересованы присоединиться к этой бета-версии, не стесняйтесь связаться с нами здесь: http://www.giscloud.com/contact/


1
Идея использовать листы для векторных данных очень интересна (это выглядит как другая формулировка для «пространственной индексации»). Как вы справляетесь с особенностями, пересекающими несколько плиток? Они вырезаны?
Жюльен

3
да, векторы обрезаны по плитке
Дино Равник

14

Похоже, очень похожий вопрос был недавно задан на форуме OSGeo Open Layers , где разработчики GIS Cloud описывают свой подход, представляющий собой интересное сочетание геометрии GeoJSON и статических пикселей. Они на самом деле генерируют все векторные плитки на лету, а не используют предварительно созданный кэш файлов GeoJSON.

Esri реализовал аналогичный подход, используя ArcGIS Server и Feature Layers , которые могут обобщать геометрии на лету и отправлять их по проводам в формате JSON.

Для прямого метода, который вы можете реально реализовать сейчас, вы можете создавать векторные плитки с помощью Tilestacheподдержкой PostGIS ) и использовать их в Polymaps . Polymaps использует SVG, но производительность довольно хорошая , и CSS-правила управляют стилем элементов карты, поэтому отрисовка объектов полностью зависит от вас. Вот сообщение в блоге, прорабатывающее что-то похожее на то, что вы просите


1
@wwnick - Спасибо за ваш ответ, но похоже, что GisCloud.com использует некоторые дополнительные методы, которые позволяют им иметь такую ​​удивительную вычислительную мощность без необходимости кэшировать элементы, что означает, что все в реальном времени. Я добавил вознаграждение к этому вопросу и надеялся, что вы, возможно, захотите принять участие в предоставлении углубленного решения. Спасибо за ваш ответ до сих пор!
NetConstructor.com

6

Я поиграл с OpenLayers с использованием Canvas и получил разумные результаты.

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

Я использовал простой механизм доставки. Каждая геометрия была функцией JavaScript в ответе HTTP HTTP. не такой продвинутый, как доставка векторов на основе плиток, но простой и открытый исходный код!

Я не смог попробовать Google Maps v3 с Canvas, но видел несколько демонстраций New York Times, которые впечатлили.


Проблема этого подхода заключается в том, что он демонстративно не так быстр, как их решение, когда имеет дело с 500 000 полигонов и,
следовательно,

пожалуйста, обратите внимание на добавленную награду, и если вы можете предоставить подробное решение. Кстати, New York Times, будучи очень крутым, использует вспышку в отличие от решения, которое использует giscloud.com.
NetConstructor.com

Ваша ссылка не в сети
NetConstructor.com

Да, извините за это - мое "хобби" теперь прекратилось после 4 лет работы с полигонами! GISCloud показывает вам, как далеко продвинулись технологии после того, как моя демоверсия переписи появилась несколько лет назад ... Я удалил ссылки на нее в приведенном выше комментарии.
минус34

1
Ну, лучше поздно, чем никогда! Я обновил все, чтобы быть «готовым к использованию», насколько это возможно, и разместил код на стороне клиента на GitHub . Настройка для нового кода была в блоге . Теперь он читает полигоны непосредственно из PostGIS как есть и применяет прореживание на лету через PostGIS RESTful Web Service Framework ( PRWSF ) к клиенту Leaflet Javascript API. Там почти не требуется никакого внутреннего кода!
минус34

6

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

Ключевое решение для улучшения скорости передачи по сети и рендеринга векторных данных заключается в их обобщении в соответствии с уровнем масштабирования. Передача и рендеринг с высоким уровнем масштабирования для тысяч объектов, рассчитанных на значительно более низкий уровень масштабирования, часто занимает очень много времени (а также бесполезно, потому что окончательное отображение обычно не читается - см., например, это изображение ). Чтобы реализовать это, ваша база данных Postgis-сервера должна быть многомасштабной : для каждого уровня масштабирования должно быть одно представление объекта, подходящее для этого уровня масштабирования. Эти различные представления могут быть вычислены автоматически с использованием методов обобщения, Кроме того, векторные данные, отправляемые сервером клиенту, должны зависеть не только от пространственного расширения, но и от уровня масштабирования: сервер отправляет подходящие данные в зависимости от уровня масштабирования. Этот подход защищен в этой превосходной статье :-)


0

Есть интересная статья, демонстрация и исходный код программного обеспечения, разработанного Stanford Visualization Group, которое использует куб данных для каждой плитки для визуализации и изучения большого набора географических данных. Он может использоваться только для набора точечных данных, но может быть интересным способом.

http://vis.stanford.edu/papers/immens

Vizzuality с их платформой CartoDB и библиотекой Torque также как-то экспериментируют с тем, как рисовать большие объемы данных.

http://cartodb.github.io/torque/
https://github.com/CartoDB/torque/tree/new_torque

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.