#include <amscudafractallevelset/amscudafractallevelset.cuh>

namespace amscuda
{
namespace fractallevelset
{

    __device__ __host__ mtcube::mtcube()
    {
        fevals[0] = 0.0f;
        fevals[1] = 0.0f;
        fevals[2] = 0.0f;
        fevals[3] = 0.0f;
        fevals[4] = 0.0f;
        fevals[5] = 0.0f;
        fevals[6] = 0.0f;
        fevals[7] = 0.0f;
        fevals[8] = 0.0f;
        fevals[9] = 0.0f;
        fevals[10] = 0.0f;
        fevals[11] = 0.0f;
        fevals[12] = 0.0f;
        fevals[13] = 0.0f;
        fevals[14] = 0.0f;
        
    }

    __device__ __host__ mtcube::~mtcube()
    {

    }


    __device__ __host__ cuvec3f mtcube::get_point(const int node_index) const //node_index [0,15)
    {
        //corner nodes (0,1,2,3,4,5,6,7)
        //center node 8
        //face center nodes 9,10,11,12,13,14
        cuvec3f ret;
        //cuvec3f a = xyz_min; //temporary during construction
        //cuvec3f b = xyz_max;
        switch(node_index)
        {
            case 0:
                ret = cuvec3f(xyz_min[0],xyz_min[1],xyz_min[2]);
                break;
            case 1:
                ret = cuvec3f(xyz_max[0],xyz_min[1],xyz_min[2]);
                break;
            case 2:
                ret = cuvec3f(xyz_max[0],xyz_max[1],xyz_min[2]);
                break;
            case 3:
                ret = cuvec3f(xyz_min[0],xyz_max[1],xyz_min[2]);
                break;
            case 4:
                ret = cuvec3f(xyz_min[0],xyz_min[1],xyz_max[2]);
                break;
            case 5:
                ret = cuvec3f(xyz_max[0],xyz_min[1],xyz_max[2]);
                break;
            case 6:
                ret = cuvec3f(xyz_max[0],xyz_max[1],xyz_max[2]);
                break;
            case 7:
                ret = cuvec3f(xyz_min[0],xyz_max[1],xyz_max[2]);
                break;
            case 8:
                ret = cuvec3f(0.5f*(xyz_min[0]+xyz_max[0]),0.5f*(xyz_min[1]+xyz_max[1]),0.5f*(xyz_min[2]+xyz_max[2]));
                break;
            case 9:
                ret = cuvec3f(0.5f*(xyz_min[0]+xyz_max[0]),xyz_min[1],0.5f*(xyz_min[2]+xyz_max[2]));
                //ret = cuvec3f(xyz_min[0],0.5f*(xyz_min[1]+xyz_max[1]),0.5f*(xyz_min[2]+xyz_max[2]));
                break;            
            case 10:
                ret = cuvec3f(0.5f*(xyz_min[0]+xyz_max[0]),xyz_max[1],0.5f*(xyz_min[2]+xyz_max[2]));
                //ret = cuvec3f(xyz_max[0],0.5f*(xyz_min[1]+xyz_max[1]),0.5f*(xyz_min[2]+xyz_max[2]));
                break;
            case 11:
                ret = cuvec3f(xyz_min[0],0.5f*(xyz_min[1]+xyz_max[1]),0.5f*(xyz_min[2]+xyz_max[2]));
                //ret = cuvec3f(0.5f*(xyz_min[0]+xyz_max[0]),xyz_min[1],0.5f*(xyz_min[2]+xyz_max[2]));
                break;
            case 12:
                ret = cuvec3f(xyz_max[0],0.5f*(xyz_min[1]+xyz_max[1]),0.5f*(xyz_min[2]+xyz_max[2]));
                //ret = cuvec3f(0.5f*(xyz_min[0]+xyz_max[0]),xyz_max[1],0.5f*(xyz_min[2]+xyz_max[2]));
                break;
            case 13:
                ret = cuvec3f(0.5f*(xyz_min[0]+xyz_max[0]),0.5f*(xyz_min[1]+xyz_max[1]),xyz_min[2]);
                break;            
            case 14:
                ret = cuvec3f(0.5f*(xyz_min[0]+xyz_max[0]),0.5f*(xyz_min[1]+xyz_max[1]),xyz_max[2]);
                break;       
        }

        return ret;
    }
    
