创建具有GISCloud等渲染性能的矢量多边形?


59

我一直在寻找一种可靠的解决方案,该解决方案使我可以创建网络地图并覆盖矢量多边形,而无需花费太多时间来加载此类数据,目的是使我能够使每个多边形在悬停事件上显示不同的颜色。

据我所知,可以通过3种画布,SVG,Flash来实现这一目标。

如果Flash能在苹果iPhone / iPad上运行,它似乎是最好的解决方案,因为它似乎提供了最快的渲染速度和最干净的显示效果。画布似乎是第二好的选择,但是如果您要在地图上显示数百个多边形,则花费非常长的时间,而SVG需要花费更长的时间来渲染。

几乎找不到希望解决该问题的解决方案的希望,但今天我遇到了一家名为GISCloud http://www.giscloud.com的公司(当前处于Beta版,具有免费注册)。

这家公司使SOMEHOW设法找到了一种惊人的方式来近乎实时地在地图上渲染数百个矢量。我对他们的方法感到惊讶,我向社区提出的问题与我们如何复制他们的方法以与现有技术一起使用,如传单,开放层,蜡...

通过查看此惊人的演示来自己看看:http : //www.giscloud.com/map/284/africa

确保将鼠标悬停在页面上的所有多边形上,并测试缩放控件,以确保这些多边形确实是矢量。

通过查看带有Firebug的请求,我已经注意到,该地图正在请求特定的json文件。似乎根据缩放级别/区域,有多个json文件被请求。


我还要在这里提到,一旦giscloud将数据加载到页面上,将鼠标悬停在矢量上就可以立即更改颜色,而无需创建新请求。

例子:

我假设url结构遵循标准的切片服务逻辑(例如,第3到最后一个文件夹是缩放级别...)。

无论如何,我已经分析了这些json文件的实际数据,并且看来他们使用的逻辑遵循某种逻辑,即它们仅基于这些数据值来创建矢量:

  • 宽度/高度:它们定义每个json请求中提供的数据的宽度和高度
  • 像素:在这里它们定义了像素值,我假设它们与某种广义点级别的一些一般x / y像素坐标有关?我猜他们会以某种方式根据缩放级别自动简化区域。我假设它们使用像素坐标,我猜想它们与经/纬度数据相比正在极大地减少需要加载的数据的大小。
  • 样式:此处定义了两个RGB css值。“ F”代表多边形文件颜色,“ S”代表多边形边界颜色。
  • geom:这是我猜测它们在某种程度上定义的地方,具体定义正在加载的图块中的每个多边形,其中基于地图容器窗口定义此类数据。有趣的是,每个条目都有一个“ S”值,我假设该值用作可选属性或特征链接值,并且在每个条目的末尾都有一个区域,似乎在定义每个矢量ID的同时我猜测的层ID被用来以某种方式加入来自每个被调用的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文件,而是查看其他似乎无关紧要的图像:)请参阅下面的答案。
2011年

“有3种特定选择”……那么,切碎的肝是Silverlight 吗?
Kirk Kuykendall

Silverlight需要其插件才能工作,我认为它实际上没有比giscloud使用的解决方案快,但是我没有做任何直接比较。
NetConstructor.com 2011年

2
这个问题提出了很多有趣的问题,这些问题与通常的问答形式不符。让我们来聊聊他们在Web世界地图用向量来
马特·威尔基

@RagiYaserBurhum还有就是如何使用类似的技术用于旅游等时映射一个很好的解释:mysociety.org/2012/11/08/...
DJQ

Answers:


56

我已经看到了过去使用的这项技术。Zain Memon(来自Trulia)向我解释了这一点,他在Michal Migurski创建TileStache时提供了一些帮助。Zain 在一次较早的SF GeoMeetup会议上解释了使用此技术的Trulia演示时仔细讨论了它。实际上,如果您下周在SF(这是我la脚的尝试,他会尝试解决这个问题,所以请随时露面:)

好的,现在开始解释。

首先,当您查看上面的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给您更高的压缩率”。

好的,让我们将与json相同的xml废话放进去:

