You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

180 lines
6.8 KiB

#include "OFFMesh.h"
#include "Vertex.h"
#include "ExternalLib/glm/glm.hpp"
#include <iostream>
#include <string>
#include <fstream>
#include <cmath>
using index_t = std::vector<int>::size_type;
OFFMesh::OFFMesh(const std::string& offFilePath_)
:offFilePath(offFilePath_)
{
/**
* \brief load a mesh from a .off file
* \param offFilePath_ <=> .off file path
* \limitations : assume every facet use the same number of vertex (all triangles, all quads, etc)
* might have unexpected behavior with unregular, non triangle meshes
* does not entirely check file structure
*/
std::string inputLine;
int inputInt, verticesLength, facetsLength, normalsLength, verticesIndLength = 0;
// saving img according to gamma 2.2 scale
std::ifstream inputFile(offFilePath, std::ifstream::in);
if ( !inputFile.is_open() )
{
std::cerr << "Couldn't open input *.off file" << std::endl;
exit(1);
}
else
{
// Reading metadata
std::getline(inputFile, inputLine);
if ( inputLine.compare("OFF") != 0 )
{
std::cerr << "Wrong input file format ?" << std::endl;
exit(1);
}
inputFile >> verticesLength;
vertices = std::vector<Vertex>();
inputFile >> facetsLength;
facets = std::vector<Facet>();
inputFile >> normalsLength;
// Reading vertices
for (int i=0; i<verticesLength; i++)
{
Vertex v;
inputFile >> v.position.x;
inputFile >> v.position.y;
inputFile >> v.position.z;
vertices.push_back(v); // Compute normals later on
}
// Reading facets
for (int i=0; i<facetsLength; i++)
{
inputFile >> verticesIndLength;
Facet f(verticesIndLength);
for (int j=0; j<f.verticesIndLength; j++)
{
inputFile >> inputInt;
f.verticesInd.push_back(inputInt);
}
// Compute facet Normal as if triangles...
// TODO : search normal equations for quads and random polygons
glm::vec3 a = vertices[static_cast<index_t>(f.verticesInd[1])].position - vertices[static_cast<index_t>(f.verticesInd[0])].position;
glm::vec3 b = vertices[static_cast<index_t>(f.verticesInd[2])].position - vertices[static_cast<index_t>(f.verticesInd[0])].position;
f.normal = glm::normalize(glm::cross(b,a));
// Compute center of triangle
f.center = glm::vec3( (vertices[static_cast<index_t>(f.verticesInd[0])].position.x + vertices[static_cast<index_t>(f.verticesInd[1])].position.x + vertices[static_cast<index_t>(f.verticesInd[2])].position.x) / 3,
(vertices[static_cast<index_t>(f.verticesInd[0])].position.y + vertices[static_cast<index_t>(f.verticesInd[1])].position.y + vertices[static_cast<index_t>(f.verticesInd[2])].position.y) / 3,
(vertices[static_cast<index_t>(f.verticesInd[0])].position.z + vertices[static_cast<index_t>(f.verticesInd[1])].position.z + vertices[static_cast<index_t>(f.verticesInd[2])].position.z) / 3);
facets.push_back(f);
}
// Compute vertices Normals (as they're often not provided by the file)
// TODO : !!! TAKE INTO ACCOUNT THE SURFACE OF EACH FACE !!!
// USE "Heron's formula" to do so
for (const Facet& f : facets)
for (const int& vInd : f.verticesInd)
vertices[static_cast<index_t>(vInd)].normal += f.normal;
for (Vertex& v : vertices)
v.normal = glm::normalize(v.normal)/static_cast<float>(facetsLength);
}
// Closing file
inputFile.close();
/*
* Moving Mesh To Center and Normalizing it
*/
// Computing barycenter and max distance
// ( !!! WARNING !!! will cause overflow with huge meshes)
float maxDistance=0;
glm::vec3 foo; // foo is just a Point, it does not have any normal => not a Vertex
for(auto const& v: vertices)
{
foo = foo + v.position;
if (std::abs(v.position.x) > maxDistance)
maxDistance = std::abs(v.position.x);
if (std::abs(v.position.y) > maxDistance)
maxDistance = std::abs(v.position.y);
if (std::abs(v.position.z) > maxDistance)
maxDistance = std::abs(v.position.z);
}
barycenter = foo/static_cast<float>(verticesLength);
// Centering and normalizing mesh
for(auto & v: vertices)
{
v.position = v.position-barycenter;
v.position = v.position/maxDistance;
}
for(auto & f: facets)
{
f.center = f.center-barycenter;
f.center = f.center/maxDistance;
}
// REALLY DIRTY HACK, PLEASE LOOK AWAY
// As for now Embryo's meshes are stored as "Three vertices in a row <=> one triangle"
// Thus throwing away all the "dont waste memory storing the same vertex twice" idea of .off files
// Also as for now, Embryo use one normal per facet, not one normal per vertex
// TODO : think about it .... and find a way to properly store OFFMesh in VBO and display them
// => should probably make a Display() pure virtual method in Mesh and reimplement it for every format
// ... This is pointing out that I'm lacking another layer of abstraction on my mesh structure ... => lots of work ahead
std::vector<Vertex> verticesCopy = std::vector<Vertex>(vertices);
vertices.clear();
for(auto const& facet: facets)
{
for (index_t i=0; i<static_cast<index_t>(verticesIndLength); i++)
{
verticesCopy[static_cast<index_t>(facet.verticesInd[i])].normal = facet.normal;
vertices.push_back(verticesCopy[static_cast<index_t>(facet.verticesInd[i])]);
}
}
// END OF REALLY DIRTY HACK
}
void OFFMesh::saveToOffFile(std::string filePath)
{
/**
* \brief Safe a mesh as a .off file
* \param filePath <=> off file path
*/
std::ofstream outputFile(filePath, std::ifstream::out);
if (!outputFile.is_open())
{
std::cerr << "Couldn't open output *.off file" << std::endl;
exit(1);
}
// Printing metadata
outputFile << "OFF" << std::endl;
outputFile << vertices.size() << " " << facets.size() << " " << 0 << std::endl;
// Printing vertices
for (auto & v: vertices)
outputFile << v.position.x << " " << v.position.y << " " << v.position.z << std::endl;
// Printing facets
for (const auto& f: facets)
{
outputFile << f.verticesIndLength << " ";
for (index_t i=0; i< static_cast<index_t>(f.verticesIndLength-1); i++)
outputFile << f.verticesInd[i] << " ";
outputFile << f.verticesInd[static_cast<index_t>(f.verticesIndLength-1)] << std::endl;
}
outputFile.close();
}