matlab怎么栅格化地图,用栅格化的思维进行地图散点数据绘制
原理上,这个课题利用point做粒子效果就可以解决,本不需要通过shader去处理。不过作为用gl的思维进行地图栅格数据绘制课题的后续,还是提出以下。本方案的核心思路还是数据栅格化,降纬处理数据减少碰撞测试次数提升性能。
Demo:http://lrdcq.com/test/mapwebgltiles/scatter/
思路
对于地图上的散点数据,我们还是将他们落到格子里:
1. 将地图区域划为MxN个格子,每个格子里会有0-x个点的经纬度数据,如果划分得相对合理,我们的x将极小(demo里总数据量约7w+,x为6)。
2. 假设我的栅格的大小为(x,y),如果我的每个点的绘制区域的大小也正好是(m,n)=(x,y),如下图
那我每一个栅格里点的绘制区域都有可能覆盖到3x3共计9个栅格的像素。同理,对于任意(m,n)的绘制区域,我们需要检查(ceil(m/x) * 2 + 1, ceil(n/y) * 2 + 1)的区域的像素。那对应的,对于我们的shader处理每一个像素时,我们需要检测周围这么大的区域的栅格里是否有数据。
3. 对每个像素处理,对拿到的可能覆盖范围内的所有数据点做矩形(即绘制区域)碰撞测试,如果到当前像素在某个数据点的绘制范围内,则取对应图片进行绘制。
相对于纯栅格绘制,这个散点的栅格绘制方案的成本包括多检索(ceil(m/x) * 2 + 1, ceil(n/y) * 2 + 1)的区域,并且每个区域需要做做多0-x次碰撞测试。以demo的数据来说,性能消耗最多是3x3x6攻击54倍——当然对于shader来说,这个也不算什么的样子。
Code
这里有一个思路转换。原本方案的数据图像(即一个像素表示一个栅格的图片),每个像素里根本没存储啥东西,所以像素数据非常无所谓。但是现在这个方案,我们需要在数据图像中储存这个像素,就是这个栅格里包含了多少个点,还有每一个点的经纬度。
1. 储存经纬度,一个像素0xFFFFFFFF储存经纬度可以储存到小数点后7位了。而如果用rgb,不用a的六位0xFFFFFF来储存经纬度,可以储存到小数点后5位。5位的进度已经是米级的了,所以五位就够了。所以我们可以用两个像素0xAABBCCFF,0xAABBCCFF来足够准确的表述以个数据点的经纬度还可以储存256*256的其他信息。完全够了。
2. 因为我们的数据图像的像素要表示栅格,因此我们开了第二个图片,数据图像2,来储存所有的经纬度点数据。只需要两个两个一组把所有数据按即有顺序罗列在图片里面就行了。
生成数据图像2的数据写入片段是:
var writeToInfo = function(zx, zy, imageData, point,count) {
var offset = 512 * zy + zx * 2;
let x = Math.floor(point.x * 100000);
let y = Math.floor(point.y * 100000);
imageData.data[4 * offset] = Math.floor(x / (256 * 256)) % 256;
imageData.data[4 * offset + 1] = Math.floor(x / (256)) % 256;
imageData.data[4 * offset + 2] = Math.floor(x) % 256;
imageData.data[4 * offset + 3] = 255;
imageData.data[4 * offset + 4] = Math.floor(y / (256 * 256)) % 256;
imageData.data[4 * offset + 5] = Math.floor(y / (256)) % 256;
imageData.data[4 * offset + 6] = Math.floor(y) % 256;
imageData.data[4 * offset + 7] = 255;
}
3. 那我们原本的数据图像储存什么呢。就用来储存像素的数量,可以具体的数据在数据图像2的offset好了,我们用0xFFFFFF的rgb来储存offset,这可是16777216的数据量,就是说原理上能指向共计1677w以上数量的点,肯定够用的。a的0xFF来储存这个格子的数据数量,也就是说最多可以储存256个数据。
生产数据图像的写入片段:
var writeToData = function(answer, imageData, zx, zy, num) {
answer.y = 1200 - answer.y;
var offset = answer.x + answer.y * 800;
imageData.data[4 * offset] = zx;
imageData.data[4 * offset + 1] = Math.floor(zy / 256) % 256;
imageData.data[4 * offset + 2] = zy % 256;
imageData.data[4 * offset + 3] = num ? 255 - num : 0;
}
那么,我们在shader里按照之前的流程,先解析出当前的经纬度,和当前在哪个栅格中,这里,我们需要解析3x3共计9个栅格了。
同时,对每个栅格的所有数据进行for循环处理:
//读取数据图像
vec4 data[9];
vec2 uv = vec2(answer.x / L_mapWidth, 1.0 - answer.y / L_mapHeight);
vec2 px = vec2(1.0, 1.0) / vec2(L_mapWidth, L_mapHeight);
//3x3的数据范围
data[0] = texture2D(dataImage, uv + vec2(-px.x, px.y));
data[1] = texture2D(dataImage, uv + vec2(0.0, px.y));
data[2] = texture2D(dataImage, uv + vec2(px.x, px.y));
data[3] = texture2D(dataImage, uv + vec2(-px.x, 0.0));
data[4] = texture2D(dataImage, uv);
data[5] = texture2D(dataImage, uv + vec2(px.x, 0.0));
data[6] = texture2D(dataImage, uv + vec2(-px.x, -px.y));
data[7] = texture2D(dataImage, uv + vec2(0.0, -px.y));
data[8] = texture2D(dataImage, uv + vec2(px.x, -px.y));
for (int i = 0 ; i < 9 ; i++) {
vec4 d = data[i];
//count从a中读取
float count = d.a > 0.0 ? floor(256.0 - floor(d.a * 256.0)) : 0.0;
//数据图像2offset从rgb中读取
vec2 pixel = vec2(floor(d.r * 256.0), floor(d.g * 256.0 * 256.0 + d.b * 256.0));
//如果存在数据
if (count > 0.0) {
//按count循环处理
//由于glsl语言循环不能有动态变量因此这里的写法直接将循环展开,并且预设最多count为8个
if (count <= 1.0) {
renderPos(pixel, now);
} else if (count <= 2.0) {
renderPos(pixel, now);
renderPos(pixel + vec2(1.0, 0.0), now);
} else if (count <= 3.0) {
renderPos(pixel, now);
renderPos(pixel + vec2(1.0, 0.0), now);
renderPos(pixel + vec2(2.0, 0.0), now);
} else if (count <= 4.0) {
renderPos(pixel, now);
renderPos(pixel + vec2(1.0, 0.0), now);
renderPos(pixel + vec2(2.0, 0.0), now);
renderPos(pixel + vec2(3.0, 0.0), now);
} else if (count <= 5.0) {
renderPos(pixel, now);
renderPos(pixel + vec2(1.0, 0.0), now);
renderPos(pixel + vec2(2.0, 0.0), now);
renderPos(pixel + vec2(3.0, 0.0), now);
renderPos(pixel + vec2(4.0, 0.0), now);
} else if (count <= 6.0) {
renderPos(pixel, now);
renderPos(pixel + vec2(1.0, 0.0), now);
renderPos(pixel + vec2(2.0, 0.0), now);
renderPos(pixel + vec2(3.0, 0.0), now);
renderPos(pixel + vec2(4.0, 0.0), now);
renderPos(pixel + vec2(5.0, 0.0), now);
} else if (count <= 7.0) {
renderPos(pixel, now);
renderPos(pixel + vec2(1.0, 0.0), now);
renderPos(pixel + vec2(2.0, 0.0), now);
renderPos(pixel + vec2(3.0, 0.0), now);
renderPos(pixel + vec2(4.0, 0.0), now);
renderPos(pixel + vec2(5.0, 0.0), now);
renderPos(pixel + vec2(6.0, 0.0), now);
} else {
renderPos(pixel, now);
renderPos(pixel + vec2(1.0, 0.0), now);
renderPos(pixel + vec2(2.0, 0.0), now);
renderPos(pixel + vec2(3.0, 0.0), now);
renderPos(pixel + vec2(4.0, 0.0), now);
renderPos(pixel + vec2(5.0, 0.0), now);
renderPos(pixel + vec2(6.0, 0.0), now);
renderPos(pixel + vec2(7.0, 0.0), now);
}
}
}
对于每个数据点,和当前渲染像素的对比,由于是矩形格子,直接解析数据并且比较就可以了:
//判断一个点的数据是否在mark经纬度上并且执行渲染
void renderPos(vec2 pixel, vec2 now) {
//xy连续两个数据像素
vec4 data_x = texture2D(data2Image, vec2((pixel.x * 2.0) / L_dataSize, pixel.y / L_dataSize));
vec4 data_y = texture2D(data2Image, vec2((pixel.x * 2.0 + 1.0) / L_dataSize, pixel.y / L_dataSize));
//像素转换为经纬度
vec2 data = vec2(256.0 * 256.0 * floor(256.0 * data_x.r) + 256.0 * floor(256.0 * data_x.g) + floor(data_x.b * 256.0), 256.0 * 256.0 * floor(256.0 * data_y.r) + 256.0 * floor(256.0 * data_y.g) + floor(data_y.b * 256.0));
vec2 d = vec2(data.x / 100000.0, data.y / 100000.0);
//当前像素是否在贴近的数据像素范围内
vec2 dis = now - d;
if (abs(dis.x) < L_tileWidth / 2.0 && abs(dis.y) < L_tileHeigth / 2.0) {
//如果在的话,转换数据icon的uv并且渲染icon
vec2 uv = vec2((dis.x + L_tileWidth / 2.0) / (L_tileWidth / 1.0), 1.0 - (dis.y + L_tileHeigth / 2.0) / (L_tileHeigth / 1.0));
gl_FragColor = texture2D(iconImage, uv);
}
}
以上两段shader,基本上就是数据图像生成的js的逆向逻辑。不过glsl的语法和数据类型很奇怪,需要处理和兼容的边界情况相当多,当前这个demo也没有完全处理。
其他
这个方案虽然是走通了,不过这也只是也行的方案的一种。除了经常说的粒子场的形式处理,可能的方案和优化还包括:
1. 数据图像2其实没必要通过图片传进去,可能通过长数据分段传进去更科学,只是如果是js写的话,二进制数据拆包为js的number再传进gl,会有无所谓的性能消耗。如果上webassembly的话,说不定就好很多了。
2. 虽然shader里没有并行buffer,但是如果能把数据图像1的处理结果作为中间数据buffer起来,那么整体可以在保证基本并行的情况下,少计算很大一层,只是多一次离屏渲染而已。
3. 如果从任意数据中划分出均匀合理的栅格,这个看起来大有学问。如果这个做不到的话,这个方案就没有意义,并且说不定还有多余的性能损耗。
matlab怎么栅格化地图,用栅格化的思维进行地图散点数据绘制相关推荐
- matlab 三维点 边界曲面,不用matlab如何从散点数据绘制极坐标三维曲面图?
[ 在 OSN10 (老洪) 的大作中提到: ] : 标 题: Re: 不用matlab如何从散点数据绘制极坐标三维曲面图? : 发信站: 水木社区 (Sat Dec 15 20:47:17 201 ...
- ai为什么要栅格化_AI 效果-栅格化的具体用途是什么
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 栅格化是将矢量图形转换为位图图像的过程.在栅格化过程中, Illustrator 会将图形路径转换为像素.您所设置的栅格化选项 将决定结果像素的大小及特征 ...
- matlab读取八叉树,基于八叉树表示的三维栅格地图路径规划系统及方法技术方案...
[技术实现步骤摘要] 基于八叉树表示的三维栅格地图路径规划系统及方法 本专利技术涉及地图路径规划技术,具体涉及基于八叉树表示的三维栅格地图路径规划系统及方法. 技术介绍 随着各项性能的提高,服务机器人 ...
- python画交互式地图_使用Python构建交互式地图-入门指南
python画交互式地图 Welcome to The Beginner's Guide to Building Interactive Maps in Python 欢迎使用Python构建交互式地 ...
- 高德地图广告投放产品介绍!高德地图广告开户找哪里?
高德地图是有2002年成立的公司,于14年在阿里巴巴的全资收购,电子地图上是通过不同的图层描述的,然后通过图层的叠加显示来进行表达的过程,每个图层的元素都是相对固定化的,在底图的基础上叠加需要的图层来 ...
- 【“零起点”--百度地图手机SDK】如何添加地图图层+按钮事件+水平垂直布局?...
摘要:我们在这一章将学习到如何通过按钮事件来控制地图图层(交通流量图,卫星图)的显示,以及如何对android应用进行水平和垂直布局. -------------------------------- ...
- android 内嵌地图,Android Fragment里嵌入高德地图【原创】
最近在做的项目里要用到地图,看了一下高德地图的API,最后决定就用高德地图,和平时不同,这次地图是要嵌在Fragment了,研究了一下网上的代码,最后实现了.下面说一下实现2D地图的方法. 1.先去高 ...
- ios 一步一步学会自定义地图吹出框(CalloutView)--(百度地图,高德地图,google地图)
前言 在ios上边使用地图库的同学肯定遇到过这样的问题:吹出框只能设置title和subtitle和左右的view,不管是百度地图还是高德地图还是自带的google地图,只提供了这四个属性,如果想添加 ...
- android 百度地图 在线建议查询,Android 百度地图 SDK v3_3_0 (五) ---POI搜索和在线建议查询功能...
目前百度地图SDK所集成的检索服务包括:POI检索.公交信息查询.线路规划.地理编码.在线建议查询.短串分享. 本篇博客将先介绍POI检索和在线建议查询(在地图地位功能基础上实现的,还不知道定位的童靴 ...
- [android] 百度地图开发 (一).申请AK显示地图及解决显示空白网格问题
最近做android百度地图,但是使用baidumapapi_v2_3_1.jar和libBaiduMapSDK_v2_3_1.so显示百度地图时总是遇到问题--只显示网格而没有显示地图,网络 ...
最新文章
- [值得学习]售前工程师的成长---一个老员工的经验之谈(一)
- 运用BeautifulSoup抓取网页的链接
- Java面试常被问到的题目+解答
- Exchange2003-2010迁移系列之六,配置及配置第二台Exchange CAS/HUB服务器
- docker 错误 request canceled while waiting for connection 或 TLS handshake timeout 解决方案
- 解决Access denied for user #39;#39;@#39;localhost#39; to database #39;mysql#39;问题
- Linux系统中文件^M乱码解决
- 《C++ Primer》14.3节练习
- 玩转oracle 11g(47):oracle删除非空表空间
- 使用webpack配置react并添加到flask应用
- 有必要考国二mysql_计算机二级必须要考吗
- vue获取input的属性_vuejs 中如何优雅的获取 Input 值
- 苹果公司的企业文化_百度、苹果、脉脉等互联网大厂的企业文化衫还能这么潮?...
- python经典实例-Python机器学习经典实例
- 2019杭州云栖大会探营:神龙的秘密
- 全网搜php,FM全网自动采集聚合影视搜索ThinkPHP源码
- 【微信小程序】实现手机全屏滚动字幕
- Junos CLI常用命令
- 信息搜集之CDN知识
- 【方法论】时间管理矩阵(Time Management Matrix )-给事情排序,列好1234再执行吧!