{ "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字节-我什至忽略了其他东西)乘以x 65,536 = 3,538,944或大约3.3MB

我想你明白了。

但这就是我们在面向服务的体系结构中传输数据的方式。可读的肿废话。

如果我想以自己发明的二进制方案传输所有内容,该怎么办?说相反,我将该信息编码为单波段图像(即黑白)。我决定0表示已售出,1表示可用,2表示我不知道。哎呀,在1个字节中,我有256个可以使用的选项-在此示例中,我仅使用其中的2个或3个。

那的存储成本是多少?256x256x 1(仅一个频段)。65,536字节或0.06MB。而且这甚至都没有考虑我从几十年的图像压缩研究中免费获得的其他压缩技术。

在这一点上,您应该问自己,为什么人们不只是发送二进制格式编码的数据,而不是序列化为json?好吧,事实证明,javascript在传输二进制数据上花了很多时间,因此这就是人们历史上没有这样做的原因。

HTML5的新功能发布时,特别是canvas,一些人已经使用了很棒的解决方法。那么,这是什么很棒的解决方法?事实证明,您可以通过编码在看起来像图像上的导线来发送数据,然后可以将该图像推送到HTML5 Canvas中,从而可以直接操作像素!现在,您可以获取数据,在客户端将其解码并在客户端中生成json对象。

停下来思考一下。

您可以通过一种高度压缩的格式对大量有意义的地理参考数据进行编码,该方法比Web应用程序中传统上做的其他任何事都要小几个数量级,并可以使用javascript操作它们。

HTML画布甚至不需要用于绘制,它仅用作二进制解码机制!

这就是您在Firebug中看到的所有图像所针对的。一个图像,其中包含为下载的每个单个图块编码的数据。它们非常小,但它们具有有意义的数据。

那么如何在服务器端对它们进行编码?好吧,您确实需要在服务器端对数据进行概括,并为每个已编码数据的缩放级别创建一个有意义的图块。当前,要执行此操作,您必须自己动手-不存在现成的开源解决方案,但您拥有执行此操作所需的所有工具。PostGIS将通过GEOS进行归纳,TileCache可用于缓存并帮助您触发图块的生成。在客户端,您将需要使用HTML5 Canvas传递特殊的“假图块”,然后您可以使用OpenLayers创建代表带有鼠标悬停效果的矢量的真实客户端javascript对象。

如果你需要更多的编码数据,请记住,你总是可以生成每个像素的RGBA图像(它给你每像素4个字节或4,294,967,296号码,你可以代表每像素)。我可以想到几种使用方法:)

更新:回答下面的QGIS问题。

与大多数其他桌面GIS一样,QGIS 没有固定的缩放级别集。它们具有任意缩放比例和仅渲染的灵活性。他们可以显示来自WMS或基于图块的来源的数据吗?当然可以,但是在大多数情况下,它们确实是愚蠢的:以不同的程度缩放,计算边界框,计算所需的平铺,抓取并显示它们。在大多数情况下,它们会忽略其他内容,例如会通过HTTP标头缓存使其不必重新提取的东西。有时,他们实现了一种简单的缓存机制(存储磁贴,如果您要的话,请检查磁贴,而不要使用它)。但这还不够。

使用这种技术时,需要在每个缩放级别重新提取图块和矢量。为什么?因为矢量已被通用化以适应缩放级别。

至于将图块放到HTML5画布上以便您可以访问缓冲区的整个技巧,则不需要整个过程。QGIS允许您使用Python和C ++编写代码,这两种语言都对处理二进制缓冲区提供了出色的支持,因此,这种解决方法对于此平台而言确实无关紧要。

*更新2 **:

首先存在一个关于如何创建通用矢量图块的问题(在能够将结果序列化为图像之前,请先进行第1步)。也许我还不够澄清。Tilestache将允许您在每个缩放级别上为数据创建有效的“矢量图块”(它甚至具有一个选项,允许您在通过图块边界时剪切或不剪切数据)。这需要将向量分成各种缩放级别的图块。我会选择“非剪辑”选项(但是它将选择覆盖更多区域的任意图块)。然后,您可以通过GEOS一般化选项为每个向量提供大量的数字,实际上,您希望其足够大以使折线和多边形折叠到其自身上,因为如果这样做,则可以将它们从缩放级别中移除,因为在该阶段它们是不相关的。Tilestache甚至允许您编写简单的pythonic数据提供程序,您可以在其中放置此逻辑。在那个阶段,您可以选择将它们作为json文件(就像它们对某些非洲地图样本所做的那样)或作为序列化的几何图形服务到png中,就像它们在我上面给出的其他样本(或Trulia样本)中一样。