    __device__ __host__ tetrahedron mtcube::get_tetrahedron(const int tet_index) const //tet_index [0,24)
    {

        tetrahedron ret;

        switch(tet_index)
        {
            case 0:
                ret.p0 = get_point(8);
                ret.p1 = get_point(9);
                ret.p2 = get_point(0);
                ret.p3 = get_point(1);
                break;
            case 1:
                ret.p0 = get_point(8);
                ret.p1 = get_point(9);
                ret.p2 = get_point(1);
                ret.p3 = get_point(5);
                break;
            case 2:
                ret.p0 = get_point(8);
                ret.p1 = get_point(9);
                ret.p2 = get_point(5);
                ret.p3 = get_point(4);
                break;
            case 3:
                ret.p0 = get_point(8);
                ret.p1 = get_point(9);
                ret.p2 = get_point(4);
                ret.p3 = get_point(0);
                break;
            case 4:
                ret.p0 = get_point(8);
                ret.p1 = get_point(10);
                ret.p2 = get_point(2);
                ret.p3 = get_point(3);
                break;
            case 5:
                ret.p0 = get_point(8);
                ret.p1 = get_point(10);
                ret.p2 = get_point(3);
                ret.p3 = get_point(7);
                break;
            case 6:
                ret.p0 = get_point(8);
                ret.p1 = get_point(10);
                ret.p2 = get_point(7);
                ret.p3 = get_point(6);
                break;
            case 7:
                ret.p0 = get_point(8);
                ret.p1 = get_point(10);
                ret.p2 = get_point(6);
                ret.p3 = get_point(2);
                break;
            case 8:
                ret.p0 = get_point(8);
                ret.p1 = get_point(11);
                ret.p2 = get_point(3);
                ret.p3 = get_point(0);
                break;
            case 9:
                ret.p0 = get_point(8);
                ret.p1 = get_point(11);
                ret.p2 = get_point(0);
                ret.p3 = get_point(4);
                break;
            case 10:
                ret.p0 = get_point(8);
                ret.p1 = get_point(11);
                ret.p2 = get_point(4);
                ret.p3 = get_point(7);
                break;
            case 11:
                ret.p0 = get_point(8);
                ret.p1 = get_point(11);
                ret.p2 = get_point(7);
                ret.p3 = get_point(3);
                break;
            case 12:
                ret.p0 = get_point(8);
                ret.p1 = get_point(12);
                ret.p2 = get_point(1);
                ret.p3 = get_point(2);
                break;
            case 13:
                ret.p0 = get_point(8);
                ret.p1 = get_point(12);
                ret.p2 = get_point(2);
                ret.p3 = get_point(6);
                break;
            case 14:
                ret.p0 = get_point(8);
                ret.p1 = get_point(12);
                ret.p2 = get_point(6);
                ret.p3 = get_point(5);
                break;
            case 15:
                ret.p0 = get_point(8);
                ret.p1 = get_point(12);
                ret.p2 = get_point(5);
                ret.p3 = get_point(1);
                break;
            case 16:
                ret.p0 = get_point(8);
                ret.p1 = get_point(13);
                ret.p2 = get_point(1);
                ret.p3 = get_point(0);
                break;
            case 17:
                ret.p0 = get_point(8);
                ret.p1 = get_point(13);
                ret.p2 = get_point(0);
                ret.p3 = get_point(3);
                break;
            case 18:
                ret.p0 = get_point(8);
                ret.p1 = get_point(13);
                ret.p2 = get_point(3);
                ret.p3 = get_point(2);
                break;
            case 19:
                ret.p0 = get_point(8);
                ret.p1 = get_point(13);
                ret.p2 = get_point(2);
                ret.p3 = get_point(1);
                break;
            case 20:
                ret.p0 = get_point(8);
                ret.p1 = get_point(14);
                ret.p2 = get_point(5);
                ret.p3 = get_point(6);
                break;
            case 21:
                ret.p0 = get_point(8);
                ret.p1 = get_point(14);
                ret.p2 = get_point(6);
                ret.p3 = get_point(7);
                break;
            case 22:
                ret.p0 = get_point(8);
                ret.p1 = get_point(14);
                ret.p2 = get_point(7);
                ret.p3 = get_point(4);
                break;
            case 23:
                ret.p0 = get_point(8);
                ret.p1 = get_point(14);
                ret.p2 = get_point(4);
                ret.p3 = get_point(5);
                break;    
        }

        return ret;
    }


