Práctica de la función de agregación de puntos de interés del mapa

introducir

Al implementar funciones comerciales relacionadas con mapas, a menudo nos enfrentamos a la necesidad de mostrar diferentes formas de datos de puntos de interés de puntos de interés del mapa en diferentes niveles de magnitud, centrándonos en valores estadísticos regionales en un gran alcance geográfico y centrándonos en un alcance geográfico pequeño Los detalles y las operaciones de los puntos de interés, por lo que es inevitable utilizar la función de agregación del mapa de puntos de interés. A continuación, analicemos cómo se agrega el PDI del mapa plano bidimensional.

Plan de IMPLEMENTACION

La función de agregación implementada en este documento utiliza el algoritmo de centroide de cuadrícula como estrategia de agregación de puntos, y el árbol cuádruple se utiliza para la búsqueda rápida. Los pasos de implementación son los siguientes: 1. Divida el área de visualización actual del mapa en varias cuadrículas, cada cuadrícula es un rectángulo del mismo tamaño;Imagen.png

2. Atraviese todas las cuadrículas y haga lo siguiente para cada cuadrícula: encuentre todos los PDI en cada cuadrícula, calcule el centroide (x, y) de los puntos de PDI, donde x es el valor promedio del eje x de todos los PDI, y Para el promedio del eje y de todos los puntos de interés, utilice el punto centroide como punto de agregación para reemplazar el punto de interés original;Imagen [2].png

Imagen [3].png

3. Renderice estos puntos de agregación y ajuste la apariencia de acuerdo con la cantidad de PDI agregados;

Imagen [4].png

4. Si la vista del mapa cambia (acercar, mover, cambiar el tamaño), repita el paso 1.

Imagen [5].png

La dificultad de este esquema es cómo encontrar rápidamente todos los puntos de interés dentro de cada rango de cuadrícula. Por supuesto, podemos utilizar el método más mecánico, es decir, recorrer cada punto para determinar si se encuentra dentro de un determinado rango de cuadrícula que se ha delimitado, pero el tiempo de ejecución de este método aumentará exponencialmente con el aumento del número de cuadrículas. y puntos de interés, no es adecuado para manejar puntos de interés masivos. Por lo tanto, es necesario construir un quadtree para proporcionar una capacidad de búsqueda rápida.

Construir quadtree

A menudo usamos árboles binarios para encontrar y almacenar datos unidimensionales. Para el mapa POI (con coordenadas xy), es una matriz bidimensional, que se puede almacenar y buscar mediante un quadtree.

Características de los nodos quadtree:

  1. Los atributos que debe contener cada nodo del árbol son los siguientes:
constructor(data, conf) {
    // 每个节点所指定的地址范围 xmin ymin xmax ymax
    this.extent =  new Extent(conf.extent)
    // 节点数据容量,超过该容量则会分裂成4个子节点
    this.bucketLimit = conf.bucketLimit || 10
    // 当前节点的深度,根节点深度为0
    this.deep = conf.deep || 0
    //存储的POI
    this.points = data
  }
复制代码
  1. Cada nodo se puede dividir en nodos secundarios 4. La extensión de estos cuatro nodos secundarios es los cuadrantes geográficos 4 del nodo principal, a saber, noroeste (noroeste) noreste (noreste) suroeste (suroeste) sureste (sureste)

  2. Si la cantidad de puntos de PDI contenidos en el rango de nodos actual excede el límite de capacidad del cubo y la profundidad del nodo no excede la profundidad máxima, los nodos secundarios se dividirán.

4. Todos los puntos de PDI finalmente se colocarán en nodos hoja

Imagen [6].png

La imagen muestra el quadtree construido en base a los datos existentes. En la imagen se puede ver que cuanto más frecuentemente se dividen los nodos, más denso es el PDI.

Encuentra puntos de interés dentro de una cuadrícula

构造好了四叉树,就可以用它来查找单个网格Grid内的POI点,这是一个对四叉树递归遍历的过程,操作如下:

  1. 从根节点开始,判断当前节点extent是否与网格Grid几何相交,如果相交,则进入步骤2

  2. 当前节点有POI点(只有叶子节点有POI点),则遍历这些POI点,将处于Grid范围内的POI点存入数组Arr;否则进入步骤3

  3. 如果当前节点有子节点(如果有的话必定是4个子节点),则按步骤1处理这些子节点