2
到目前为止,我见过的使用此技术的每个人都尚未发布代码。恕我直言,因为重要的部分实际上是在服务器上发生的,因此没有“标准”,并且因为选择每个像素的含义(1 =已售,2 =可用等)对于您的当前地图而言是如此特定,因此此代码是最有可能不是“通用”。
2011年

1
至于QGIS,答案涉及更多,我将在工作方式上更新我的答案。不要惊慌,我要坐火车,所以在给我回复GIS.SE时不要开车:)
Ragi Yaser Burhum 2011年

12
+1感谢您不要压缩此可读性很强的响应:)
Kirk Kuykendall

1
您可以确定使用Silverlight或Flash进行此操作。但是,请记住,重要的部分是发生的服务器上,以便Flash或Silverlight不会是那个太大的帮助。
2011年

2
四年后,发生了许多事情,这个文本框只有500个字符来解释。总结是WebGL是成熟的,除了序列化技术之外,人们还一直在以Topojson之类的格式应用固定精度的增量编码(就像我们在60年代曾经使用的那样)。这是一个很好的事情。我很乐意以OGC的标准来查看其中的一些内容……但是,最近OGC周围的政治非常复杂。这是我两年前的感受:blog.burhum.com/post/50036141569/the-ogc-is-stuck-in-1999
Ragi Yaser Burhum

23

直接来自开发人员Dino Ravnic的最新邮件列表帖子

我们如何做到这不是一个秘密,所以我很乐意与您分享这一点。关键在于两点:

  1. 从图块中删除所有较小的可见矢量,即,将它们计算为像素时的面积小于1px。所以我们放下这样的向量,而不是放置一个像素,因此我们的json磁贴中有“ pixels”属性

  2. 将对实际可见的向量进行泛化,然后将其坐标以像素为单位写入图块

在客户端,我们在画布上渲染这些静态像素和可见向量。在向量之上,我们实现了鼠标事件处理以实现悬停(即交互)。就是这样。

我们的后端地图引擎可以完成所有繁重的工作,因为我们不使用任何预缓存,并且所有瓦片都是即时生成的。拥有可以快速刷新的地图对我们非常重要。

因此,听起来客户端很容易。令人印象深刻的是,无需任何缓存即可呈现数据。

他还提到了您可能感兴趣的托管服务。您可能要权衡尝试重新创建它的成本与使用现成服务的成本。


让我感到困惑的部分是,似乎请求被发送到了postgis,而不是获得带有经纬度值的标准geojson,它们似乎(实时地)将经纬度值转换为xyz坐标并将其吐出基于所需的缩放级别和地图图块。你们认为用来获得这些速度的是什么?
NetConstructor.com 2011年

@netconstructor也许几何体已经存储在xyz几何体中,所以不需要转换?
geographika,

相对xyz坐标可能比需要较少带宽的相对纬度/经度短。
马修·斯内普

正确,但他们正在即时转换数据
NetConstructor.com 2011年

17

正如我在OSGeo列表中所述,关键是将数据作为矢量JSON切片传递,这些切片具有用于子像素几何的像素和用于那些在特定级别上实际可见的特征的广义几何。性能非常好,因为该技术消除了所有不必要的矢量信息,只保留了那些实际上会对地图产生视觉影响的矢量。像素在那里填补空白并被放置,而不是放置那些子像素向量。关于图块格式就是这样。

在后端方面是真正的繁重工作。我们没有使用TileStache或任何其他地图引擎,因为我们编写了自己的引擎,可以通过许多优化实时生成此类矢量图形。

首先,我们开始将地图图块作为SWF交付,最近我们仅将输出启用为JSON,因此我们可以使用HTML5 Canvas渲染图形。您可以找到一个基准,将这种矢量技术与栅格技术(mapnik)进行比较。为了公平比较,仅在CGI模式下查找结果。

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