    __device__ __host__ tetrahedron_feinds mtcube::get_feinds(const int tet_index) const //tet_index [0,24)
    {
        tetrahedron_feinds ret;

        switch(tet_index)
        {
            case 0:
                ret.index0 = 8;
                ret.index1 = 9;
                ret.index2 = 0;
                ret.index3 = 1;
                break;
            case 1:
                ret.index0 = 8;
                ret.index1 = 9;
                ret.index2 = 1;
                ret.index3 = 5;
                break;
            case 2:
                ret.index0 = 8;
                ret.index1 = 9;
                ret.index2 = 5;
                ret.index3 = 4;
                break;
            case 3:
                ret.index0 = 8;
                ret.index1 = 9;
                ret.index2 = 4;
                ret.index3 = 0;
                break;
            case 4:
                ret.index0 = 8;
                ret.index1 = 10;
                ret.index2 = 2;
                ret.index3 = 3;
                break;
            case 5:
                ret.index0 = 8;
                ret.index1 = 10;
                ret.index2 = 3;
                ret.index3 = 7;
                break;
            case 6:
                ret.index0 = 8;
                ret.index1 = 10;
                ret.index2 = 7;
                ret.index3 = 6;
                break;
            case 7:
                ret.index0 = 8;
                ret.index1 = 10;
                ret.index2 = 6;
                ret.index3 = 2;
                break;
            case 8:
                ret.index0 = 8;
                ret.index1 = 11;
                ret.index2 = 3;
                ret.index3 = 0;
                break;
            case 9:
                ret.index0 = 8;
                ret.index1 = 11;
                ret.index2 = 0;
                ret.index3 = 4;
                break;
            case 10:
                ret.index0 = 8;
                ret.index1 = 11;
                ret.index2 = 4;
                ret.index3 = 7;
                break;
            case 11:
                ret.index0 = 8;
                ret.index1 = 11;
                ret.index2 = 7;
                ret.index3 = 3;
                break;
            case 12:
                ret.index0 = 8;
                ret.index1 = 12;
                ret.index2 = 1;
                ret.index3 = 2;
                break;
            case 13:
                ret.index0 = 8;
                ret.index1 = 12;
                ret.index2 = 2;
                ret.index3 = 6;
                break;
            case 14:
                ret.index0 = 8;
                ret.index1 = 12;
                ret.index2 = 6;
                ret.index3 = 5;
                break;
            case 15:
                ret.index0 = 8;
                ret.index1 = 12;
                ret.index2 = 5;
                ret.index3 = 1;
                break;
            case 16:
                ret.index0 = 8;
                ret.index1 = 13;
                ret.index2 = 1;
                ret.index3 = 0;
                break;
            case 17:
                ret.index0 = 8;
                ret.index1 = 13;
                ret.index2 = 0;
                ret.index3 = 3;
                break;
            case 18:
                ret.index0 = 8;
                ret.index1 = 13;
                ret.index2 = 3;
                ret.index3 = 2;
                break;
            case 19:
                ret.index0 = 8;
                ret.index1 = 13;
                ret.index2 = 2;
                ret.index3 = 1;
                break;
            case 20:
                ret.index0 = 8;
                ret.index1 = 14;
                ret.index2 = 5;
                ret.index3 = 6;
                break;
            case 21:
                ret.index0 = 8;
                ret.index1 = 14;
                ret.index2 = 6;
                ret.index3 = 7;
                break;
            case 22:
                ret.index0 = 8;
                ret.index1 = 14;
                ret.index2 = 7;
                ret.index3 = 4;
                break;
            case 23:
                ret.index0 = 8;
                ret.index1 = 14;
                ret.index2 = 4;
                ret.index3 = 5;
                break;    
        }

        ret.eval0 = fevals[ret.index0];
        ret.eval1 = fevals[ret.index1];
        ret.eval2 = fevals[ret.index2];
        ret.eval3 = fevals[ret.index3];
        

        return ret;
    }

    
    void test_tetorientation()
    {
        mtcube qube;
        qube.xyz_min = cuvec3f(0,0,0);
        qube.xyz_max = cuvec3f(1,1,1);
        cuvec3f p0;
        tetrahedron tet;
        int I;
        float vsum;

        for(I=0;I<15;I++)
        {
            p0 = qube.get_point(I);
            printf("vertex %d: (%1.3f %1.3f %1.3f)\n",I,p0[0],p0[1],p0[2]);
        }

        vsum = 0.0f;
        for(I=0;I<24;I++)
        {
            tet = qube.get_tetrahedron(I);
            vsum += tet.volume();
            printf("tet %d: volume: %1.3f, vsign %d\n",I,tet.volume(),tet.volume_sign());
        }
        printf("total volume = %1.3f\n",vsum);
        
        return;
    }


