球体上密度最高的位置

时间:2014-07-09 16:18:50

标签: algorithm math geometry computational-geometry

我在球体表面有很多点。 如何计算具有最大点密度的球体的面积/点? 我需要这么快完成。如果这是一个正方形,例如我想我可以创建一个网格然后让点投票哪个部分的网格是最好的。 我试过将点变换为球面坐标,然后做一个网格,这两个都不能很好地工作,因为北极点附近的球体在球体上很近但在变换后很远。

由于

9 个答案:

答案 0 :(得分:4)

要为混合添加一些其他替代方案:可以通过细化内接多面体在球形几何上定义多个(几乎)规则网格。

第一个选项称为二十面体网格,它是球面的三角剖分。通过连接每个顶点的三角形中心,您还可以基于底层三角剖分创建双六边形网格:

icosahedral grid

另一种选择,如果您不喜欢三角形(和/或六边形),则是通过细分内接立方体的面并将结果投影到球面上而形成的立方体网格:

enter image description here

在任何一种情况下,重要的一点是结果网格几乎常规 - 因此要评估球体上密度最高的区域,您只需执行直方图样式分析,计算每个网格单元的样本数。

正如许多评论者指出的那样,为了解释网格中的轻微不规则性,可以通过除以每个网格单元的面积来标准化直方图计数。然后将得到的密度作为“每单位面积”度量给出。要计算每个网格单元的面积,有两个选项:(i)您可以通过假设边缘是直线来计算每个单元格的“平坦”区域 - 当网格足够时,这种近似可能非常好密集,或(ii)您可以通过评估必要的表面积分来计算“真实”表面积。

如果您有兴趣有效地执行必要的“单元格”查询,一种方法是将网格构造为quadtree - 从粗略的内切多面体开始,并将其面部细化为树子面孔。要找到封闭的单元格,您只需从根遍历树,这通常是O(log(n))操作。

您可以获得有关这些网格类型here的其他信息。

答案 1 :(得分:3)

实际上没有理由将球体划分为常规的非重叠网格,请尝试:

  • 将您的球体划分为半重叠的圆圈

    请参阅此处以生成均匀分布的点(您的圆心)

    Dispersing n points uniformly on a sphere

  • 你可以用一个简单的点积来快速识别每个圆圈中的点数。如果某些点被重复计算真的无关紧要,那么点数最多的圆圈仍代表最高密度

enter image description here

mathematica实施