我们计划将这项技术作为地图图块托管服务提供。这个想法是将您的地理数据托管在云上,并通过HTML5将其高速传输到任何地图客户端,而无需预先缓存图块。如果您有兴趣加入此Beta,请随时与我们联系:http : //www.giscloud.com/contact/


1
将图块用于矢量数据的想法非常有趣(它看起来像是“空间索引”的另一种说法)。您如何处理跨越多个图块的要素?他们被割了吗?
2011年

3
是的,矢量被剪切在瓷砖上
Dino Ravnic 2011年

14

看起来最近在OSGeo开放层论坛上提出了一个非常类似的问题,由GIS Cloud开发人员描述了他们的方法,这是GeoJSON几何和静态像素的有趣组合。实际上,它们实际上是在运行时生成所有矢量切片,而不是使用GeoJSON文件的预构建缓存。

Esri使用ArcGIS Server和Feature Layers实现了类似的方法,可以动态地绘制几何图形并以JSON的形式通过网络发送。

对于现在可以实际实现的简单方法,您可以使用Tilestache(具有PostGIS支持)构建矢量图块,然后在Polymaps中使用它们。Polymaps使用SVG,但是性能非常好,并且CSS规则可以对地图元素进行样式设置,因此要素渲染完全取决于您。 是一篇博客文章,内容与您所要求的类似。


1
@wwnick-感谢您的回答,但是GisCloud.com似乎正在利用一些其他方法,这些方法使他们具有惊人的处理能力,而不必缓存元素,这意味着一切都是实时的。我为这个问题添加了赏金,希望您可能愿意参与提供深入的解决方案。到目前为止,感谢您的回复!
NetConstructor.com 2011年

6

我使用Canvas与OpenLayers一起玩,并获得了合理的结果。

如其他答案中所述:实时传递和显示矢量-需要针对每个缩放级别和每个数据集将其通用化。另外,您可以使用Google折线编码来大大减小尺寸。

我使用了一种简单的传递机制。每个几何都是JavaScript HTTP响应中的JavaScript函数。不如基于图块的矢量交付先进,而是简单且开源!

我没有尝试通过Canvas尝试使用Google Maps v3,但是看到了一些《纽约时报》的演示 给人留下了深刻的印象。


这种方法的问题在于,在处理500,000个多边形时,它的速度通常不及其解决方案的速度,即性能确实很差
NetConstructor.com 2011年

请注意增加的赏金,如果可以,请提供详细的解决方案。顺便说一句,《纽约时报》非常酷,但是却利用giscloud.com使用的解决方案来利用闪存。
NetConstructor.com 2011年

您的链接处于离线状态
NetConstructor.com 2012年

是的,对此感到抱歉-经过4年的多边形修补后,我的“爱好”已经结束!GISCloud向您展示了自几年前进行人口普查演示以来该技术已经走了多远...在上面的评论中,我已删除了对该技术的引用。
2012年

1
迟到总比不到好!我已将事情更新为尽可能“开箱即用”,并将客户端代码发布在GitHub上。新代码的设置已被热议。现在,它可以直接从PostGIS中直接读取多边形,并通过PostGIS RESTful Web服务框架(PRWSF)即时将细化应用到Leaflet Javascript API客户端。几乎不需要后端编码!
minus34'6

6

我不确切知道该公司使用哪种解决方案(您可以直接问他们),但是我有个主意。

改善矢量数据的网络传输和渲染速度的关键解决方案是根据缩放级别对其进行归纳:在高缩放级别下传输和渲染成千上万个为低缩放级别设计的对象通常非常耗时(而且没有用,因为最终的显示效果通常不清晰-例如,请参见此图片)。为此,您的postgis服务器数据库必须是多尺度的:对于每个缩放级别,应该有一个适合于该缩放级别的对象表示。可以使用归纳技术自动计算这些不同的表示形式。此外,服务器发送给客户端的矢量数据不仅应取决于空间范围,还应取决于缩放级别:服务器根据缩放级别发送合适的数据。这就是这篇优秀论文所捍卫的方法:-)


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.