欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

28、几何算法-线段相交、凸包、球面弧长

程序员文章站 2022-06-03 21:07:21
...

1、判断线段是否相交
(1)标准方法:如果两直线不平行先求直线交点,再看这个交点是否分别在两个线段上。

28、几何算法-线段相交、凸包、球面弧长

(2)标准方法方法涉及到除法,计算机中一般方法:先判断以两个线段作为对角线的矩形是否相交,如果矩形相交再判断以一个线段为轴,另一个线段的两个端点是否分别位于顺时针和逆时针方向。
28、几何算法-线段相交、凸包、球面弧长

28、几何算法-线段相交、凸包、球面弧长

int lint(Point p1, Point p2, Point p3, Point p4)
{
    double z1, z2, z3, z4;
    int s1, s2, s3, s4;

    if(!( (MAX(p1.x, p2.x) >= MIN(p3.x, p4.x)) && (MAX(p3.x, p4.x) >= MIN(p1.x, p2.x))
        && (MAX(p1.y, p2.y) >= MIN(p3.y, p4.y))&& (MAX(p3.y, p4.y) >= MIN(p1.y, p2.y)) ))
        {
            return -1;
        }
    if( ( z1 = ((p3.x - p1.x)*(p2.y - p1.y)) - ((p3.y - p1.y)*(p2.x - p1.x)) ) < 0 )
        s1 = -1;
    else if(z1 > 0)
        s1 = 1;
    else
        s1 = 0;

    if( ( z2 = ((p4.x - p1.x)*(p2.y - p1.y)) - ((p4.y - p1.y)*(p2.x - p1.x)) ) < 0 )
        s2 = -1;
    else if(z1 > 0)
        s2 = 1;
    else
        s2 = 0;

    if( ( z3 = ((p1.x - p3.x)*(p4.y - p3.y)) - ((p1.y - p3.y)*(p4.x - p3.x)) ) < 0 )
        s3 = -1;
    else if(z1 > 0)
        s3 = 1;
    else
        s3 = 0;

    if( ( z4 = ((p2.x - p3.x)*(p4.y - p3.y)) - ((p2.y - p3.y)*(p4.x - p3.x)) ) < 0 )
        s4 = -1;
    else if(z1 > 0)
        s4 = 1;
    else
        s4 = 0;

    if((s1 * s2 <= 0) && (s3 * s4 <= 0))
        return 1;
    return -1; 
}

2、凸包
凸包:一个多边形内任意两点之间的连线都在多边形内部,即所有角都向外凸或平。
28、几何算法-线段相交、凸包、球面弧长

Jarvis’s March法:(1)选取y轴最低处点,为P0。(2)选取Pc,其他所有点和P0构成的直线顺时针到P0和Pc构成的直线。如下图z<0,则任何点Pi相比Pc符合这个条件。(3)如果z=0,则选离P0更远的点。(4)循环以Pc为P0,再次找Pc。
28、几何算法-线段相交、凸包、球面弧长

//P为原来所有节点构成的链表, polygon为最终所有外围点 
int cvxhull(const LIST_ATTRITIVE *P, LIST_ATTRITIVE *polygon)
{
    LIST_ELEMENT *element;
    Point *min, *low, *p0, *pi, *pc;
    double z, length1, length2;
    int count;//计数外围点的个数

    //找最低最左边的点为P0 
    min = list_data(list_head(p));
    for(element = list_head(p); element != NULL; element = list_next(element))
    {
        p0 = list_data(element);

        if(p0->y < min->y)
        {
            min = p0;
            low = list_data(element);
        }
        else
        {
            if( p0->y == min->y && p0->x < min->x)
            {
                    min = p0;
                    low = list_data(element);
            }
        }
    } 
    list_init(polygon, NULL);

    //先执行后判断,一直循环到再次找到P0这个点 
    p0 = low;
    do
    {
        list_ins_next(polygon, list_tail(polygon), p0);
        count = 0

        //找下一个点pc 
        for(element = list_head(p); element != NULL; element = list_next(element))
        {
            if((pi = list_data(element)) == p0)
                continue;
            count++;

            //每次大循环while,暂时把第二个点作为pc
            if(count == 1)
            {
                pc = list_data(element);
                continue;
            }

            if( ( z = ((pi.x - p0.x)*(pc.y - p0.y)) - ((pi.y - p0.y)*(pc.x - p0.x)) ) > 0 )
                pc = pi;

            //z==0时选取远的点
            else if(z == 0)
            {
                length1 = sqrt(pow(pi->x - p0->x, 2.0) + pow(pi->y - p0->y, 2.0));
                length2 = sqrt(pow(pc->x - p0->x, 2.0) + pow(pc->y - p0->y, 2.0));
                if(length1 > length2)
                    pc = pi
            } 
        } 

        p0 = pc;
    }while(p0 != low);

    return 0; 
}

3、球面弧长
28、几何算法-线段相交、凸包、球面弧长

28、几何算法-线段相交、凸包、球面弧长

void arclen(SPoint p1, SPoint p2, double *length)
{
    Point p1_rtc, p2_rtc;
    double alpha, dot;

    p1_rtc.x = p1.rho * sin(p1.phi) * cos(p1.theta);
    p1_rtc.y = p1.rho * sin(p1.phi) * sin(p1.theta);
    p1_rtc.z = p1.rho * cos(p1.phi);

    p2_rtc.x = p2.rho * sin(p2.phi) * cos(p2.theta);
    p2_rtc.y = p2.rho * sin(p2.phi) * sin(p2.theta);
    p2_rtc.z = p2.rho * cos(p2.phi);

    dot = (p1_rtc.x * p2_rtc.x) + (p1_rtc.y * p2_rtc.y) + (p1_rtc.z * p2_rtc.z);
    alpha = acos(dot / pow(p1.rho, 2.0));

    *length = alpha * p1.rho;
    return;
} 

4、球面弧长的应用-地球上两点的近视距离
28、几何算法-线段相交、凸包、球面弧长
地球半径约为3440065海里,北纬,西经为正。纬度(-90到+90需要转换成0到180,对应φ),经度(-180到+180需要转换成0到360,对应θ)