最终我们会得到一个Grid范围内所有POI点的数组Arr。每个网格范围内的POI点到手了,直接求取它们xy轴的平均值,就能得到这个网格质心聚合点的坐标,接下来就是在地图上的渲染工作。

Cámara de miel 2022-04-11 16-29-40.gif

代码层实现四叉树

我依据代码复用情况建了两个类

1.四叉树QuadTreeNode,提供树的构建和查找功能 findPoints(extent)
2.矩形范围Extent,这里的范围即有四叉树的地理范围,也有网格的地理范围,用于计算点和面,面和面之间的几何关系

QuadTreeNode

  /**
   * 查找指定范围内的坐标点
   * @param extent 指定范围
   * @returns {Array}
   */
  findPoints(extent) {

    if (!(extent instanceof Extent)) {
      extent = new Extent(extent)
    }

    let arr = []

    function travel(node) {

      if (node.isIntersects(extent)) {

        //如果当前四叉树节点有points,则将在extent范围内的points入栈
        if (node.points.length > 0) {
          node.points.forEach(point => {
            if (extent.within(point)) {
              arr.push(point)
            }
          })

        } else {
          const {northWest, northEast, southWest, southEast} = node

          if (northWest && northWest.isIntersects(extent)) {
            travel(northWest)
          }
          if (northEast && northEast.isIntersects(extent)) {
            travel(northEast)
          }
          if (southWest && southWest.isIntersects(extent)) {
            travel(southWest)
          }
          if (southEast && southEast.isIntersects(extent)) {
            travel(southEast)
          }
        }
      }
    }

    travel(this)

    return arr
  }
  
}
复制代码

Extent

class  Extent{
  constructor(conf = {xmin: 0, ymin: 0, xmax: 100, ymax: 100}){

    this.xmin = conf.xmin
    this.ymin = conf.ymin
    this.xmax = conf.xmax
    this.ymax = conf.ymax
  }
  /**
   * 判断当前范围是否与指定范围相交
   * 如果两个矩形相交,则两个矩形中心点间的距离肯定小于两个矩形边长和的1/2
   * @param extent 指定范围
   * @returns {boolean}
   */
  intersects(extent) {

    const {xmin, ymin, xmax, ymax} = extent

    //x轴 两个矩形中心点距离 * 2
    let lx = Math.abs(this.xmax + this.xmin - xmin - xmax)
    //x轴 两个矩形边长和
    let bx = Math.abs(this.xmax - this.xmin + xmax - xmin)
    //y轴 两个矩形中心点距离 * 2
    let ly = Math.abs(this.ymax + this.ymin - ymin - ymax)
    //y轴 两个矩形x轴边长和
    let by = Math.abs(this.ymax - this.ymin + ymax - ymin)

    if (lx <= bx && ly <= by) {
      return true
    } else {
      return false
    }
  }
}
复制代码

聚合功能的应用

1.解决重叠坐标点的选择问题 这是我非常想解决的问题,在实际项目中遇到的真实数据其实没有那么理想,很多情况下有部分POI数据因为地址不够详细或者定位api出错会导致坐标点一模一样,从而导致一堆点叠加在某个位置,鼠标操作只能取到最上方点的属性。既然实现了点聚合功能,那么可以配置缩小聚合的阈值,提取到所有叠加点的属性。

2.为热力图层的渲染提供基础数据 热力图其实可以看做点聚合的另一种展示方式,它所需要的源数据与点聚合非常类似(x坐标,y坐标,点的权值)。有了源数据,只要将做表单做一次地理坐标和平面坐标的转换,权值归一化,再渲染出热力图也是很简单的事。

3.海量数据的统计展示 还是文章开头提到的需求,大比例尺我要看POI的聚合数量,小比例尺我要看单个POI的属性明细。

优点和缺陷

  1. 四叉树其实是个空间换时间的做法,和质心合并算法(求平均值)结合带来的有点就是计算速度快
  2. Hay un cierto error en el algoritmo de cuadrícula. Si hay un montón de puntos cortados en la línea límite de las dos cuadrículas, el algoritmo cortará el montón de puntos en dos puntos agregados, pero esto no es gran cosa.

Ejemplo de artículo

Página de demostración de agregación de puntos de interés del mapa

Código fuente de GitHub

Artículo de referencia

"Exploración y práctica de algoritmos de agregación de puntos de interés de mapas" Las soluciones de algoritmos mencionadas en este artículo son más detalladas y vívidas, adecuadas para una investigación más profunda

Supongo que te gusta

Origin juejin.im/post/7085274646949396487
Recomendado
Clasificación