    __device__ __host__ __forceinline__ static bool mtoppsign(const int sa, const int sb)
    {
        return ((sa!=0&&sb!=0) && (sa==-sb));
    }

    __device__ __host__ int mt_count_triangles(const tetrahedron_feinds &fevals)
    {
        int ret = 0;
        int s0 = isignf(fevals.eval0);
        int s1 = isignf(fevals.eval1);
        int s2 = isignf(fevals.eval2);
        int s3 = isignf(fevals.eval3);
        int os1 = mtoppsign(s0,s1);
        int os2 = mtoppsign(s0,s2);
        int os3 = mtoppsign(s0,s3);
        
        //cases - exact zero bounday triangles
        if(s0==0 && s1==0 && s2==0 && s3!=0)
        {
            ret = 1;
        }
        else if(s0==0 && s1==0 && s2!=0 && s3==0)
        {
            ret = 1;
        }
        else if(s0==0 && s1!=0 && s2==0 && s3==0)
        {
            ret = 1;
        }
        else if(s0!=0 && s1==0 && s2==0 && s3==0)
        {
            ret = 1;
        }
        //cases opposed signs
        else if(os1 && os2 && os3)
        {
            ret = 1;
        }
        else if(!os1 && os2 && os3)
        {
            ret = 2;
        }
        else if(os1 && !os2 && os3)
        {
            ret = 2;
        }
        else if(!os1 && !os2 && os3)
        {
            ret = 1;
        }
        else if(os1 && os2 && !os3)
        {
            ret = 2;
        }
        else if(!os1 && os2 && !os3)
        {
            ret = 1;
        }
        else if(os1 && !os2 && !os3)
        {
            ret = 1;
        }
        else if(!os1 && !os2 && !os3 && s0!=0)
        {
            ret = 0;
        }

        return ret;
    }

    __device__ __host__ __forceinline__ cuvec3f mtlmpoint(const cuvec3f &p0, const cuvec3f &p1, const float &f0, const float &f1)
    {
        return p0*(1.0f-(-f0/(f1-f0))) + p1*(-f0/(f1-f0));
    }

    __device__ __host__ __forceinline__ void mtfliptriangle(triangle &t)
    {
        cuvec3f tmp;
        tmp = t.p0;
        t.p0 = t.p1;
        t.p1 = tmp;
        return;
    }

