Estimating size of marching cubes output geometry

419 Views Asked by At

Is there a way to quickly estimate how much geometry the marching cubes algorithm will produce? As in a ballpark estimate of num verts + num faces or STL file sizes?

I'm trying to implement a pre-triangulation check that tells the user to lower the resolution (i.e. use lower number of samples, spanning larger regions of space), or reduce the domain size before inadvertently trying to generate a multi-GB-large STL-file mesh of an implicit surface that no slicing software could cope with anyway.

In the worst case, I could probably just generate a whole bunch of STL's with different settings to find out these values.

1

There are 1 best solutions below

0
On

It is not difficult to modify a Marching Cubes code so that it only counts the number of vertices and the number of triangles. I think that option that you propose can be useful. You only have to identify in which part of the code the vertices (and normals and colors) and the indices of the triangles are stored. In the case of the Marching Cubes 33 code for the C language that we programmed (marching_cubes_33_c_library_v4, MC33_libraries), the vertices are stored in the MC33_storePointNormal function. Instead of calling MC33_storePointNormal, the vertex counter is simply increased by 1. And in this specific case, the code that stores the indices of the triangles is eliminated, only the counter increment of the number of triangles is left.

I made a function that counts the number of vertices and triangles and calculates the amount of memory occupied by the surface:

// modified from calculate_isosurface function
unsigned long long memory_of_isosurface (MC33 * M, float iso, unsigned int * nV, unsigned int * nT);

This function calls the MC33_findCase_count function instead of calling the MC33_findCase function. You just need to copy the code for both functions at the end of the source/marching_cubes_33.c file and place the declaration of the memory_of_isosurface function in the include/marching_cubes_33.h file.

I benchmarked the function that only counts, and the execution time decrease is between 12 and 32%.

Important note: for reasons of size of the post, I removed a part of the code, switch (c>>8). This part of the code must be copied from the MC33_findCase function.

// modified from MC33_findCase

