zoukankan      html  css  js  c++  java
  • ClickHouse 像素聚合

    背景

    海量点的可视化是业界的一大难题,本文采用像素聚合方式尝试聚合千万到上亿的点数据减少为前端可以接受的点数,然后进行渲染

    思路

    采用微软的地图计算公式,计算出每级每个点的像素聚合值实现聚合,这样粗粒度聚合结果大概在几十万左右,再通过js库细粒度聚合

    具体实现

    必应C#版经纬度转像素代码

     public static void LatLongToPixelXY(double latitude, double longitude, int levelOfDetail, out int pixelX, out int pixelY)  
            {  
                latitude = Clip(latitude, MinLatitude, MaxLatitude);  
                longitude = Clip(longitude, MinLongitude, MaxLongitude);  
      
                double x = (longitude + 180) / 360;   
                double sinLatitude = Math.Sin(latitude * Math.PI / 180);  
                double y = 0.5 - Math.Log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI);  
      
                uint mapSize = MapSize(levelOfDetail);  
                pixelX = (int) Clip(x * mapSize + 0.5, 0, mapSize - 1);  
                pixelY = (int) Clip(y * mapSize + 0.5, 0, mapSize - 1);  
            }  
    

    建表存入所需数据

    CREATE TABLE pntsXY(`id` UInt32,      `Lon` Float64,    `Lat` Float64, `X` Float64,`Y` Float64) ENGINE = MergeTree() order by (id,Lon,Lat) 
    

    导入跟层级无关的中间表数据,减少查询的计算量

    insert into pntsXY select id,Lon,Lat,(arrayMin([arrayMax([Lon,-180]),180]) + 180) / 360 x,(0.5 - log((1 + sin(arrayMin([arrayMax([Lat,-85.05112878]),85.05112878])* pi() / 180) ) / (1 - sin(arrayMin([arrayMax([Lat,-85.05112878]),85.05112878])* pi() / 180) )) / (4 *  pi())) y from pntsh3
    

    计算像素聚合

    select floor(arrayMin([arrayMax([Y* pow(2,8+3) + 0.5,0]),pow(2,8+3) - 1]),0)  y,
    floor(arrayMin([arrayMax([X* pow(2,8+3) + 0.5,0]),pow(2,8+3) - 1]),0)   x from pntsXY  group by x,y
    

    像素转为经纬度

    js版像素转经纬度代码

    function Clip(n, minValue, maxValue)
    {
        return Math.min(Math.max(n, minValue), maxValue);
    }
    
    function MapSize(levelOfDetail)
    {
     	if (levelOfDetail == 23)
     		return 2147483648;
        return 256 << levelOfDetail;
    }
    
    function PixelXYToLatLong(x,y,zoom){
         let mapSize = MapSize(zoom);  
         let newx = (Clip(x, 0, mapSize - 1) / mapSize) - 0.5;  
         let newy = 0.5 - (Clip(y, 0, mapSize - 1) / mapSize);  
         let latitude = 90 - 360 * Math.atan(Math.exp(-newy  * 2 * Math.PI)) / Math.PI;  
         let longitude = 360 * newx; 
         return [longitude,latitude]
    }
    

    supercluster.js聚合结果数据

      let index=new Supercluster({ maxZoom: zoom,minZoom:zoom, radius: radius})
      index.getClusters([-180, -90, 180,90 ], zoom)
    

    实现效果

    前端地图库为maptalks,后端使用express

    数据为一亿点
    一亿点!
    数据为五千万点
    五千万点
    数据为一千万点
    一千万点

    参考资料

    https://github.com/stumpyfr/quadkey/blob/master/lib/quadkey.js

    https://docs.microsoft.com/en-us/bingmaps/articles/bing-maps-tile-system?redirectedfrom=MSDN

  • 相关阅读:
    Codeforces Round #249 (Div. 2) D. Special Grid 枚举
    图论二
    C语言中的atan和atan2(转)
    BestCoder Round #79 (div.2)
    数学
    LCA
    二分图
    动态规划
    线段树
    树状数组
  • 原文地址:https://www.cnblogs.com/polong/p/14354976.html
Copyright © 2011-2022 走看看