IAM

OPENSOURCEFAN STUDYING
STUDYINGCOMPUTERSCIENCEANDMATH COMPUTERSCIENCE

Check out the latest superpixel benchmark — Superpixel Benchmark (2016) — and let me know your opinion! @david_stutz
17thAPRIL2017

SNIPPET

C++

C++ code to read triangular meshes from .off files.

main.cpp
#ifndef IO_OFF_READ_OFF_HPP
#define IO_OFF_READ_OFF_HPP

#include <fstream>
#include <vector>

/** \brief Reading an off file and returning the vertices x, y, z coordinates and the
 * face indices.
 * \param[in] filepath path to the OFF file
 * \param[out] vertices read vertices as x1, y1, z1, x2, y2, z2, x3, y3, z3, ...
 * \param[out] faces read faces as v11, v12, v13, v21, v22, v23 where vij are vertex indices
 * \return success
 */
bool read_off(const std::string filepath, int& n_vertices, std::vector<float>& vertices, 
        int& n_faces, std::vector<int>& faces) {

    std::ifstream file(filepath.c_str());
    std::string line;
    std::stringstream ss;
    int line_nb = 0;

    std::getline(file, line);
    ++line_nb;

    if (line != "off" && line != "OFF") {
        std::cout << "[Error] Invalid header: \"" << line << "\", " << filepath << std::endl;
        return false;
    }

    size_t n_edges;
    std::getline(file, line);
    ++line_nb;

    ss << line;
    ss >> n_vertices;
    ss >> n_faces;
    ss >> n_edges;

    float x, y, z;
    for (size_t v = 0; v < n_vertices; ++v) {
        std::getline(file, line);
        ++line_nb;

        ss.clear();
        ss.str("");

        ss << line;
        ss >> x;
        ss >> y;
        ss >> z;

        vertices.push_back(x);
        vertices.push_back(y);
        vertices.push_back(z);
    }

    size_t n;
    int v1, v2, v3;
    for (size_t f = 0; f < n_faces; ++f) {
        std::getline(file, line);
        ++line_nb;

        ss.clear();
        ss.str("");

        ss << line;
        ss >> n;

        if(n != 3) {
            std::cout << "[Error] Not a triangle (" << n << " points) at " << (line_nb - 1) << std::endl;
            return false;
        }

        ss >> v1;
        ss >> v2;
        ss >> v3;

        faces.push_back(v1);
        faces.push_back(v2);
        faces.push_back(v3);
    }

    if (n_vertices != vertices.size()/3) {
        std::cout << "[Error] Number of vertices in header differs from actual number of vertices." << std::endl;
        return false;
    }

    if (n_faces != faces.size()/3) {
        std::cout << "[Error] Number of faces in header differs from actual number of faces." << std::endl;
        return false;
    }

    file.close();
    return true;
}

#endif /* IO_OFF_READ_OFF_HPP */
read_off.cpp
#include <fstream>
#include <gtest/gtest.h>
#include "read_off.hpp"

namespace io_off
{
    TEST(ReadOFF, ReadOFF)
    {
        int n_vertices;
        std::vector<float> vertices;
        int n_faces;
        std::vector<int> faces;
        
        bool success = read_off("0.off", n_vertices, vertices, n_faces, faces);
        ASSERT_TRUE(success);
        
        ASSERT_EQ(n_vertices, vertices.size()/3);
        ASSERT_EQ(n_faces, faces.size()/3);
        ASSERT_EQ(n_vertices, 8);
        ASSERT_EQ(n_faces, 12);
        
        ASSERT_NEAR(vertices[0], 0.353553390593, 1e-6);
        ASSERT_NEAR(vertices[1], 0.25, 1e-6);
        ASSERT_NEAR(vertices[2], 0, 1e-6);
        
        ASSERT_NEAR(vertices[(n_vertices - 1)*3 + 0], -0.353553390593, 1e-6);
        ASSERT_NEAR(vertices[(n_vertices - 1)*3 + 1], -0.25, 1e-6);
        ASSERT_NEAR(vertices[(n_vertices - 1)*3 + 2], 0, 1e-6);
        
        ASSERT_EQ(faces[0], 0);
        ASSERT_EQ(faces[1], 6);
        ASSERT_EQ(faces[2], 4);
        
        ASSERT_EQ(faces[(n_faces - 1)*3 + 0], 0);
        ASSERT_EQ(faces[(n_faces - 1)*3 + 1], 2);
        ASSERT_EQ(faces[(n_faces - 1)*3 + 2], 3);
    }
}

int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
CMakeLists.txt
cmake_minimum_required (VERSION 2.8)
project(io_off)

set(CMAKE_CXX_FLAGS  "-Wall -Wno-sign-compare -g -std=c++0x -O4")

include_directories(../ ../../vendor/googletest/googletest/include)
add_executable(read_off read_off.cpp)
target_link_libraries(read_off gtest)

file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/0.off"
        DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
0.off
OFF
8 12 0
0.353553390593 0.25 2.77555756156e-17
2.77555756156e-17 0.25 -0.353553390593
0.353553390593 -0.25 2.77555756156e-17
2.77555756156e-17 -0.25 -0.353553390593
-2.77555756156e-17 0.25 0.353553390593
-0.353553390593 0.25 -2.77555756156e-17
-2.77555756156e-17 -0.25 0.353553390593
-0.353553390593 -0.25 -2.77555756156e-17
3 0 6 4
3 0 2 6
3 0 5 4
3 0 1 5
3 2 7 6
3 2 3 7
3 1 7 5
3 1 3 7
3 4 7 5
3 4 6 7
3 0 3 1
3 0 2 3

What is your opinion on the code snippet? Is it working? Let me know your thoughts in the comments below or using the following platforms: