计算几何 点到线段的距离 点在简单多边形内 点到凸多边形的距离

部分内容参考 http://blog.csdn.net/angelazy/article/details/38489293


1.点到线段的距离 

矢量算法

矢量算法过程清晰,如果具有一定的空间几何基础,则是解决此类问题时应优先考虑的方法。当需要计算的数据量很大时,这种方式优势明显。

由于矢量具有方向性,故一些方向的判断直接根据其正负号就可以得知,使得其中的一些问题得以很简单的解决。

用此方法考虑,我们只需要找到向量 方向上的投影,具体如下:

                    计算几何 点到线段的距离 点在简单多边形内 点到凸多边形的距离_第1张图片

上面的 方向上的单位向量,其意义是给所求向量确定方向。是的两个向量的内积,且   ,其中θ为向量APAB之间的夹角。是向量长度。

 

那么即为上图中线段AC的长度值,不带有方向性。此数值与上述表征方向的 整体构成有大小、有方向的新向量,即为 方向上的投影向量,C为投影点。

根据得到的,由向量的方向性可知:如果情况是上图(a)所示,那么0<1;如果是如图(b)所示的情况,那么r ≥1;如果是如图(c)所示的情况,那么得到r ≤0;

特殊情况如点在线段上、点在端点、点在线段延长线上等等的情况全部适用于此公式,只是作为特殊情况出现,无需另作讨论。这也是矢量算法思想的优势所在。

故根据r值的不同,最短距离

代码如下 :

double PointTOline( point_t const&a,point_t const&b,point_t const&p){
    double ap_ab = (b.x - a.x)*(p.x - a.x)+(b.y - a.y)*(p.y - a.y);//cross( a , p , b );
    if ( ap_ab <= 0 )
        return sqrt( (p.x-a.x)*(p.x-a.x) + (p.y-a.y)*(p.y-a.y) );

    double d2 = ( b.x - a.x ) * ( b.x - a.x ) + ( b.y-a.y ) * ( b.y-a.y ) ;
    if ( ap_ab >= d2 ) return sqrt( (p.x - b.x )*( p.x - b.x ) + ( p.y - b.y )*( p.y - b.y ) ) ;

    double r = ap_ab / d2;
    double px = a.x + ( b.x - a.x ) *r;
    double py = a.y + ( b.y - a.y ) *r;
    return sqrt( (p.x - px)*(p.x - px) + (p.y - py)*(p.y - py) );
}

2. 点在简单多边形内,

(1) 如果多边形是凸多边形,可用叉积法,先graham逆时针排序,然后旋转一周,判断方向是否一致

计算几何 点到线段的距离 点在简单多边形内 点到凸多边形的距离_第2张图片

如图,点在凸包内,方向一定一致的。


(2)凹包要用射线法判断;

给定点A与简单多边形P[N],判断A是否在P上
从A向右做射线,如果射线与P的边有奇数个交点,A在P上,否则A在P外

剔除几种特殊情况
•水平边不判断
•点在边上直接给结论
•点与边的交点恰好是端点,则只计数y值大的那个端点
代码如下
/*
 *  点与简单多边形相交,使用射线法,剔除三种特殊情况后,判断交点的奇偶
 *  从0开始标号
 ×  注意n <= 2 的时候
 */
struct point_t{
    int x,y;
};
bool isOnline( point_t const&a,point_t const&b, point_t const&po ){
    return po.x >= min( a.x , b.x ) &&
           po.x <= max( a.x , b.x ) &&
           po.y >= min( a.y , b.y ) &&
           po.y <= max( a.y , b.y ) &&
           ( po.x - a.x ) * ( b.y - a.y ) == ( po.y - a.y ) * ( b.x - a.x );
}
bool isInSimple( point_t * p ,int n , point_t const&po ){

    p[n] = p[0];
    bool flag = 0;
    int tmp;
    for ( int i = 0; i < n;++i ){
        if ( isOnline( p[i] , p[i+1] , po ) ) return true;
        if ( p[i].y == p[i+1].y ) continue;
        p[i].y < p[i+1].y ? tmp = i+1 : tmp = i ;
        if ( po.y == p[tmp].y && po.x < p[tmp].x ) flag ^= 1;
        p[i].y > p[i+1].y ? tmp = i+1 : tmp = i ;
        if ( po.y == p[tmp].y && po.x < p[tmp].x ) continue ;

        if ( po.x < max( p[i].x , p[i+1].x ) &&
             po.y > min( p[i].y , p[i+1].y ) &&
             po.y < max( p[i].y , p[i+1].y ) ) flag ^= 1;
    }
    return flag;
}

3.点与凸多边形的距离
先判断是否在多边形内,在求出到每条边的距离
代码如下
#include 
using namespace std;

struct point_t {
    double x,y;
};
double cross(point_t const &O,point_t const &A,point_t const &B){
	double xOA = A.x - O.x;
	double yOA = A.y - O.y;
	double xOB = B.x - O.x;
	double yOB = B.y - O.y;
	return xOA * yOB - xOB * yOA;
}
double PointTOline( point_t const&a,point_t const&b,point_t const&p){
    double ap_ab = (b.x - a.x)*(p.x - a.x)+(b.y - a.y)*(p.y - a.y);//cross( a , p , b );
    if ( ap_ab <= 0 )
        return sqrt( (p.x-a.x)*(p.x-a.x) + (p.y-a.y)*(p.y-a.y) );

    double d2 = ( b.x - a.x ) * ( b.x - a.x ) + ( b.y-a.y ) * ( b.y-a.y ) ;
    if ( ap_ab >= d2 ) return sqrt( (p.x - b.x )*( p.x - b.x ) + ( p.y - b.y )*( p.y - b.y ) ) ;

    double r = ap_ab / d2;
    double px = a.x + ( b.x - a.x ) *r;
    double py = a.y + ( b.y - a.y ) *r;
    return sqrt( (p.x - px)*(p.x - px) + (p.y - py)*(p.y - py) );
}

bool isOnline( point_t const&a,point_t const&b, point_t const&po ){
    return po.x >= min( a.x , b.x ) &&
           po.x <= max( a.x , b.x ) &&
           po.y >= min( a.y , b.y ) &&
           po.y <= max( a.y , b.y ) &&
           ( po.x - a.x ) * ( b.y - a.y ) == ( po.y - a.y ) * ( b.x - a.x );
}
bool isInSimple( point_t * p ,int n , point_t const&po ){
    p[n] = p[0];
    bool flag = 0;
    int tmp;
    for ( int i = 0; i < n;++i ){
        if ( isOnline( p[i] , p[i+1] , po ) ) return true;
        if ( p[i].y == p[i+1].y ) continue;
        p[i].y < p[i+1].y ? tmp = i+1 : tmp = i ;
        if ( po.y == p[tmp].y && po.x < p[tmp].x ) flag ^= 1;
        p[i].y > p[i+1].y ? tmp = i+1 : tmp = i ;
        if ( po.y == p[tmp].y && po.x < p[tmp].x ) continue ;

        if ( po.x < max( p[i].x , p[i+1].x ) &&
             po.y > min( p[i].y , p[i+1].y ) &&
             po.y < max( p[i].y , p[i+1].y ) ) flag ^= 1;
    }
    return flag;
}

point_t p[120];
int main(){
    int n;
    while(cin>>n && n){
        point_t po;    
        cin>>po.x>>po.y;
        for (int i = 0;i < n;++i)
            cin>>p[i].x>>p[i].y;

        if ( isInSimple( p , n , po ) ) {
            cout <<"0.00"<





你可能感兴趣的:(ACM,算法模板)