    __device__ __host__ int mt_find_triangles(const tetrahedron &tet, const tetrahedron_feinds &fevals, triangle &tri1, triangle &tri2)
    {
        int ret = 0;
        int s0 = isignf(fevals.eval0);
        int s1 = isignf(fevals.eval1);
        int s2 = isignf(fevals.eval2);
        int s3 = isignf(fevals.eval3);
        int os1 = mtoppsign(s0,s1);
        int os2 = mtoppsign(s0,s2);
        int os3 = mtoppsign(s0,s3);
        
        //cases - exact zero bounday triangles
        if(s0==0 && s1==0 && s2==0 && s3!=0)
        {
            ret = 1;
            tri1.p0 = tet.p1;
            tri1.p1 = tet.p0;
            tri1.p2 = tet.p2;

            if(s3==-1) mtfliptriangle(tri1);
        }
        else if(s0==0 && s1==0 && s2!=0 && s3==0)
        {
            ret = 1;
            tri1.p0 = tet.p0;
            tri1.p1 = tet.p1;
            tri1.p2 = tet.p3;

            if(s2==-1) mtfliptriangle(tri1);
        }
        else if(s0==0 && s1!=0 && s2==0 && s3==0)
        {
            ret = 1;
            tri1.p0 = tet.p2;
            tri1.p1 = tet.p0;
            tri1.p2 = tet.p3;

            if(s1==-1) mtfliptriangle(tri1);
        }
        else if(s0!=0 && s1==0 && s2==0 && s3==0)
        {
            ret = 1;
            tri1.p0 = tet.p1;
            tri1.p1 = tet.p2;
            tri1.p2 = tet.p3;

            if(s0==-1) mtfliptriangle(tri1);
        }
        //cases opposed signs
        else if(os1 && os2 && os3)
        {
            //01, 02, 03
            ret = 1;
            tri1.p0 = mtlmpoint(tet.p0,tet.p1,fevals.eval0,fevals.eval1);
            tri1.p1 = mtlmpoint(tet.p0,tet.p2,fevals.eval0,fevals.eval2);
            tri1.p2 = mtlmpoint(tet.p0,tet.p3,fevals.eval0,fevals.eval3);
        }
        else if(!os1 && os2 && os3)
        {
            ret = 2;
            tri1.p0 = mtlmpoint(tet.p0,tet.p2,fevals.eval0,fevals.eval2);
            tri1.p1 = mtlmpoint(tet.p0,tet.p3,fevals.eval0,fevals.eval3);
            tri1.p2 = mtlmpoint(tet.p3,tet.p1,fevals.eval3,fevals.eval1);

            tri2.p0 = mtlmpoint(tet.p1,tet.p2,fevals.eval1,fevals.eval2);
            tri2.p1 = mtlmpoint(tet.p0,tet.p2,fevals.eval0,fevals.eval2);
            tri2.p2 = mtlmpoint(tet.p3,tet.p1,fevals.eval3,fevals.eval1);      
        }
        else if(os1 && !os2 && os3)
        {

            ret = 2;
            tri1.p0 = mtlmpoint(tet.p0,tet.p1,fevals.eval0,fevals.eval1);
            tri1.p1 = mtlmpoint(tet.p3,tet.p2,fevals.eval3,fevals.eval2);
            tri1.p2 = mtlmpoint(tet.p0,tet.p3,fevals.eval0,fevals.eval3);

            tri2.p0 = mtlmpoint(tet.p1,tet.p2,fevals.eval1,fevals.eval2);
            tri2.p1 = mtlmpoint(tet.p3,tet.p2,fevals.eval3,fevals.eval2);  
            tri2.p2 = mtlmpoint(tet.p0,tet.p1,fevals.eval0,fevals.eval1);
            
        }
        else if(!os1 && !os2 && os3)
        {
            ret = 1;
            tri1.p0 = mtlmpoint(tet.p3,tet.p0,fevals.eval3,fevals.eval0);
            tri1.p1 = mtlmpoint(tet.p3,tet.p1,fevals.eval3,fevals.eval1);
            tri1.p2 = mtlmpoint(tet.p3,tet.p2,fevals.eval3,fevals.eval2);

        }
        else if(os1 && os2 && !os3)
        {
            ret = 2;
            tri1.p0 = mtlmpoint(tet.p0,tet.p1,fevals.eval0,fevals.eval1);
            tri1.p1 = mtlmpoint(tet.p0,tet.p2,fevals.eval0,fevals.eval2);
            tri1.p2 = mtlmpoint(tet.p3,tet.p1,fevals.eval3,fevals.eval1);

            tri2.p0 = mtlmpoint(tet.p3,tet.p1,fevals.eval3,fevals.eval1);
            tri2.p1 = mtlmpoint(tet.p0,tet.p2,fevals.eval0,fevals.eval2);
            tri2.p2 = mtlmpoint(tet.p3,tet.p2,fevals.eval3,fevals.eval2);  
        }
        else if(!os1 && os2 && !os3)
        {
            ret = 1;
            tri1.p0 = mtlmpoint(tet.p2,tet.p1,fevals.eval2,fevals.eval1);
            tri1.p1 = mtlmpoint(tet.p2,tet.p0,fevals.eval2,fevals.eval0);
            tri1.p2 = mtlmpoint(tet.p2,tet.p3,fevals.eval2,fevals.eval3);
        }
        else if(os1 && !os2 && !os3)
        {
            ret = 1;
            tri1.p0 = mtlmpoint(tet.p1,tet.p0,fevals.eval1,fevals.eval0);
            tri1.p1 = mtlmpoint(tet.p1,tet.p2,fevals.eval1,fevals.eval2);
            tri1.p2 = mtlmpoint(tet.p1,tet.p3,fevals.eval1,fevals.eval3);
        }
        else if(!os1 && !os2 && !os3 && s0!=0)
        {
            ret = 0;
        }

        //based on s0, flip triangle orientations so that normals point positive
        if(s0==1 && ret>0)
        {
            mtfliptriangle(tri1);
            mtfliptriangle(tri2);
        }

        return ret;
    }