这需要12秒来分析5000点。 (花了大约10分钟写)

 testcircles = { RandomReal[ {0, 1}, {3}] // Normalize};
 Do[While[ (test = RandomReal[ {-1, 1}, {3}] // Normalize ;
     Select[testcircles , #.test > .9 & , 1] ) == {} ];
        AppendTo[testcircles, test];, {2000}];
 vmax = testcircles[[First@
    Ordering[-Table[ 
        Count[ (testcircles[[i]].#) & /@ points   , x_ /; x > .98 ] ,
              {i, Length[testcircles]}], 1]]];

enter image description here

答案 2 :(得分:2)

Partition the sphere进入等面积区域(以平行线和经线为界),如我的答案所述,并计算每个区域的点数。

区域的纵横比将不均匀(N~M时赤道区域将更“方形”,而极区将更加拉长)。 这是问题,因为区域的直径在NM增加时变为0。 这种方法的计算简单性胜过了包含漂亮图片的其他优秀答案中更好的域均匀性。

一个简单的修改是将两个“极帽”区域添加到链接答案中描述的N*M区域以提高数值稳定性(当点非常靠近极点时,其经度不太好定义)。这样,区域的纵横比是有界的。

答案 3 :(得分:2)

将球体上的点作为3D点处理可能不会那么糟糕。

尝试:

  1. 选择k,对3D中的每个点或选定的兴趣点进行近似k-NN搜索,然后根据它们到查询点的距离对结果进行加权。对于不同的近似k-NN算法,复杂度可能会有所不同。
  2. 构建像k-d Tree这样的空间分区数据结构,然后使用以数据中的每个点或所选兴趣点为中心的球范围进行近似(或精确)范围计数查询。对于具有最新算法的每个近似范围查询,复杂度为O(log(n)+ epsilon ^( - 3))或O(epsilon ^( - 3)* log(n)),其中epsilon是范围误差阈值WRT查询球的大小。对于精确范围查询,每个查询的复杂度为O(n ^(2/3))。

答案 4 :(得分:1)

您可以使用保留区域的Peters projection

这将允许您使用integral image技巧有效地计算网格中的点,但也可以在滑动窗口(Parzen窗口框)中计算。

答案 5 :(得分:0)

这实际上只是我的this答案的反面

将等距球面顶点的方程反演为表面单元索引。甚至不要尝试将细胞可视化为不同的圆圈,否则你会发疯。但如果有人真的这样做,那么请在这里发布结果(现在让我)

现在只需创建2D单元格地图并在O(N)中进行密度计算(就像完成直方图一样),类似于Darren Engwirda在答案中提出的那样

这就是 C ++

中代码的样子
//---------------------------------------------------------------------------
const int na=16;                                // sphere slices
      int nb[na];                           // cells per slice
const int na2=na<<1;
      int map[na][na2];                     // surface cells
const double da=M_PI/double(na-1);          // latitude angle step
      double db[na];                        // longitude angle step per slice
// sherical -> orthonormal
void abr2xyz(double &x,double &y,double &z,double a,double b,double R)
    {
    double r;
    r=R*cos(a);
    z=R*sin(a);

    y=r*sin(b);
    x=r*cos(b);
    }
// sherical -> surface cell
void ab2ij(int &i,int &j,double a,double b)
    {
    i=double(((a+(0.5*M_PI))/da)+0.5);
    if (i>=na) i=na-1;
    if (i<  0) i=0;
    j=double(( b            /db[i])+0.5);
    while (j<     0) j+=nb[i];
    while (j>=nb[i]) j-=nb[i];
    }
// sherical <- surface cell
void ij2ab(double &a,double &b,int i,int j)
    {
    if (i>=na) i=na-1;
    if (i<  0) i=0;
    a=-(0.5*M_PI)+(double(i)*da);
    b=             double(j)*db[i];
    }
// init variables and clear map
void ij_init()
    {
    int i,j;
    double a;
    for (a=-0.5*M_PI,i=0;i<na;i++,a+=da)
        {
        nb[i]=ceil(2.0*M_PI*cos(a)/da);     // compute actual circle cell count
        if (nb[i]<=0) nb[i]=1;
        db[i]=2.0*M_PI/double(nb[i]);       // longitude angle step
        if ((i==0)||(i==na-1)) { nb[i]=1; db[i]=1.0; }
        for (j=0;j<na2;j++) map[i][j]=0;    // clear cell map
        }
    }
//---------------------------------------------------------------------------
// this just draws circle from point x0,y0,z0 with normal nx,ny,nz and radius r
// need some vector stuff of mine so i did not copy the body here (it is not important)
void glCircle3D(double x0,double y0,double z0,double nx,double ny,double nz,double r,bool _fill);
//---------------------------------------------------------------------------
void analyse()
    {
    // n is number of points and r is just visual radius of sphere for rendering
    int i,j,ii,jj,n=1000;
    double x,y,z,a,b,c,cm=1.0/10.0,r=1.0;
    // init
    ij_init();      // init variables and map[][]
    RandSeed=10;    // just to have the same random points generated every frame (do not need to store them)
    // generate draw and process some random surface points
    for (i=0;i<n;i++)
        {
        a=M_PI*(Random()-0.5);
        b=M_PI* Random()*2.0 ;
        ab2ij(ii,jj,a,b);       // cell corrds
        abr2xyz(x,y,z,a,b,r);   // 3D orthonormal coords
        map[ii][jj]++; // update cell density
        // this just draw the point (x,y,z) as line in OpenGL so you can ignore this
        double w=1.1;   // w-1.0 is rendered line size factor
        glBegin(GL_LINES);
        glColor3f(1.0,1.0,1.0); glVertex3d(x,y,z);
        glColor3f(0.0,0.0,0.0); glVertex3d(w*x,w*y,w*z);
        glEnd();
        }

    // draw cell grid (color is function of density)
    for (i=0;i<na;i++)
     for (j=0;j<nb[i];j++)
        {
        ij2ab(a,b,i,j); abr2xyz(x,y,z,a,b,r);
        c=map[i][j]; c=0.1+(c*cm); if (c>1.0) c=1.0;
        glColor3f(0.2,0.2,0.2); glCircle3D(x,y,z,x,y,z,0.45*da,0); // outline
        glColor3f(0.1,0.1,c  ); glCircle3D(x,y,z,x,y,z,0.45*da,1); // filled by bluish color the more dense the cell the more bright it is
        }
    }
//---------------------------------------------------------------------------

结果如下:

surface density

所以现在只需查看map[][]数组中的内容,您就可以找到密度的全局/局部最小值/最大值或者您需要的任何内容...只是不要忘记大小为map[na][nb[i]] i是数组中的第一个索引。网格大小由na常数控制,cm只是密度到色标......

[edit1] 获得了四线网格,更准确地表示了已使用的映射

surface density

这是na=16最糟糕的舍入误差在极点上。如果您想要精确,那么您可以通过细胞表面大小来加权密度。对于所有非极性电池,它是简单的四极杆。对于杆子,它的三角扇(正多边形)

这是网格绘制代码:

// draw cell quad grid (color is function of density)
int i,j,ii,jj;
double x,y,z,a,b,c,cm=1.0/10.0,mm=0.49,r=1.0;
double dx=mm*da,dy;
for (i=1;i<na-1;i++)    // ignore poles
 for (j=0;j<nb[i];j++)
    {
    dy=mm*db[i];
    ij2ab(a,b,i,j);
    c=map[i][j]; c=0.1+(c*cm); if (c>1.0) c=1.0;
    glColor3f(0.2,0.2,0.2);
    glBegin(GL_LINE_LOOP);
    abr2xyz(x,y,z,a-dx,b-dy,r); glVertex3d(x,y,z);
    abr2xyz(x,y,z,a-dx,b+dy,r); glVertex3d(x,y,z);
    abr2xyz(x,y,z,a+dx,b+dy,r); glVertex3d(x,y,z);
    abr2xyz(x,y,z,a+dx,b-dy,r); glVertex3d(x,y,z);
    glEnd();
    glColor3f(0.1,0.1,c  );
    glBegin(GL_QUADS);
    abr2xyz(x,y,z,a-dx,b-dy,r); glVertex3d(x,y,z);
    abr2xyz(x,y,z,a-dx,b+dy,r); glVertex3d(x,y,z);
    abr2xyz(x,y,z,a+dx,b+dy,r); glVertex3d(x,y,z);
    abr2xyz(x,y,z,a+dx,b-dy,r); glVertex3d(x,y,z);
    glEnd();
    }
i=0; j=0; ii=i+1; dy=mm*db[ii];
ij2ab(a,b,i,j); c=map[i][j]; c=0.1+(c*cm); if (c>1.0) c=1.0;
glColor3f(0.2,0.2,0.2);
glBegin(GL_LINE_LOOP);
for (j=0;j<nb[ii];j++) { ij2ab(a,b,ii,j); abr2xyz(x,y,z,a-dx,b-dy,r); glVertex3d(x,y,z); }
glEnd();
glColor3f(0.1,0.1,c  );
glBegin(GL_TRIANGLE_FAN);                 abr2xyz(x,y,z,a   ,b   ,r); glVertex3d(x,y,z);
for (j=0;j<nb[ii];j++) { ij2ab(a,b,ii,j); abr2xyz(x,y,z,a-dx,b-dy,r); glVertex3d(x,y,z); }
glEnd();
i=na-1; j=0; ii=i-1; dy=mm*db[ii];
ij2ab(a,b,i,j); c=map[i][j]; c=0.1+(c*cm); if (c>1.0) c=1.0;
glColor3f(0.2,0.2,0.2);
glBegin(GL_LINE_LOOP);
for (j=0;j<nb[ii];j++) { ij2ab(a,b,ii,j); abr2xyz(x,y,z,a-dx,b+dy,r); glVertex3d(x,y,z); }
glEnd();
glColor3f(0.1,0.1,c  );
glBegin(GL_TRIANGLE_FAN);                 abr2xyz(x,y,z,a   ,b   ,r); glVertex3d(x,y,z);
for (j=0;j<nb[ii];j++) { ij2ab(a,b,ii,j); abr2xyz(x,y,z,a-dx,b+dy,r); glVertex3d(x,y,z); }
glEnd();

mm是网格单元格大小mm=0.5是单元格大小,较少在单元格之间创建空格

答案 6 :(得分:0)

如果我理解正确,你试图在球体上找到密集点。

如果点数在某些时候更密集

  • 考虑笛卡尔坐标并找出点的平均值X,Y,Z

  • 找到最接近球体的X,Y,Z的平均值(您可以考虑使用球面坐标,只需将半径延伸到原始半径)。

<强>约束

  • 如果平均X,Y,Z与中心之间的距离小于r / 2,则该算法可能无法正常工作。

答案 7 :(得分:0)

我不是数学硕士,但也许可以通过分析方式解决:

1.短坐标

2.R =(Σ(n = 0.n = max)(Σ(m = 0.M = n)(1 / A ^ diff_in_consecative))* angle)/Σangle

A =可以是任何常数

答案 8 :(得分:-1)

考虑使用地理方法来解决这个问题。 GIS工具,SQL中的地理数据类型等都处理椭球体的曲率。如果你实际上没有在地球上建模某些东西,你可能必须找到一个使用纯球而不是地球状球体的坐标系。

对于速度,如果你有大量的点并且想要它们最密集的位置,那么栅格热图类型解决方案可能会运行良好。您可以创建低分辨率栅格,然后缩放到高密度区域,并创建更高分辨率的细胞,只关注您关注的细胞。