void MC33_findCase_count(MC33 *M, unsigned int x, unsigned int y, unsigned int z, unsigned int i, float *v)
{
    unsigned int p[13] = {FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF};
    int f[6];
    unsigned int ti[3];
    unsigned int c, m, k;
    const unsigned short int *pcase = MC33_all_tables;
    c = pcase[i&0x80? i^0xFF: i];
    m = (i^c)&0x80;
    k = c&0x7F;
    switch (c>>8)
    {
        /* copy here the missing code part from the MC33_findCase function */
    }
    while (i)
    {
        i = *(++pcase);
        for (k = 3; k;)
        {
            c = i&0x0F;
            if (p[c] == FF)
            {
                switch (c)
                {
                case 0:
                    if (z || x)
                        p[0] = M->Oy[y][x];
                    else
                    {
                        if (v[0] == 0)
                        {
                            if (p[3] != FF)
                                p[0] = p[3];
                            else if (p[8] != FF)
                                p[0] = p[8];
                            else if (y && signbf(v[3]))
                                p[0] = M->Lz[y][0];
                            else if (y && signbf(v[4]))
                                p[0] = M->Ox[y][0];
                            else if (y? sbf(M->iso - M->F[0][y - 1][0]): 0)
                                p[0] = M->Oy[y - 1][0];
                            else
                                p[0] = M->nV++;
                        }
                        else if (v[1] == 0)
                        {
                            if (p[1] != FF)
                                p[0] = p[1];
                            else if (p[9] != FF)
                                p[0] = p[9];
                            else
                                p[0] = M->nV++;
                        }
                        else
                            p[0] = M->nV++;

                        M->Oy[y][0] = p[0];
                    }
                    break;
                case 1:
                    if (x)
                        p[1] = M->Lz[y + 1][x];
                    else
                    {
                        if (v[1] == 0)
                        {
                            if (p[0] != FF)
                                p[1] = p[0];
                            else if (p[9] != FF)
                                p[1] = p[9];
                            else if (z && signbf(v[0]))
                                p[1] = M->Oy[y][0];
                            else if (z && signbf(v[5]))
                                p[1] = M->Ox[y + 1][0];
                            else if (z && y + 1 < M->ny? sbf(M->iso - M->F[z][y + 2][0]): 0)
                                p[1] = M->Oy[y + 1][0];
                            else if (z? sbf(M->iso - M->F[z - 1][y + 1][0]): 0)
                                p[1] = M->Lz[y + 1][0];
                            else
                                p[1] = M->nV++;
                        }
                        else if (v[2] == 0)
                        {
                            if (p[2] != FF)
                                p[1] = p[2];
                            else if (p[10] != FF)
                                p[1] = p[10];
                            else
                                p[1] = M->nV++;
                        }
                        else
                            p[1] = M->nV++;
                        M->Lz[y + 1][0] = p[1];
                    }
                    break;
                case 2:
                    if (x)
                        p[2] = M->Ny[y][x];
                    else
                    {
                        if (v[3] == 0)
                        {
                            if (p[3] != FF)
                                p[2] = p[3];
                            else if (p[11] != FF)
                                p[2] = p[11];
                            else if (y && signbf(v[0]))
                                p[2] = M->Lz[y][0];
                            else if (y && signbf(v[7]))
                                p[2] = M->Nx[y][0];
                            else if (y? sbf(M->iso - M->F[z + 1][y - 1][0]): 0)
                                p[2] = M->Ny[y - 1][0];
                            else
                                p[2] = M->nV++;
                        }
                        else if (v[2] == 0)
                        {
                            if (p[1] != FF)
                                p[2] = p[1];
                            else if (p[10] != FF)
                                p[2] = p[10];
                            else
                                p[2] = M->nV++;
                        }
                        else
                            p[2] = M->nV++;
                        M->Ny[y][0] = p[2];
                    }
                    break;
                case 3:
                    if (y || x)
                        p[3] = M->Lz[y][x];
                    else
                    {
                        if (v[0] == 0)
                        {
                            if (p[0] != FF)
                                p[3] = p[0];
                            else if (p[8] != FF)
                                p[3] = p[8];
                            else if (z && signbf(v[1]))
                                p[3] = M->Oy[0][0];
                            else if (z && signbf(v[4]))
                                p[3] = M->Ox[0][0];
                            else if (z? sbf(M->iso - M->F[z - 1][0][0]): 0)
                                p[3] = M->Lz[0][0];
                            else
                                p[3] = M->nV++;
                        }
                        else if (v[3] == 0)
                        {
                            if (p[2] != FF)
                                p[3] = p[2];
                            else if (p[11] != FF)
                                p[3] = p[11];
                            else
                                p[3] = M->nV++;
                        }
                        else
                            p[3] = M->nV++;
                        M->Lz[0][0] = p[3];
                    }
                    break;
                case 4:
                    if (z)
                        p[4] = M->Oy[y][x + 1];
                    else
                    {
                        if (v[4] == 0)
                        {
                            if (p[8] != FF)
                                p[4] = p[8];
                            else if (p[7] != FF)
                                p[4] = p[7];
                            else if (y && signbf(v[0]))
                                p[4] = M->Ox[y][x];
                            else if (y && signbf(v[7]))
                                p[4] = M->Lz[y][x + 1];
                            else if (y? sbf(M->iso - M->F[0][y - 1][x + 1]): 0)
                                p[4] = M->Oy[y - 1][x + 1];
                            else if (y && x + 1 < M->nx? sbf(M->iso - M->F[0][y][x + 2]): 0)
                                p[4] = M->Ox[y][x + 1];
                            else
                                p[4] = M->nV++;
                        }
                        else if (v[5] == 0)
                        {
                            if (p[9] != FF)
                                p[4] = p[9];
                            else if (p[5] != FF)
                                p[4] = p[5];
                            else
                                p[4] = M->nV++;
                        }
                        else
                            p[4] = M->nV++;
                        M->Oy[y][x + 1] = p[4];
                    }
                    break;
                case 5:
                    if (v[5] == 0)
                    {
                        if (signbf(v[4]))
                        {
                            if (z)
                            {
                                p[5] = p[4] = M->Oy[y][x + 1];
                                if (signbf(v[1]))
                                    p[9] = p[5];
                            }
                            else
                            {
                                if (p[4] != FF)
                                    p[5] = p[4];
                                else if (p[9] != FF)
                                    p[5] = p[9];
                                else
                                    p[5] = M->nV++;
                            }
                        }
                        else if (signbf(v[1]))
                        {
                            if (z)
                                p[5] = p[9] = M->Ox[y + 1][x];
                            else
                            {
                                if (p[9] != FF)
                                    p[5] = p[9];
                                else
                                    p[5] = M->Ox[y + 1][x] = p[9] = M->nV++;
                            }
                        }
                        else
                        {
                            if (z && x + 1 < M->nx? sbf(M->iso - M->F[z][y + 1][x + 2]): 0)
                                p[5] = M->Ox[y + 1][x + 1];
                            else if (z && y + 1 < M->ny? sbf(M->iso - M->F[z][y + 2][x + 1]): 0)
                                p[5] = M->Oy[y + 1][x + 1];
                            else if (z? sbf(M->iso - M->F[z - 1][y + 1][x + 1]): 0)
                                p[5] = M->Lz[y + 1][x + 1];
                            else
                                p[5] = M->nV++;
                        }
                    }
                    else if (v[6] == 0)
                    {
                        if (p[6] == FF)
                        {
                            if (p[10] == FF)
                            {
                                p[5] = M->nV++;
                                if (signbf(v[2])) M->Nx[y + 1][x] = p[10] = p[5];
                                if (signbf(v[7])) M->Ny[y][x + 1] = p[6] = p[5];
                            }
                            else
                            {
                                p[5] = p[10];
                                if (signbf(v[7])) M->Ny[y][x + 1] = p[6] = p[5];
                            }
                        }
                        else
                        {
                            p[5] = p[6];
                            if (signbf(v[2])) M->Nx[y + 1][x] = p[10] = p[5];
                        }
                    }
                    else
                        p[5] = M->nV++;
                    M->Lz[y + 1][x + 1] = p[5];
                    break;
                case 6:
                    if (v[7] == 0)
                    {
                        if (signbf(v[3]))
                        {
                            if (y)
                            {
                                p[6] = p[11] = M->Nx[y][x];
                                if (signbf(v[4]))
                                    p[7] = p[6];
                            }
                            else
                            {
                                if (p[11] != FF)
                                    p[6] = p[11];
                                else if (p[7] != FF)
                                    p[6] = p[7];
                                else
                                    p[6] = M->nV++;
                            }
                        }
                        else if (signbf(v[4]))
                        {
                            if (y)
                                p[6] = p[7] = M->Lz[y][x + 1];
                            else if (p[7] != FF)
                                p[6] = p[7];
                            else
                                p[6] = M->Lz[y][x + 1] = p[7] = M->nV++;
                        }
                        else
                        {
                            if (y? sbf(M->iso - M->F[z + 1][y - 1][x + 1]): 0)
                                p[6] = M->Ny[y - 1][x + 1];
                            else if (y && x + 1 < M->nx? sbf(M->iso - M->F[z + 1][y][x + 2]): 0)
                                p[6] = M->Nx[y][x + 1];
                            else
                                p[6] = M->nV++;
                        }
                    }
                    else if (v[6] == 0)
                    {
                        if (p[5] == FF)
                        {
                            if (p[10] == FF)
                            {
                                p[6] = M->nV++;
                                if (signbf(v[5])) M->Lz[y + 1][x + 1] = p[5] = p[6];
                                if (signbf(v[2])) M->Nx[y + 1][x] = p[10] = p[6];
                            }
                            else
                            {
                                p[6] = p[10];
                                if (signbf(v[5])) M->Lz[y + 1][x + 1] = p[5] = p[6];
                            }
                        }
                        else
                        {
                            p[6] = p[5];
                            if (signbf(v[2])) M->Nx[y + 1][x] = p[10] = p[6];
                        }
                    }
                    else
                        p[6] = M->nV++;
                    M->Ny[y][x + 1] = p[6];
                    break;
                case 7:
                    if (y)
                        p[7] = M->Lz[y][x + 1];
                    else
                    {
                        if (v[4] == 0)
                        {
                            if (p[8] != FF)
                                p[7] = p[8];
                            else if (p[4] != FF)
                                p[7] = p[4];
                            else if (z && signbf(v[0]))
                                p[7] = M->Ox[0][x];
                            else if (z && x + 1 < M->nx? sbf(M->iso - M->F[z][0][x + 2]): 0)
                                p[7] = M->Ox[0][x + 1];
                            else if (z? sbf(M->iso - M->F[z - 1][0][x + 1]): 0)
                                p[7] = M->Lz[0][x + 1];
                            else
                                p[7] = M->nV++;
                        }
                        else if (v[7] == 0)
                        {
                            if (p[6] != FF)
                                p[7] = p[6];
                            else if (p[11] != FF)
                                p[7] = p[11];
                            else
                                p[7] = M->nV++;
                        }
                        else
                            p[7] = M->nV++;
                        M->Lz[0][x + 1] = p[7];
                    }
                    break;
                case 8:
                    if (z || y)
                        p[8] = M->Ox[y][x];
                    else
                    {
                        if (v[0] == 0)
                        {
                            if (p[3] != FF)
                                p[8] = p[3];
                            else if (p[0] != FF)
                                p[8] = p[0];
                            else if (x && signbf(v[3]))
                                p[8] = M->Lz[0][x];
                            else if (x && signbf(v[1]))
                                p[8] = M->Oy[0][x];
                            else if (x? sbf(M->iso - M->F[0][0][x - 1]): 0)
                                p[8] = M->Ox[0][x - 1];
                            else
                                p[8] = M->nV++;
                        }
                        else if (v[4] == 0)
                        {
                            if (p[4] != FF)
                                p[8] = p[4];
                            else if (p[7] != FF)
                                p[8] = p[7];
                            else
                                p[8] = M->nV++;
                        }
                        else
                            p[8] = M->nV++;
                        M->Ox[0][x] = p[8];
                    }
                    break;
                case 9:
                    if (z)
                        p[9] = M->Ox[y + 1][x];
                    else
                    {
                        if (v[1] == 0)
                        {
                            if (p[0] != FF)
                                p[9] = p[0];
                            else if (p[1] != FF)
                                p[9] = p[1];
                            else if (x && signbf(v[0]))
                                p[9] = M->Oy[y][x];
                            else if (x && signbf(v[2]))
                                p[9] = M->Lz[y + 1][x];
                            else if (x? sbf(M->iso - M->F[0][y + 1][x - 1]): 0)
                                p[9] = M->Ox[y + 1][x - 1];
                            else
                                p[9] = M->nV++;
                        }
                        else if (v[5] == 0)
                        {
                            if (p[5] != FF)
                                p[9] = p[5];
                            else if (p[4] != FF)
                                p[9] = p[4];
                            else
                                p[9] = M->nV++;
                        }
                        else
                            p[9] = M->nV++;
                        M->Ox[y + 1][x] = p[9];
                    }
                    break;
                case 10:
                    if (v[2] == 0)
                    {
                        if (signbf(v[1]))
                        {
                            if (x)
                            {
                                p[10] = p[1] = M->Lz[y + 1][x];
                                if (signbf(v[3])) p[2] = p[10];
                            }
                            else
                            {
                                if (p[1] != FF)
                                    p[10] = p[1];
                                else if (p[2] != FF)
                                    p[10] = p[2];
                                else
                                    p[10] = M->nV++;
                            }
                        }
                        else if (signbf(v[3]))
                        {
                            if (x)
                                p[10] = p[2] = M->Ny[y][x];
                            else
                                p[10] = M->nV++;
                        }
                        else
                        {
                            if (x? sbf(M->iso - M->F[z + 1][y + 1][x - 1]): 0)
                                p[10] = M->Nx[y + 1][x - 1];
                            else
                                p[10] = M->nV++;
                        }
                    }
                    else if (v[6] == 0)
                    {
                        if (p[6] == FF)
                        {
                            if (p[5] == FF)
                            {
                                p[10] = M->nV++;
                                if (signbf(v[5])) M->Lz[y + 1][x + 1] = p[5] = p[10];
                                if (signbf(v[7])) M->Ny[y][x + 1] = p[6] = p[10];
                            }
                            else
                            {
                                p[10] = p[5];
                                if (signbf(v[7])) M->Ny[y][x + 1] = p[6] = p[10];
                            }
                        }
                        else
                        {
                            p[10] = p[6];
                            if (signbf(v[5])) M->Lz[y + 1][x + 1] = p[5] = p[10];
                        }
                    }
                    else
                        p[10] = M->nV++;
                    M->Nx[y + 1][x] = p[10];
                    break;
                case 11:
                    if (y)
                        p[11] = M->Nx[y][x];
                    else
                    {
                        if (v[3] == 0)
                        {
                            if (p[3] != FF)
                                p[11] = p[3];
                            else if (p[2] != FF)
                                p[11] = p[2];
                            else if (x && signbf(v[0]))
                                p[11] = M->Lz[0][x];
                            else if (x? sbf(M->iso - M->F[z + 1][0][x - 1]): 0)
                                p[11] = M->Nx[0][x - 1];
                            else
                                p[11] = M->nV++;
                        }
                        else if (v[7] == 0)
                        {
                            if (p[6] != FF)
                                p[11] = p[6];
                            else if (p[7] != FF)
                                p[11] = p[7];
                            else
                                p[11] = M->nV++;
                        }
                        else
                            p[11] = M->nV++;
                        M->Nx[0][x] = p[11];
                    }
                break;
                default:
                    p[12] = M->nV++;
                }
            }
            ti[--k] = p[c];
            i >>= 4;
        }
        if (ti[0] != ti[1] && ti[0] != ti[2] && ti[1] != ti[2])
            M->nT++;
    }
}