    __device__ __host__ int mtcube::count_triangles()
    {
        int tricount = 0;
        int I;
        for(I=0;I<24;I++)
            tricount += mt_count_triangles(get_feinds(I));

        return tricount;
    }

    //fills from offset to offset+ntris*3*3 with the triangles calculated from fevals
    //increments offset
    __device__ __host__ void mtcube::fill_trianglebuffer(float *buffer, int64_t &offset) 
    {
        int I;
        triangle t1,t2;
        int tc;

        for(I=0;I<24;I++)
        {
            tc = mt_find_triangles(get_tetrahedron(I),get_feinds(I),t1,t2);
            if(tc>=1)
            {
                buffer[offset + 0+3*0] = t1.p0[0];
                buffer[offset + 1+3*0] = t1.p0[1];
                buffer[offset + 2+3*0] = t1.p0[2];

                buffer[offset + 0+3*1] = t1.p1[0];
                buffer[offset + 1+3*1] = t1.p1[1];
                buffer[offset + 2+3*1] = t1.p1[2];

                buffer[offset + 0+3*2] = t1.p2[0];
                buffer[offset + 1+3*2] = t1.p2[1];
                buffer[offset + 2+3*2] = t1.p2[2];
                offset += 9;
            }
            if(tc>=2)
            {
                buffer[offset + 0+3*0] = t2.p0[0];
                buffer[offset + 1+3*0] = t2.p0[1];
                buffer[offset + 2+3*0] = t2.p0[2];

                buffer[offset + 0+3*1] = t2.p1[0];
                buffer[offset + 1+3*1] = t2.p1[1];
                buffer[offset + 2+3*1] = t2.p1[2];

                buffer[offset + 0+3*2] = t2.p2[0];
                buffer[offset + 1+3*2] = t2.p2[1];
                buffer[offset + 2+3*2] = t2.p2[2];

                offset += 9;
            }
        }
        return;
    }

    //counts triangle area without filling a buffer or retaining the mesh
    __device__ __host__ float mtcube::count_triarea() 
    {
        float areasum = 0.0f;
        int I;
        triangle t1,t2;
        int tc;

        for(I=0;I<24;I++)
        {
            tc = mt_find_triangles(get_tetrahedron(I),get_feinds(I),t1,t2);
            if(tc>=1)
            {
                areasum += t1.area();
            }
            if(tc>=2)
            {
                areasum += t2.area();
            }
        }
        return areasum;
    }

    static void _local_mtcubeset(mtcube &c, float corners, float faces, float center)
    {
        int I;
        for(I=0;I<8;I++)
        {
            c.fevals[I] = corners;
        }
        c.fevals[8] = center;
        for(I=9;I<15;I++)
        {
            c.fevals[I] = faces;
        }
        return;
    }

    void test_mtcube_triangulation()
    {
        mtcube q;
        int tricount;
        float area,a,b,c;

        q.xyz_min = cuvec3f(-0.5f,-0.5f,-0.5f);
        q.xyz_max = cuvec3f(0.5f,0.5f,0.5f);
        
        a = 0.0f; b = 0.0f; c = 0.0f;
        _local_mtcubeset(q,a,b,c);
        tricount = q.count_triangles();
        area = q.count_triarea();
        printf("Cube (%1.3f, %1.3f, %1.3f): %d tris, %1.3f area\n",a,b,c,tricount,area);

        a = 1.0f; b = 1.0f; c = -1.0f;
        _local_mtcubeset(q,a,b,c);
        tricount = q.count_triangles();
        area = q.count_triarea();
        printf("Cube (%1.3f, %1.3f, %1.3f): %d tris, %1.3f area\n",a,b,c,tricount,area);

        a = -1.0f; b = -1.0f; c = 1.0f;
        _local_mtcubeset(q,a,b,c);
        tricount = q.count_triangles();
        area = q.count_triarea();
        printf("Cube (%1.3f, %1.3f, %1.3f): %d tris, %1.3f area\n",a,b,c,tricount,area);

        a = 1.0f; b = 1.0f; c = 0.1f;
        _local_mtcubeset(q,a,b,c);
        tricount = q.count_triangles();
        area = q.count_triarea();
        printf("Cube (%1.3f, %1.3f, %1.3f): %d tris, %1.3f area\n",a,b,c,tricount,area);

        a = 1.0f; b = 1.0f; c = -0.1f;
        _local_mtcubeset(q,a,b,c);
        tricount = q.count_triangles();
        area = q.count_triarea();
        printf("Cube (%1.3f, %1.3f, %1.3f): %d tris, %1.3f area\n",a,b,c,tricount,area);

        a = 1.0f; b = 1.0f; c = -0.25f;
        _local_mtcubeset(q,a,b,c);
        tricount = q.count_triangles();
        area = q.count_triarea();
        printf("Cube (%1.3f, %1.3f, %1.3f): %d tris, %1.3f area\n",a,b,c,tricount,area);

        a = 1.0f; b = 1.0f; c = -0.50f;
        _local_mtcubeset(q,a,b,c);
        tricount = q.count_triangles();
        area = q.count_triarea();
        printf("Cube (%1.3f, %1.3f, %1.3f): %d tris, %1.3f area\n",a,b,c,tricount,area);

        a = 0.0f; b = 0.0f; c = 1.0f;
        _local_mtcubeset(q,a,b,c);
        tricount = q.count_triangles();
        area = q.count_triarea();
        printf("Cube (%1.3f, %1.3f, %1.3f): %d tris, %1.3f area\n",a,b,c,tricount,area);

        a = 1.0f; b = -1.0f; c = -1.0f;
        _local_mtcubeset(q,a,b,c);
        tricount = q.count_triangles();
        area = q.count_triarea();
        printf("Cube (%1.3f, %1.3f, %1.3f): %d tris, %1.3f area\n",a,b,c,tricount,area);





        return;
    }

    __device__ __host__ void mtcube::eval_function(main_functionpars &pars)
    {
        //calls a function under consideration at each of the 15 node points
        int I;
        for(I=0;I<15;I++)
        {
            fevals[I] = main_function(get_point(I),pars);
        }
    }
    
};//end namespace fractallevelset
};// end namespace amscuda
