无法理解HDU 2823的解决方案

时间:2016-07-30 17:56:55

标签: c++ computational-geometry raycasting convex-hull

以下代码段取自here。这是此问题的解决方案HDU 2823

#define eps 1e-9
double rc(point pp[],point qq[],int n,int m)    
{    
    int q=0;    
    int p=0;    
    for(int i=0;i<n;i++)     
        if(pp[i].y-pp[p].y<-eps)    
            p=i;    
    for(int i=0;i<m;i++)    
        if(qq[i].y-qq[q].y>eps)    
            q=i;    
    pp[n]=pp[0];    
    qq[m]=qq[0];    
    double tmp,ans=1e99;    
    for(int i=0;i<n;i++)    
    {    
        while((tmp=cross(pp[p+1],qq[q+1],pp[p])-cross(pp[p+1],qq[q],pp[p]))>eps)    
            q=(q+1)%m;    
        if(tmp<-eps)    
            ans=min(ans,dist_p_to_seg(qq[q],pp[p],pp[p+1]));    
        else    
            ans=min(ans,dist_seg_to_seg(pp[p],pp[p+1],qq[q],qq[q+1]));    
        p=(p+1)%n;    
    }    
    return ans;    

}    

pp[]qq[]是两个不同的凸包。 ppp凸包的最高点,qqq凸包的最低点。

我似乎无法理解这一行:

while((tmp=cross(pp[p+1],qq[q+1],pp[p])-cross(pp[p+1],qq[q],pp[p]))>eps) 
    q=(q+1)%m;

他想要达到什么目标?

1 个答案:

答案 0 :(得分:1)

函数cross(a,b,c)是找到以下矩阵的行列式,

| a.x a.y 1 |
| b.x b.x 1 |  = 2 * A
| c.x c.y 1 | 

其中A是三角形a,b,c的签名区域。 行列式的符号也告诉我们3个点是顺时针方向还是顺时针方向。 see here for an explanation

让我们像这样重写,

triA ← cross(pp[p+1],qq[q+1],pp[p])
triB ← cross(pp[p+1],qq[q],pp[p])

// This is equivalent to,
// just to make it a bit clearer
triA ← cross(pp[p], pp[p+1],    qq[q+1])
triB ← cross(pp[p], pp[p+1],    qq[q])

因此它检查由{em} 的一侧形成的三角形qq上的最低点是否小于同一侧形成的三角形和qq的下一个最高点

如果是,请选择qq中的下一个点为q并继续。 -i.e.选择q,以使q<p, p+1>的垂直距离最小化。

enter image description here

对于给定的一方<p, p+1>,在本地最小化后,对pp的所有边重复此操作。在每个步骤中保持当前边之间的最小距离。

这是一种找到两个凸包之间最小间距的 shaky 方式。直觉是正确的 - 正确的是它理解它很简单(这个想法,不是有问题的代码),对于凸多边形来说非常普遍,并且非常有用的各种问题(参见参考资料)下面);但是,我觉得这可以用更有效和易于理解的方式编写。

本文充分说明了这些想法背后的直觉 "Solving Geometric Problems with the Rotating Calipers" - Toussaint G。