// modified from calculate_isosurface function
unsigned long long memory_of_isosurface(MC33 *M, float iso, unsigned int *nV, unsigned int *nT)
{
    unsigned int x, y, z, nx = M->nx, ny = M->ny, nz = M->nz;
    GRD_data_type ***F = M->F, **F0, **F1, *V00, *V01, *V11, *V10;
    float V[12];
    float *v1 = V, *v2 = V + 4;
    M->nT = M->nV = 0;
    M->iso = iso;
    for (z = 0; z != nz; ++z)
    {
        F0 = *F;
        F1 = *(++F);
        for (y = 0; y != ny; ++y)
        {
            V00 = *F0;
            V01 = *(++F0);
            V10 = *F1;
            V11 = *(++F1);
            v2[0] = iso - *V00;
            v2[1] = iso - *V01;
            v2[2] = iso - *V11;
            v2[3] = iso - *V10;
            unsigned int i = signbf(v2[3]) != 0;
            if (signbf(v2[2])) i |= 2;
            if (signbf(v2[1])) i |= 4;
            if (signbf(v2[0])) i |= 8;
            for (x = 0; x != nx; ++x)
            {
                {float *P = v1; v1 = v2; v2 = P;}
                v2[0] = iso - *(++V00);
                v2[1] = iso - *(++V01);
                v2[2] = iso - *(++V11);
                v2[3] = iso - *(++V10);
                i = ((i&0x0F)<<4)|(signbf(v2[3]) != 0);
                if (signbf(v2[2])) i |= 2;
                if (signbf(v2[1])) i |= 4;
                if (signbf(v2[0])) i |= 8;
                if (i && i^0xFF)
                {
                    if (v1 > v2) {float *t = v2; float *s = t + 8; *s = *t; *(++s) = *(++t); *(++s) = *(++t); *(++s) = *(++t);}                        
                    MC33_findCase_count(M,x,y,z,i,v1);
                }
            }
        }
        {unsigned int** P = M->Ox; M->Ox = M->Nx; M->Nx = P;}
        {unsigned int** P = M->Oy; M->Oy = M->Ny; M->Ny = P;}
    }
    *nV = M->nV;
    *nT = M->nT;
    // number of vertices * (size of vertex and normal + size of color ) + number of triangle * size of triangle + size of struct surface
    return (*nV) * (6 * sizeof(float) + sizeof(int)) + (*nT) * (3 * sizeof(int)) + sizeof(surface);
}