在实际应用中,经常会遇到大批数据需要读取的情况,如何重新组织数据是一个必须面对和解决的首要问题。举个例子,我在一个项目中就遇到过这种问题,我把解决的办法写出来。
因项目需要,我要对一个2G多的激光文件进行重新整理,这些文件除了文件头,存储的就是点云数据,每个点是由3个浮点数表示,即在局部坐标系中的坐标 (x,y,z),我的任务就是将这些数据整理,要方便按任意平面坐标(x,y)或平面区域读取符合要求的数据,还希望能够像Google地球那样可以缩放显示。
说实话,拿到那个文件和文件头结构,我第一个想法就是想撞墙,回过神之后,我开始读文件头的结构,这个倒是很简单,保存了文件标志,激光扫描的时间,本次扫描持续的时间,有效距离,扫描的最小角度,扫描数据的精度等等。然后我开始读那些数据发现数据描述的是一个大约500m*500m区域的地形数据,而且不是均匀分布,跟高度起伏有一定关联。
我的第一个想法就是将这些数据按某一维排序,这样想要查找某一个点就可以采用二分法进行查找。比如按照 x 进行排序,那么要查找某一点,我就先按 x 进行二分查找,再对 y 进行二分查找,这样找到某一点最多需要不到20次文件读取和比较。但问题是要读取区域内的所有数据即使可以按行读取,也是很麻烦的,而且要缩放显示就更难了。
在否定了最好想的办法后,我突然想到这些数据在读区域数据时比较麻烦,那我就把这些区域数据存在一起,一次就可以全部读出来了。一个自然而然的想法就是划分网格,以网格为单位组织数据,但是为了实现任意查询,我决定把网格设为0.5m*0.5m大小,这样我在读取读和显示数据时就以这样的网格为最小单位进行读取,应该能满足需要,在显示略缩图时,我只读取网格的部分数据就可以了。但是麻烦还是存在,那就是网格数量很多,达到了1000*1000个,依然是很恐怖的数量,因此还需要再划分一个层次出来,我以1000个为一组,这样层次就比较清晰了。
在具体实现过程中,首先进行第一遍循环,按照点的平面坐标给每个点分配一个整数型的网格标号。具体的方法是先计算 网格的2维标号:
       Xindex = ( x – Xmin ) / Xstep , Yindex = ( y – Ymin ) / Ystep  
那么分配的网格标号就是
           Index = Xindex * Ycount + Yindex (其中 Ycount = ( Ymax – Ymin )/Ystep)
(例子中,Xmin = Ymin = 0,Xmax = Ymax = 500,Ystep = 0.5)
然后将这些网格按照标号顺序保存。
最后制作索引并放在文件的开头部分,索引其实是表示某一网格在整理好的文件中的位置,这样在读取网格数据时就可以根据索引直接定位到目标位置。由于所有点的数据自身的大小是相同的,因而很容易的可以得到网格内数据的个数,从而获得数据的分布状态,不需要另外存储。