c++cgalwavefront

Writing simple surface mesh with CGAL only outputs 2 facets


I'm testing the CGAL library on a Linux machine. As part of my testing, I wanted to build a simple surface mesh of a cube.

This is my Catch2 test:

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>

#include <catch2/catch_test_macros.hpp>
#include <cmath>
#include <fstream>
#include <iostream>

using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
using Mesh = CGAL::Surface_mesh<Kernel::Point_3>;

// Function to create an approximate parametric sphere
Mesh create_mesh(double size) {
    Mesh mesh;

    // Cube.
    // Define the 8 vertices of the cube
    auto v0 = mesh.add_vertex(Kernel::Point_3(0, 0, 0));
    auto v1 = mesh.add_vertex(Kernel::Point_3(size, 0, 0));
    auto v2 = mesh.add_vertex(Kernel::Point_3(size, size, 0));
    auto v3 = mesh.add_vertex(Kernel::Point_3(0, size, 0));
    auto v4 = mesh.add_vertex(Kernel::Point_3(0, 0, size));
    auto v5 = mesh.add_vertex(Kernel::Point_3(size, 0, size));
    auto v6 = mesh.add_vertex(Kernel::Point_3(size, size, size));
    auto v7 = mesh.add_vertex(Kernel::Point_3(0, size, size));

    // Define the 6 faces of the cube (each face is a quadrilateral made of 2 triangles)
    mesh.add_face(v0, v1, v2, v3);  // Bottom
    mesh.add_face(v4, v5, v6, v7);  // Top
    mesh.add_face(v0, v4, v7, v3);  // Left
    mesh.add_face(v1, v5, v6, v2);  // Right
    mesh.add_face(v0, v4, v5, v1);  // Front
    mesh.add_face(v3, v7, v6, v2);  // Back

    return mesh;
}

TEST_CASE("OBJ Export of Cube") {
    const std::string filename = "test_output.obj";

    // Remove file if it exists, to start fresh
    std::remove(filename.c_str());

    auto mesh = create_mesh(1);
    // Use CGAL to save the combined mesh to OBJ format
    CGAL::IO::write_OBJ(filename, mesh);

    REQUIRE(std::ifstream(filename).good());
}

Problem

To my surprise the cube is not complete. There are only two faces written to the OBJ file for the cube. I don't understand this. What am I doing wrong?

This is the test_output.obj file:

# file written from a CGAL tool in Wavefront obj format
# 8 vertices
# 16 halfedges
# 2 facets


# 8 vertices
# ------------------------------------------

v 0 0 0
v 1 0 0
v 1 1 0
v 0 1 0
v 0 0 1
v 1 0 1
v 1 1 1
v 0 1 1

# 2 facets
# ------------------------------------------

f  1 2 3 4
f  5 6 7 8

# End of Wavefront obj format #


Solution

  • Your faces have incompatible orientations, and so some of the add_face() calls in fact do not add any new face.

    The class CGAL::Surface_mesh is an halfedge data structure to represent a polygon mesh. The faces are oriented by the order of the vertices. The polygon mesh must be manifold, and as such you can't have two faces that have the same (directed) halfedge. Here it is your case as for example your "bottom" and "back" faces and v2 --> v3.

    Here is a possible fix, with outward face orientations:

        // Define the 6 faces of the cube (each face is a quadrilateral made of 2 triangles)
        mesh.add_face(v0, v3, v2, v1);  // Bottom
        mesh.add_face(v4, v5, v6, v7);  // Top
        mesh.add_face(v0, v4, v7, v3);  // Left
        mesh.add_face(v1, v2, v6, v5);  // Right
        mesh.add_face(v0, v1, v5, v4);  // Front
        mesh.add_face(v3, v7, v6, v2);  // Back
    

    and you get the expected result (6 faces).

    Note that add_face() has a return value (the face index) that you can use to check if your face was correctly added since it returns null_face() if the face could not be added. See the doc: https://doc.cgal.org/latest/Surface_mesh/classCGAL_1_1Surface__mesh.html#af45a68e4c8a0fcb7c4fd899185824cae.