Recently, I wrote a class which can load an .obj file into vector array, and save the vector array as an .obj file. The .obj file looks something like this:
v 0.041159 -0.342570 1.029412 //vertices position : x, y,z
v 0.015579 -0.341674 1.077751
v 0.014664 -0.341184 1.031222
v 0.041923 -0.343100 1.073583
v 0.064655 -0.344713 1.068008
vt 0.516780 0.631480 // vertices' texture coordinate
vt 0.491540 0.621580
vt 0.495720 0.621740
vt 0.500000 0.621740
vt 0.504300 0.624760
vt 0.508540 0.628060
vt 0.512810 0.631590
vt 0.487450 0.621300
f 6497/6542 6321/6366 6319/6364 // triangles compounded by three vertices
f 6498/6543 6495/6540 6496/6541 // the number is index of vertices
f 6498/6543 6496/6541 6497/6542
f 6499/6544 6494/6539 6495/6540
f 6499/6544 6495/6540 6498/6543
f 6500/6545 6492/6537 6494/6539
f 6500/6545 6494/6539 6499/6544
f 6501/6546 6497/6542 6319/6364
f 6501/6546 6319/6364 6316/6361
f 6502/6547 6498/6543 6497/6542
f 6502/6547 6497/6542 6501/6546
f 6503/6548 6499/6544 6498/6543
f 6503/6548 6498/6543 6502/6547
f 6504/6549 6501/6546 6316/6361
I use double
type for vertices and vertices' texture coordinates, unsigned int
for faces.
Here is my header and implementation. The code can be compiled and run successfully. Are there any lurking errors here? How can I improve it?
trimesh.h
#ifndef TRIMESH_H
#define TRIMESH_H
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class trimesh {
public:
std::vector<std::vector<double > > vertices;
std::vector<std::vector<double > > tex_coords;
std::vector<std::vector<double > > vert_normal;
std::vector<std::vector<double > > vert_color;
std::vector<std::vector<unsigned int> > faces;
std::vector<std::vector<unsigned int> > faces_tc;
void load(const std::string filename);// load .obj file from given path
void save(const std::string save_path, const bool with_color = true, const bool with_vt = true); // save the current mesh to the given save_path
};
#endif
trimesh.cpp
#include "trimesh.h"
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
using std::ofstream;
void trimesh::load(const std::string filename)
{
std::ifstream file(filename);
if (file.is_open())
{
std::string line;
while (std::getline(file, line))
{
// using printf() in all tests for consistency
//printf("%s", line.c_str());
istringstream in(line);
vector<string> vec_line;
string line_s;
while (in >> line_s)
{
vec_line.push_back(line_s);
}
//std::cout << "vec_line:" << vec_line[0] << std::endl;
std::vector<double> double_line;
std::vector<double> double_line_color;
std::vector<unsigned int> unint_line;
std::vector<unsigned int> unint_line_tc;
if (vec_line[0]=="v")
{
double v0 = std::stod(vec_line[1]);
double v1 = std::stod(vec_line[2]);
double v2 = std::stod(vec_line[3]);
double_line.push_back(v0);
double_line.push_back(v1);
double_line.push_back(v2);
vertices.push_back(double_line);
double_line.clear();
if (vec_line.size()==7)
{
double c1 = std::stod(vec_line[4]);
double c2 = std::stod(vec_line[5]);
double c3 = std::stod(vec_line[6]);
double_line_color.push_back(c1);
double_line_color.push_back(c2);
double_line_color.push_back(c3);
vert_color.push_back(double_line_color);
double_line_color.clear();
}
}
else if (vec_line[0]=="vt")
{
double vt0 = std::stod(vec_line[1]);
double vt1 = std::stod(vec_line[2]);
double_line.push_back(vt0);
double_line.push_back(vt1);
tex_coords.push_back(double_line);
double_line.clear();
}
else if (vec_line[0]=="f")
{
size_t idx1 = vec_line[1].find("/");
unsigned int v_idx_f_1 = std::stod(vec_line[1].substr(0, idx1));
size_t idx2 = vec_line[1].find("/", idx1 + 1);
unsigned int v_idx_ftc_1 = std::stod(vec_line[1].substr(idx1 + 1, idx2));
size_t idx3 = vec_line[2].find("/");
unsigned int v_idx_f_2 = std::stod(vec_line[2].substr(0, idx3));
size_t idx4 = vec_line[2].find("/", idx3 + 1);
unsigned int v_idx_ftc_2 = std::stod(vec_line[2].substr(idx3 + 1, idx4));
size_t idx5 = vec_line[3].find("/");
unsigned int v_idx_f_3 = std::stod(vec_line[3].substr(0, idx5));
size_t idx6 = vec_line[3].find("/", idx5 + 1);
unsigned int v_idx_ftc_3 = std::stod(vec_line[3].substr(idx5 + 1, idx6));
unint_line.push_back(v_idx_f_1);
unint_line.push_back(v_idx_f_2);
unint_line.push_back(v_idx_f_3);
faces.push_back(unint_line);
unint_line_tc.push_back(v_idx_ftc_1);
unint_line_tc.push_back(v_idx_ftc_2);
unint_line_tc.push_back(v_idx_ftc_3);
faces_tc.push_back(unint_line_tc);
}
}
file.close();
}
else
{
printf ("loading obj: %s doesn't exists!\n", filename.c_str());
throw;
}
}
void trimesh::save(const std::string save_path, const bool with_color, const bool with_vt)
{
ofstream outdata;
outdata.open(save_path);
if( !outdata )
{ // file couldn't be opened
std::cout << "Error: file could not be opened" << std::endl;
exit(1);
}
if (with_color && (vertices.size()==vert_color.size())) //write the vertices and colors
{
for (size_t i=0; i<vertices.size(); i++)
{
outdata << "v ";
outdata << vertices[i][0] << " " << vertices[i][1] << " " << vertices[i][2] << " " << vert_color[i][0] << " " << vert_color[i][1] << " " << vert_color[i][2] <<endl;
}
}
else // only write the vertices
{
for (size_t i = 0; i < vertices.size(); i++)
{
outdata << "v ";
outdata << vertices[i][0] << " " << vertices[i][1] << " " << vertices[i][2]<<endl;
}
}
if (with_vt)
{
for (size_t j=0; j<tex_coords.size(); j++)
{
outdata << "vt ";
outdata << tex_coords[j][0] << " " << tex_coords[j][1] << endl;
}
}
if (faces.size() == faces_tc.size())
{
for (size_t k = 0; k < faces.size(); k++)
{
outdata << "f ";
outdata << faces[k][0] << "/" << faces_tc[k][0] << " " << faces[k][1] << "/" << faces[k][1] << " " << faces[k][2] << "/" << faces_tc[k][2] <<endl;
}
}
else
{
for (size_t k = 0; k < faces.size(); k++)
{
outdata << "f ";
outdata << faces[k][0] << " " << faces[k][1] << " " << faces[k][2] << endl;
}
}
outdata.close();
}