从N个定向平面构造(凸)多边形网格

时间:2018-08-01 06:28:40

标签: algorithm computational-geometry mesh convex-hull

我从一组点中发现了许多关于Covex Hull的构造的材料,这基本上是通过定向平面的交点(分别为half-spaces)来界定这些点的任务。

现在我对某种逆任务感兴趣-给定N个半空间,找到定义由半空间的交点创建的凸多面体表面的多边形网格(即顶点和连通性图)。

  • 我正在尝试搜索它,但不知道可以用哪个名称找到
  • 我对O(N ^ 3)时间复杂度的天真的算法有一个粗略的想法。但是我想应该有更好的东西。

采用O(N ^ 3)算法的天真的算法:

verts = {}
edges = {}
for i < N: 
  for j < i: # find intersection lines
   edge_ij = intersection(planes[i],planes[j])
   for k < i: # trim them by other planes
     edge_ij = trim(edge_ij,plane[k])
   # store all edges of non-zero lenght
   if(edge_ij.length > 0.0):
     edges.insert(edge_ij)
   # store endpoints, if not known yet
   i1 = verts.find( edge_ij.endPoint1 )
   if i1:
     edge_ij.endPoint1 = verts[i1]
   else:
     verts.insert(edge_ij.endPoint1)
   i2 = verts.find( edge_ij.endPoint2 )
   if i2:
     edge_ij.endPoint2 = verts[i2]
   else:
     verts.insert(edge_ij.endPoint2)

编辑:好的,这是我在C ++()中对上述算法的实现

class LineInterval3d{ public:
    Vec3d  p0,hdir;
    double t0,t1;

    inline bool fromPlanes( Vec3d& dir1, double c1, Vec3d& dir2, double c2 ){
        double s = dir1.dot(dir2);
        if( s*s>0.999 ) return false;
        double s2=s*s;
        double denom = 1/(1-s2);
        p0.set_lincomb(  (c1-c2*s)*denom, dir1, (c2-c1*s)*denom,  dir2 );
        hdir.set_cross( dir1, dir2 );
        hdir.mul( sqrt(denom) );
        infiniteSpan();
        return true;
    };

    inline int trim( Vec3d& dir, double c ){
        double s = dir.dot(hdir);
        double d = c - dir.dot(p0);
        if( s*s<0.0001 ){
            //printf( "perpendiculer \n" );
            if( d > 0 ){ double t=t0; t0=t1; t1=t; }; // always outside
            return 0;
        }
        double t = d/s;
        if( s>0 ){ if(t>t0){t0=t; return -1; }; }
        else     { if(t<t1){t1=t; return  1; }; }
        //printf( "no-trim \n" );
        return 0;
        //return t1<t0;
    };

    inline Vec3d infiniteSpan(){ t0 = -1e+300; t1 =  1e+300; }
    inline Vec3d endPoint0(){ return p0+hdir*t0; };
    inline Vec3d endPoint1(){ return p0+hdir*t1; };

};



// order-agnostic hash for triple of inexes i,j,k
inline uint32_t   pack32 (             uint8_t  x, uint8_t  y, uint8_t  z, uint8_t  w ){ return x|(((uint32_t)y)<<8)|(((uint32_t)z)<<16)|(((uint32_t)w)<<24);};
inline uint32_t vertIdjk( uint8_t i, uint8_t j, uint8_t k ){
    uint8_t t;
    if(i>k){t=i; i=k; k=t; }
    if(i>j){t=i; i=j; j=t; }
    if(j>k){t=j; j=k; k=t; }
    return pack32(i,j,k,0);
}

