Qt 求两个多边形组合后的凸包,Qt里的排序方法

来源:互联网 发布:整进度计划软件 编辑:程序博客网 时间:2024/06/14 09:14

unique是很关键的一步,不可省略,一般的题目都给定了不会有重合点,但是实际项目应用里保不准。

可以证明,交点不会出现在凸包上。

这里的排序方法非常好用,不用单独写一个cmp函数了,相当于直接把这个函数写在sort下面



qreal DataConvert::getCrossProduct(const QPointF &iPointA,const QPointF &iPointB,const QPointF &iPointC){//获得a->b和a->c的叉积
    //x1y2-x2y1
    return ((iPointB.x()-iPointA.x())*(iPointC.y()-iPointA.y())-(iPointC.x()-iPointA.x())*(iPointB.y()-iPointA.y()));
}
QPolygonF DataConvert::getPolysConvexHull(const QPolygonF &iFirstPoly, const QPolygonF &iSecondPoly){//获取两个poly的凸包
    if(iFirstPoly.size()==0)return iSecondPoly;
    if(iSecondPoly.size()==0)return iFirstPoly;
    int Size1=iFirstPoly.size();
    int Size2=iSecondPoly.size();
    //第一步把所有结点取出来
    QVector<QPointF>AllPoints;
    for(int i=0;i<Size1;i++){
        AllPoints.push_back(iFirstPoly[i]);
    }
    for(int i=0;i<Size2;i++){
        AllPoints.push_back(iSecondPoly[i]);
    }
    //其实交点可以不加,因为交点一定不属于凸包,凸包一定是两个多边形顶点的子集
//    for(int i=0;i<Size1;i++){
//        QLineF FirstLine=QLineF(iFirstPoly[i],iFirstPoly[(i+1)%Size1]);
//        //AllPoints.push_back(FirstLine.p1());
//        for(int j=0;j<Size2;j++){
//            QLineF SecondLine=QLineF(iSecondPoly[j],iSecondPoly[(j+1)%Size2]);
//            //AllPoints.push_back(SecondLine.p1());
//            QPointF intersectionPoint;
//            int interV=FirstLine.intersect(SecondLine,&intersectionPoint);
//            if(interV==1)AllPoints.push_back(intersectionPoint);
//        }
//    }
    //第二步,寻找基点,此步可以并到第一步里,但是为了代码清晰,便于阅读,多O(n)的复杂度也不太影响
    int startPosition=0;
    for(int i=0;i<AllPoints.size();i++){
        if(AllPoints[startPosition].y()>AllPoints[i].y()||
                (AllPoints[startPosition].y()==AllPoints[i].y()&&AllPoints[startPosition].x()>AllPoints[i].x())){
            startPosition=i;
        }
        //AllPoints.swap()
    }
    if(startPosition>0){
        qSwap(AllPoints[0],AllPoints[startPosition]);
    }
    //第三,给点按照与基点的叉积排序
    qSort(AllPoints.begin()+1,AllPoints.end(),[=](const QPointF &aa,const QPointF &bb){
        qreal crossAns=DataConvert::getCrossProduct(AllPoints[0],aa,bb);
        qreal length1=QLineF(AllPoints[0],aa).length();
        qreal length2=QLineF(AllPoints[0],bb).length();
        return (crossAns>0||(crossAns==0&&length1>length2));
    });
    for(int i=0;i<AllPoints.size();i++){
        qDebug()<<AllPoints[i].x()<<" fuck "<<AllPoints[i].y()<<"\n";
    }
    //第四unique
    QVector<QPointF>uniquePoints;
    for(int i=0;i<AllPoints.size();i++){
        uniquePoints.push_back(AllPoints[i]);
        int j=i;
        while(i<AllPoints.size()){
            if(DataConvert::fuzzyEqual(AllPoints[(i+1)%AllPoints.size()].x(),AllPoints[j].x())&&
                    DataConvert::fuzzyEqual(AllPoints[(i+1)%AllPoints.size()].y(),AllPoints[j].y())){
                i++;
            }
            else break;
        }
    }
    //第五开始算凸包
    int s[1000];
    s[0]=0;
    s[1]=1;
    int top=1;
    for(int i=2;i<uniquePoints.size();i++){
        while(top&&DataConvert::getCrossProduct(uniquePoints[s[top-1]],uniquePoints[s[top]],uniquePoints[i])<0)top--;
        s[++top]=i;
    }
    top++;
    qDebug()<<"top  "<<top<<"\n";
    //把凸包里的点组成新的poly输出
    QPolygonF newpoly;
    for(int i=0;i<top;i++){
        newpoly.push_back(uniquePoints[s[i]]);
    }
    return newpoly;
}


1 0
原创粉丝点击