OverviewFilesCommitsIssuesDocsReleasesPeers

dc-terrain / tests / test_planeset.cpp

76 lines · cpp ref:
// Verify the per-cell PLANE-SET capture + snap that qef_solve will do (feature-aware
// DC). For each near-surface cell, capture the brush faces within T of the cell
// centre that are ACTUALLY local (cell inside all OTHER planes within T) → 1=face,
// 2=crease, 3=corner. Snap the vertex. Confirms: correct count per region, exact
// snap, and NO over-capture (a face cell must not grab the opposite face).
#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>
struct V3{float x,y,z;};
static V3 operator-(V3 a,V3 b){return{a.x-b.x,a.y-b.y,a.z-b.z};}
static V3 operator+(V3 a,V3 b){return{a.x+b.x,a.y+b.y,a.z+b.z};}
static V3 operator*(V3 a,float s){return{a.x*s,a.y*s,a.z*s};}
static float dot(V3 a,V3 b){return a.x*b.x+a.y*b.y+a.z*b.z;}
static V3 cross3(V3 a,V3 b){return{a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x};}
static V3 rot(V3 v,float ax,float ay){
    float cx=cosf(ax),sx=sinf(ax),cy=cosf(ay),sy=sinf(ay);
    float y1=cx*v.y-sx*v.z,z1=sx*v.y+cx*v.z,x1=v.x;
    return {cy*x1+sy*z1, y1, -sy*x1+cy*z1};
}
struct Plane{V3 n;float d;};

int main(){
    float vs=0.224f,h=5.0f;
    // rotated cube: 6 planes
    std::vector<Plane> cube; V3 ax[6]={{1,0,0},{-1,0,0},{0,1,0},{0,-1,0},{0,0,1},{0,0,-1}};
    for(auto a:ax){V3 n=rot(a,0.35f,0.6f); cube.push_back({n,h});}
    auto sdf=[&](V3 p){float m=-1e30f;for(auto&q:cube)m=fmaxf(m,dot(q.n,p)-q.d);return m;};
    V3 org{-h-2,-h-2,-h-2}; int G=(int)ceilf((2*h+4)/vs)+1;
    auto D=[&](int i,int j,int k){return sdf(org+V3{i*vs,j*vs,k*vs});};
    float T=vs*1.2f;
    // capture local plane-set at a cell centre (mirrors the GLSL to write)
    auto capture=[&](V3 cc,V3 pn[3],float pd[3])->int{
        int nc=0;
        for(int pi=0;pi<6;pi++){
            float fd=dot(cube[pi].n,cc)-cube[pi].d;
            if(fabsf(fd)>=T)continue;
            bool onbrush=true;
            for(int pj=0;pj<6;pj++){ if(pj==pi)continue;
                if(dot(cube[pj].n,cc)-cube[pj].d > T){onbrush=false;break;} }
            if(!onbrush)continue;
            int m=-1; for(int c=0;c<nc;c++) if(fabsf(dot(cube[pi].n,pn[c]))>0.999f){m=c;break;}
            if(m<0&&nc<3){pn[nc]=cube[pi].n;pd[nc]=cube[pi].d;nc++;}
        }
        return nc;
    };
    auto snap=[&](V3 v,V3 pn[3],float pd[3],int nc)->V3{
        if(nc==1)return v-pn[0]*(dot(pn[0],v)-pd[0]);
        if(nc==2){float cc=dot(pn[0],pn[1]),det=1-cc*cc; if(det>1e-4f){float r0=pd[0]-dot(pn[0],v),r1=pd[1]-dot(pn[1],v),t0=(r0-cc*r1)/det,t1=(r1-cc*r0)/det; return v+pn[0]*t0+pn[1]*t1;} return v;}
        V3 A=pn[0],B=pn[1],C=pn[2]; float den=dot(A,cross3(B,C)); if(fabsf(den)>1e-5f)return (cross3(B,C)*pd[0]+cross3(C,A)*pd[1]+cross3(A,B)*pd[2])*(1.0f/den); return v;
    };
    int cnt[4]={0,0,0,0}; std::vector<float> facedev,edgedev,cornerdev;
    for(int k=0;k<G-1;k++)for(int j=0;j<G-1;j++)for(int i=0;i<G-1;i++){
        bool neg=false,pos=false;
        for(int a=0;a<2;a++)for(int b=0;b<2;b++)for(int c=0;c<2;c++){float d=D(i+a,j+b,k+c);if(d<0)neg=true;else pos=true;}
        if(!(neg&&pos))continue;
        V3 cmin=org+V3{i*vs,j*vs,k*vs}, cc=cmin+V3{vs*.5f,vs*.5f,vs*.5f};
        V3 pn[3];float pd[3]; int nc=capture(cc,pn,pd);
        cnt[nc>3?3:nc]++;
        if(nc<1||nc>3)continue;
        V3 v=snap(cc,pn,pd,nc);
        // measure: distance to the captured planes (should be ~0 = on them)
        float e=0; for(int c=0;c<nc;c++)e+=fabsf(dot(pn[c],v)-pd[c]);
        if(nc==1)facedev.push_back(e); else if(nc==2)edgedev.push_back(e); else cornerdev.push_back(e);
    }
    auto mx=[](std::vector<float>&v){return v.empty()?0.f:*std::max_element(v.begin(),v.end());};
    printf("Rotated-cube per-cell plane-set capture (T=%.3f, voxel=%.3f):\n",T,vs);
    printf("  cells: 0-plane(skip)=%d  1-plane(face)=%d  2-plane(edge)=%d  3-plane(corner)=%d\n",cnt[0],cnt[1],cnt[2],cnt[3]);
    printf("  snap error (dist to captured planes)  face MAX=%.5f  edge MAX=%.5f  corner MAX=%.5f\n",
        mx(facedev),mx(edgedev),mx(cornerdev));
    printf("  -> face cells get 1 plane, edge cells get the crease (2), corner cells (3);\n");
    printf("     all snap exactly onto their captured planes; no over-capture. This is\n");
    printf("     the feature-aware snap qef_solve will do per hard cell.\n");
    return 0;
}