Оценка размера выходной геометрии марширующих кубов

Есть ли способ быстро оценить, сколько геометрии создаст алгоритм марширующих кубов? Как в приблизительной оценке количества вершин + количество граней или размеров файла STL?

Я пытаюсь реализовать предварительную проверку триангуляции, которая говорит пользователю снизить разрешение (т. е. использовать меньшее количество выборок, охватывающих большие области пространства) или уменьшить размер домена, прежде чем непреднамеренно пытаться создать многогигабайтный большой STL-файловая сетка неявной поверхности, с которой никакое программное обеспечение для слайсинга не справилось бы.

В худшем случае я мог бы просто сгенерировать целую кучу STL с разными настройками, чтобы узнать эти значения.


person Joshua Leung    schedule 29.11.2020    source источник


Ответы (1)


Несложно изменить код Marching Cubes так, чтобы он подсчитывал только количество вершин и количество треугольников. Я думаю, что тот вариант, который вы предлагаете, может быть полезен. Вам нужно только определить, в какой части кода хранятся вершины (а также нормали и цвета) и индексы треугольников. В случае кода Marching Cubes 33 для языка C, который мы запрограммировали (marching_cubes_33_c_library_v4, MC33_libraries), вершины сохраняются в функции MC33_storePointNormal. Вместо вызова MC33_storePointNormal счётчик вершин просто увеличивается на 1. И в данном конкретном случае убирается код, который хранит индексы треугольников, остаётся только счётчик приращения количества треугольников.

Я сделал функцию, которая подсчитывает количество вершин и треугольников и вычисляет объем памяти, занимаемой поверхностью:

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

Эта функция вызывает функцию MC33_findCase_count вместо вызова функции MC33_findCase. Вам просто нужно скопировать код обеих функций в конец файла source/marching_cubes_33.c и поместить объявление функции memory_of_isosurface в файл include/marching_cubes_33.h.

Я протестировал функцию, которая только считает, и снижение времени выполнения составляет от 12 до 32%.

Важное примечание: из соображений размера поста я удалил часть кода, переключатель (c››8). Эту часть кода необходимо скопировать из функции MC33_findCase.

// 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);
}
person David Vega    schedule 18.01.2021