Сохранение многогранника Nef как Polyhedron_3 или Surface_mesh дает разные результаты - PullRequest
0 голосов
/ 30 октября 2018

Я хотел сохранить многогранник Nef в файл OFF для его визуализации. Как написано в многограннике Nef CGAL в руководстве пользователя (см. Параграфы 5.4 и 5.5), многогранник Nef можно преобразовать как в Polyhedron_3 , так и в Surface_mesh .

Однако я заметил, что при преобразовании в эти структуры и последующем сохранении его в файл OFF результаты отличаются.

Здесь я сообщаю код для минимального примера:

#include <list>
#include <iostream>
#include <fstream>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/Nef_polyhedron_3.h>
#include <CGAL/IO/Nef_polyhedron_iostream_3.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/boost/graph/convert_nef_polyhedron_to_polygon_mesh.h>    

typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point_3;
typedef CGAL::Surface_mesh<Point_3> Mesh;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron_3;
typedef CGAL::Nef_polyhedron_3<Kernel> Nef_polyhedron;
typedef Kernel::Vector_3 Vector_3;
typedef Kernel::Aff_transformation_3 Aff_transformation_3;

int convertStlToOff(const char* inputFilename, const char* outputFilename)
{
    //read 80 bytes and put in std::cerr
    std::ifstream obj(inputFilename, std::ios::in | std::ios::binary);
    for (int i = 0; i < 80; i++) {
        boost::uint8_t c;
        obj.read(reinterpret_cast<char*>(&c), sizeof(c));
        std::cerr << c;
    }
    std::cerr << std::endl;

    //read 4 bytes and initialize number of triangles
    boost::uint32_t N32;
    obj.read(reinterpret_cast<char*>(&N32), sizeof(N32));
    unsigned int N = N32;
    std::cerr << N << " triangles" << std::endl;

    //reserve space for N faces
    std::vector<Point_3> points;
    std::map<Point_3, int> pmap;
    typedef boost::tuple<int, int, int> Face;
    std::vector<Face> faces;
    faces.reserve(N);

    //read all faces
    int number_of_points = 0;
    int number_of_snapped_points = 0;
    for (int i = 0; i < N; i++)
    {
        //read face normal (it is ignored)
        float normal[3];
        obj.read(reinterpret_cast<char*>(&normal[0]), sizeof(normal[0]));
        obj.read(reinterpret_cast<char*>(&normal[1]), sizeof(normal[1]));
        obj.read(reinterpret_cast<char*>(&normal[2]), sizeof(normal[2]));

        //read coordinates of all 3 points
        int index[3];
        for (int j = 0; j < 3; j++)
        {
            float x, y, z;
            obj.read(reinterpret_cast<char*>(&x), sizeof(x));
            obj.read(reinterpret_cast<char*>(&y), sizeof(y));
            obj.read(reinterpret_cast<char*>(&z), sizeof(z));
            Point_3 p(x, y, z);
            if (pmap.find(p) == pmap.end())
            {
                // check brute force if there is a close point
                bool found_close_point = false;
                /*for (int k = 0; k < points.size(); k++)
                {
                if (sqrt(CGAL::squared_distance(p, points[k])) < 0.00001)
                {
                index[j] = k;
                found_close_point = true;
                number_of_snapped_points++;
                }
                }*/
                if (!found_close_point)
                {
                    points.push_back(p);
                    index[j] = number_of_points;
                    pmap[p] = number_of_points++;
                }
            }
            else {
                index[j] = pmap[p];
            }
        }
        faces.push_back(boost::make_tuple(index[0], index[1], index[2]));

        //read two additional bytes, and ignore them
        char c;
        obj.read(reinterpret_cast<char*>(&c), sizeof(c));
        obj.read(reinterpret_cast<char*>(&c), sizeof(c));
    }
    std::cerr << number_of_snapped_points << " snapped points" << std::endl;

    std::ofstream outputFile(outputFilename);
    outputFile.precision(20);
    outputFile << "OFF\n" << points.size() << " " << faces.size() << " 0" << std::endl;
    for (int i = 0; i < points.size(); i++)
    {
        outputFile << points[i] << std::endl;
    }

    for (int i = 0; i < faces.size(); i++)
    {
        outputFile << "3 " << boost::get<0>(faces[i]) << " " << boost::get<1>(faces[i]) << " " << boost::get<2>(faces[i]) << std::endl;
    }

    return 0;
}

void fill_cube_1(Polyhedron_3 & poly)
{
    std::string input =
        "OFF\n\
8 12 0\n\
-1 -1 -1\n\
-1 1 -1\n\
1 1 -1\n\
1 -1 -1\n\
-1 -1 1\n\
-1 1 1\n\
1 1 1\n\
1 -1 1\n\
3  0 1 3\n\
3  3 1 2\n\
3  0 4 1\n\
3  1 4 5\n\
3  3 2 7\n\
3  7 2 6\n\
3  4 0 3\n\
3  7 4 3\n\
3  6 4 7\n\
3  6 5 4\n\
3  1 5 6\n\
3  2 1 6";
    std::stringstream ss;
    ss << input;
    ss >> poly;
}

enum savingModality
{
    SAVE_AS_POLYHEDRON_3 = 0,
    SAVE_AS_SURFACE_MESH = 1,
};

int saveNefObjectInOffFile(Nef_polyhedron offObject, const char* filename, savingModality modality)
{
    if (!offObject.is_simple())
    {
        printf("Object is not simple. Cannot convert to mesh or polyhedron\n");
        return 1;
    }

    std::ofstream outStream;
    outStream.open(filename);
    if (modality == SAVE_AS_POLYHEDRON_3)
    {
        Polyhedron_3 outputPolyhedron;
        offObject.convert_to_Polyhedron(outputPolyhedron);
        outStream << outputPolyhedron;
    }
    else if (modality == SAVE_AS_SURFACE_MESH)
    {
        Mesh outputMesh;
        CGAL::convert_nef_polyhedron_to_polygon_mesh(offObject, outputMesh);
        outStream << outputMesh;
    }
    outStream.close();

    return 0;
}

int main()
{
    int ret;

    //construct nef object #1
    Polyhedron_3 cube1;
    fill_cube_1(cube1);
    Nef_polyhedron nefObject1(cube1);

    //construct nef object #2
    Nef_polyhedron nefObject2(cube1);
    Aff_transformation_3 scale2(1, 0, 0,
        0, 1, 0,
        0, 0, 1,
        2);
    nefObject2.transform(scale2);
    Aff_transformation_3 translation2(CGAL::TRANSLATION, Vector_3(-0.5, -0.5, -0.5));
    nefObject2.transform(translation2);

    //construct nef object #3
    Nef_polyhedron nefObject3;
    nefObject3 = nefObject1 - nefObject2;

    //save results into .off file
    ret = saveNefObjectInOffFile(nefObject3, "out1.off", SAVE_AS_POLYHEDRON_3);
    ret = saveNefObjectInOffFile(nefObject3, "out2.off", SAVE_AS_SURFACE_MESH);

    return 0;
}

и скриншоты визуализации двух файлов: сохранение в виде многогранника_3 и сохранение в виде Surface_mesh . Как видите, похоже, что некоторые лица пропали без вести.

Мой вопрос: «Почему результаты визуализируются по-разному?»

1 Ответ

0 голосов
/ 30 октября 2018

Выход на Polyhedron_3 триангулирован, а на Surface_mesh нет. Я думаю, в meshlab есть ошибка для отображения невыпуклых граней.

Посмотрите на doc , вы увидите, что есть булевский параметр для запуска или нет триангуляции.

...