如何在2D点范围内确定有用的中心

问题描述

如何在创建四叉树节点的点范围内找到中心并高效地进行?

class point {
    constructor(x,y) {
        this.x = x;
        this.y = y;
    }
}
//range = [] of points,(they get sorted into quarters in the tree node)

范围代表点的阵列,代表板。

以下是相关代码

class quadtreeNode {
    constructor(range,parent,depth) {
        const centerPoint = findCenter(range);
        this.center = centerPoint; 
        this.parent = parent;
        if (range.length <= 1) {
            this.leaf = true;
            this.value = this.center;
        } else {
            this.TL = new quadtreeNode(
                range.filter(x => x.x < this.center.x && x.y < this.center.y),this,depth + 1
            );
            this.TR = new quadtreeNode(
                range.filter(x => x.x > this.center.x && x.y < this.center.y),depth + 1
            );
            this.BL = new quadtreeNode(
                range.filter(x => x.x < this.center.x && x.y > this.center.y),depth+1
            );
            this.BR = new quadtreeNode(
                range.filter(x => x.x > this.center.x && x.y > this.center.y),depth + 1
            );
        }
    }
}

并且:

findCenter(array){
    let centerPoint = null;
    if (array.length <= 1) {
       centerPoint = array[0];
    } else {
        let minX = array.sort((x,y) => x.x < y.x)[0];
        let minY = array.sort((x,y) => x.y < y.y)[0];
        let maxX = array.sort((x,y) => x.x > y.x)[0];
        let maxY = array.sort((x,y) => x.y > y.y)[0];
        const targetX = maxX-minX;
        const targetY = maxY-minY;
        const target = array.find(x => x.x == targetX && x.y == targetY);
        if (!target) {
            return array[(Math.floor(array.length / 2))];
        } else {
            centerPoint = target;
        }
    }
    return centerPoint;  
}

对于如何找到中心,我是否每次都需要找到确切的中心,或者是否有四叉树的估计,或者范围应为可被...整除的特定长度,我有些困惑。 4?

解决方法

这取决于您要优化的内容。大多数情况下,您需要最小化四叉树的深度。因此,理想情况下,您希望选择一个节点,以使其跟随的四个子范围中的每个子范围都具有大约四分之一的点,即相等的分布。如果您要在每个节点上实现该目标,那么当 n 是总数时,树的深度将接近log 4 n 的节点数。

但是,并非总是可以选择这样的中心节点。想象一下范围内的点分布:

                                         *
                                  *

                                 *

                                *

                             *

                   *
         *
*

无论选择哪个点,都将始终产生四个子范围,其中两个是空的,因此在4个子范围内均匀分布的“梦境”是不可行的。

您将要选择中心点,以使获得最大点数的象限最小。计算起来可能会很昂贵,但是以下是一种很好的启发式方法:

  • 针对每个点,通过x坐标(sx)收集其排序顺序,并通过y坐标(sy)收集其排序顺序。通过执行两个排序操作,您可以轻松地实现这一点
  • 考虑到最佳中心的(sx,sy)=(n / 2,n / 2),应选择(sx,sy)到(n / 2,n / 2)的点)最小化。

因此建议的代码为:

findCenter(array) {
    const mid = array.length >> 1;
    if (!mid) {
        return array[0];
    }
    return array.sort((p,q) => p.x - q.x) // NB: sort callback should return signed number
                .map((p,sx) => [p,sx]))
                .sort(([p],[q]) => p.y - q.y)
                .map(([p,sx],sy) => [(sx - mid) ** 2 + (sy - mid) ** 2,p])
                .sort(([a],[b]) => a - b)[0][1];
}