void fromPlanes(int n, Plane3D* planes ){
    std::unordered_map<uint32_t,int> verts;
    std::vector<int> faceEdges[n];
    int nv =0;
    for(int i=0; i<n; i++){
        // find all edges by itersection of two planes
        for(int j=i+1; j<n; j++){
            LineInterval3d lij;
            if( !lij.fromPlanes( planes[i].normal, planes[i].iso, planes[j].normal, planes[j].iso ) ){
                //printf("colinear intersection %i,%i \n", i,j  );
                continue;
            }
            MeshEdge eij;
            decltype(verts.find(0)) it;
            uint32_t iv0,iv1;
            eij.verts.a = -1; // DEBUG
            eij.verts.b = -1; // DEBUG
            // trim the edge by other planes
            for( int k=0; k<n; k++ ){
                if( (k==i)||(k==j) ){ continue; }
                int side = lij.trim( planes[k].normal, planes[k].iso );
                if( lij.t0>lij.t1 ){
                    //printf( "   line Vanish (%i,%i,%i) \n", i,j,k );
                    goto lineVanish;
                };
                if     ( side>0 ){ eij.verts.b = k; }
                else if( side<0 ){ eij.verts.a = k; }
            }
            if( (eij.verts.a<0) or (eij.verts.b<0) ){
                //printf( "end not trimmed %i %i \n", eij.verts.a, eij.verts.b );
                continue; // DEBUG
            }
            // try insert endpoint 1
            eij.faces.a = i;
            eij.faces.b = j;
            iv0 = vertIdjk( i, j, eij.verts.a );
            it = verts.find(iv0);
            if(  it == verts.end() ){
                verts.insert({iv0,nv});
                eij.verts.a = nv;
                points.push_back( lij.endPoint0() );
                nv++;
            }else{
                eij.verts.a = it->second;
            }
            // try insert endpoint 2
            iv1 = vertIdjk( i, j, eij.verts.b );
            it = verts.find(iv1);
            if(  it == verts.end() ){
                verts.insert({iv1,nv});
                eij.verts.b = nv;
                points.push_back( lij.endPoint1() );
                nv++;
            }else{
                eij.verts.b = it->second;
            }
            faceEdges[i].push_back( edges.size() );
            faceEdges[j].push_back( edges.size() );
            edges.push_back( eij );
        lineVanish:
            ;
        }

        // order edges to make a polygon
        if( faceEdges[i].size()>0 ){
            //printf( " face: %i nedges %i \n", i, faceEdges[i].size() );
            Polygon * pl = new Polygon();
            //int ieo   = -1;
            int ie    = faceEdges[i][0];
            int iv    = edges[ie].verts.a;
            int ivEnd = edges[ie].verts.b;
            //printf( "%i(%i,%i)\n", ie, iv, ivEnd );
            //for(int iter=0; iter<ne; iter++){
            // todo - we can perhaps sort it by faster algorithms but for small number of edges-per-polygon it is not worth it
            int ndone=0;
            while( iv != ivEnd ){
                int ivNew = -1;
                int j;
                //for( j : faceEdges[i]){
                for(int jj=0; jj<faceEdges[i].size(); jj++){
                    j = faceEdges[i][jj];
                    if(ie==j) continue;
                    //if((ie==j)||(ie==ieo)) continue;
                    if      (edges[j].verts.a == iv){ ivNew=edges[j].verts.b; break; }
                    else if (edges[j].verts.b == iv){ ivNew=edges[j].verts.a; break; };
                }
                if(ivNew>=0){ // anything was found ?
                    pl->ipoints.push_back(iv);
                    pl->iedges .push_back(ie);
                    //ieo = ie;
                    ie  = j;
                    //printf( "ie %i %i iv %i->%i \n", ie, j, iv, ivNew );
                    iv = ivNew;
                }else                         { printf("error: cannot find %i \n", iv );      return; }
                if(ndone>=faceEdges[i].size()){ printf("error: cannot close polygon \n", iv ); return; }
                ndone++;
            }
            pl->ipoints.push_back(iv);
            pl->iedges .push_back(ie);
            polygons.push_back(pl);
        }
    }
}

0 个答案:

没有答案