Program Listing for File mesh.cc¶
↰ Return to documentation for file (src/mesh.cc
)
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* The ENVE project *
* *
* Copyright (c) 2020, Davide Stocco and Enrico Bertolazzi. *
* *
* The ENVE project and its components are supplied under the terms of *
* the open source BSD 3-Clause License. The contents of the ENVE *
* project and its components may not be copied or disclosed except in *
* accordance with the terms of the BSD 3-Clause License. *
* *
* URL: https://opensource.org/licenses/BSD-3-Clause *
* *
* Davide Stocco *
* Department of Industrial Engineering *
* University of Trento *
* e-mail: davide.stocco@unitn.it *
* *
* Enrico Bertolazzi *
* Department of Industrial Engineering *
* University of Trento *
* e-mail: enrico.bertolazzi@unitn.it *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#include "enve.hh"
namespace enve
{
namespace ground
{
/*\
| _
| _ __ ___ ___ ___| |__
| | '_ ` _ \ / _ \/ __| '_ \
| | | | | | | __/\__ \ | | |
| |_| |_| |_|\___||___/_| |_|
|
\*/
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mesh::mesh(void)
: m_AABBtree(std::make_shared<AABBtree>())
{
this->m_triangles.reserve(100000);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mesh::mesh(
triangleground::vecptr const & triangles
)
: mesh()
{
this->m_triangles = triangles;
this->buildAABBtree();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mesh::mesh(
std::string const & path
)
: mesh()
{
#define CMD "enve::mesh::mesh(...): "
ENVE_ASSERT(this->load(path),
CMD "error while reading file.");
#undef CMD
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mesh::mesh(
std::string const & path,
real friction
)
: mesh()
{
#define CMD "enve::mesh::mesh(...): "
ENVE_ASSERT(this->load(path, friction),
CMD "error while reading file.");
#undef CMD
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
mesh::copy(
mesh const & mesh_obj
)
{
this->m_triangles = mesh_obj.m_triangles;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
mesh::clear(void)
{
if (!this->m_triangles.empty())
{
for (size_t i = 0; i < this->size(); ++i)
{this->m_triangles[i].reset();}
}
this->m_triangles.clear();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
triangleground::vecptr const &
mesh::vecptrTriangleground(void)
const
{
return this->m_triangles;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
triangleground::ptr
mesh::ptrTriangleground(
size_t i
)
const
{
return this->m_triangles[i];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
triangleground::ptr
mesh::operator[](
size_t i
)
const
{
return this->m_triangles[i];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
mesh::print(
std::string const & path
)
const
{
// Create Out.txt
std::ofstream file(path);
// Print introduction
file
<< "MESH DATA" << std::endl
<< std::endl
<< "Legend:" << std::endl
<< "T : i-th triangle position" << std::endl
<< "V0 : triangle vertex 0" << std::endl
<< "V1 : triangle vertex 1" << std::endl
<< "V2 : triangle vertex 2" << std::endl
<< "N : normal to the face" << std::endl
<< "F : friction coefficient" << std::endl
<< std::endl;
for (size_t i = 0; i < this->m_triangles.size(); ++i)
{
triangleground const & Ti = *this->m_triangles[i];
point const & V0 = Ti.triangle::vertex(0);
point const & V1 = Ti.triangle::vertex(1);
point const & V2 = Ti.triangle::vertex(2);
vec3 const & N = Ti.normal();
real const & F = Ti.friction();
// Print vertices, normal and friction
file
<< "T = " << i << std::endl
<< "V0 = " << V0 << std::endl
<< "V1 = " << V1 << std::endl
<< "V2 = " << V2 << std::endl
<< "N = " << N << std::endl
<< "F = " << F << std::endl
<< std::endl;
}
// Close File
file.close();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
size_t
mesh::size(void)
const
{
return this->m_triangles.size();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool
mesh::load(
std::string const & path
)
{
#define CMD "enve::ground::load(...): "
// Start loading mesh
std::cout << "Loading *.rdf mesh... ";
// Check if the file is an ".rdf" file
if (path.substr(path.size() - 4, 4) != ".rdf")
{
std::cout << "Failed" << std::endl;
ENVE_ERROR(CMD "not a *.rdf file.");
//return false;
}
// Check if the file had been correctly open
std::ifstream file(path);
if (!file.is_open())
{
std::cout << "Failed" << std::endl;
ENVE_ERROR(CMD "*.rdf file not opened.");
//return false;
}
// Vector for nodes coordinates
std::vector<point> nodes;
nodes.reserve(25000);
this->m_triangles.reserve(100000);
size_t nodes_count = size_t(0);
size_t elements_count = size_t(0);
bool nodes_parse = false;
bool elements_parse = false;
// Instantiate temporaries
std::string curline, token;
std::vector<std::string> s_node;
s_node.reserve(4);
point p_node;
std::vector<integer> i_element(3);
real i_friction;
while (std::getline(file, curline))
{
token = this->firstToken(curline);
if (token == "[NODES]" || token == "NODES")
{
nodes_parse = true;
elements_parse = false;
continue;
}
else if (token == "[ELEMENTS]" || token == "ELEMENTS")
{
nodes_parse = false;
elements_parse = true;
continue;
}
else if (token[0] == '{')
{
// Multi-line comment, should read until '}' - NOT IMPLEMENTED
// Treated as a sigle-line comment
continue;
}
else if (token[0] == '%' || token[0] == '#' || token[0] == '\r')
{
// Check comments or empty lines
continue;
}
// Generate a vertex position
if (nodes_parse)
{
this->split(this->tail(curline), s_node, " ");
ENVE_ASSERT(s_node.size() == size_t(3),
CMD "wrong numbder of elements detected.");
p_node[0] = real(std::stod(s_node[0]));
p_node[1] = real(std::stod(s_node[1]));
p_node[2] = real(std::stod(s_node[2]));
nodes.push_back(p_node);
++nodes_count;
}
// Generate a face (vertices & indices)
if (elements_parse)
{
// Generate the triangle vertices from the element
this->split(curline, s_node, " ");
ENVE_ASSERT(s_node.size() == size_t(4),
CMD "wrong numbder of elements detected.");
i_element[0] = integer(std::stoi(s_node[0]));
i_element[1] = integer(std::stoi(s_node[1]));
i_element[2] = integer(std::stoi(s_node[2]));
i_friction = real(std::stod(s_node[3]));
ENVE_ASSERT(i_element[0] >= integer(0),
CMD "element 0 index cannot be negative.");
ENVE_ASSERT(i_element[1] >= integer(0),
CMD "element 1 index cannot be negative.");
ENVE_ASSERT(i_element[2] >= integer(0),
CMD "element 2 index cannot be negative.");
ENVE_ASSERT(i_friction >= real(0.0),
CMD "element friction cannot be negative.");
// Create a shared pointer for the last triangle
this->m_triangles.push_back(
std::make_shared<triangleground const>(
elements_count, i_friction,
nodes[i_element[0]], nodes[i_element[1]], nodes[i_element[2]]
));
++elements_count;
continue;
}
}
std::cout
<< "Done" << std::endl;
// Perform safety check
ENVE_ASSERT(nodes.size() == nodes_count && this->m_triangles.size() == elements_count,
CMD "safety check not passed.");
file.close();
if (this->m_triangles.empty())
{
ENVE_ERROR(CMD "*.rdf loaded mesh is empty.");
//return false;
}
else
{
// Update the local intersected triangles list
std::cout
<< "Building AABB tree... ";
this->buildAABBtree();
std::cout
<< "Done" << std::endl
<< std::endl;
return true;
}
#undef CMD
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool
mesh::load(
std::string const & path,
real friction
)
{
#define CMD "enve::ground::load(...): "
// Start loading mesh
std::cout << "Loading *.obj mesh... ";
// Check if the file is an ".obj" file
if (path.substr(path.size() - 4, 4) != ".obj")
{
std::cout << "Failed" << std::endl;
ENVE_ERROR(CMD "not a *.obj file.");
//return false;
}
// Check if the file had been correctly open
std::ifstream file(path);
if (!file.is_open())
{
std::cout << "Failed" << std::endl;
ENVE_ERROR(CMD "*.obj file not opened.");
//return false;
}
// Vector for nodes coordinates
std::vector<point> nodes;
nodes.reserve(25000);
this->m_triangles.reserve(100000);
size_t nodes_count = size_t(0);
size_t elements_count = size_t(0);
// Instantiate temporaries
std::string curline, token;
std::vector<std::string> s_node;
s_node.reserve(4);
std::vector<integer> i_element(3);
point p_node;
while (std::getline(file, curline))
{
token = this->firstToken(curline);
if (token == "v")
{
// Generate a vertex position
this->split(this->tail(curline), s_node, " ");
ENVE_ASSERT(s_node.size() == size_t(3),
CMD "wrong numbder of elements detected.");
p_node[0] = std::stod(s_node[0]);
p_node[1] = std::stod(s_node[1]);
p_node[2] = std::stod(s_node[2]);
nodes.push_back(p_node);
++nodes_count;
continue;
}
else if (token == "f")
{
// Generate the triangle vertices from the element
this->split(this->tail(curline), s_node, " ");
ENVE_ASSERT(s_node.size() == size_t(3),
CMD "wrong numbder of elements detected.");
i_element[0] = std::stoi(s_node[0]) - 1;
i_element[1] = std::stoi(s_node[1]) - 1;
i_element[2] = std::stoi(s_node[2]) - 1;
ENVE_ASSERT(i_element[0] >= integer(0),
CMD "element 0 index cannot be negative.");
ENVE_ASSERT(i_element[1] >= integer(0),
CMD "element 1 index cannot be negative.");
ENVE_ASSERT(i_element[2] >= integer(0),
CMD "element 2 index cannot be negative.");
// Create a shared pointer for the last triangle
this->m_triangles.push_back(
std::make_shared<triangleground const>(
elements_count, friction,
nodes[i_element[0]], nodes[i_element[1]], nodes[i_element[2]]
));
++elements_count;
continue;
}
else if (token[0] == '%' || token[0] == '#' || token[0] == '\r')
{
// Check comments or empty lines
continue;
}
}
std::cout
<< "Done" << std::endl;
// Perform safety check
ENVE_ASSERT(nodes.size() == nodes_count && this->m_triangles.size() == elements_count,
CMD "safety check not passed.");
file.close();
if (this->m_triangles.empty())
{
ENVE_ERROR(CMD "*.obj loaded mesh is empty.");
//return false;
}
else
{
// Update the local intersected triangles list
std::cout << "Building AABB tree... ";
this->buildAABBtree();
std::cout
<< "Done" << std::endl
<< std::endl;
return true;
}
#undef CMD
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool
mesh::intersection(
aabb::ptr const box,
triangleground::vecptr & triangles
)
const
{
#define CMD "enve::mesh::intersection(...): "
aabb::vecptr ptrVecbox{box};
AABBtree::ptr ptrAABBtree = std::make_shared<AABBtree>();
ptrAABBtree->build(ptrVecbox);
triangles.clear();
aabb::vecpairptr intersection_list;
this->m_AABBtree->intersection(*ptrAABBtree, intersection_list);
for (size_t i = 0; i < intersection_list.size(); ++i)
{
triangles.emplace_back(
this->ptrTriangleground((intersection_list[i].first)->id())
);
}
return triangles.size() > integer(0);
#undef CMD
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
mesh::buildAABBtree(void)
{
#define CMD "enve::mesh::buildAABBtree(...): "
this->updateBBoxes();
this->m_AABBtree->build(this->m_bboxes);
#undef CMD
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
mesh::updateBBoxes(void)
{
this->m_bboxes.clear();
for (size_t i = 0; i < this->m_triangles.size(); ++i)
{
this->m_bboxes.push_back(
std::make_shared<aabb const>(this->m_triangles[i]->bbox())
);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
mesh::split(
std::string const & in,
std::vector<std::string> & out,
std::string const & token
)
const
{
std::string tmp, test;
out.clear();
for (size_t i = 0; i < in.size(); ++i)
{
test = in.substr(i, token.size());
if (test == token)
{
if (!tmp.empty())
{
out.push_back(tmp);
tmp.clear();
i += token.size() - 1;
}
}
else if (i + token.size() >= in.size())
{
tmp += in.substr(i, token.size());
out.push_back(tmp);
break;
}
else
{
tmp += in[i];
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::string
mesh::tail(
std::string const & in
)
const
{
size_t token_start = in.find_first_not_of(" \t");
size_t space_start = in.find_first_of(" \t", token_start);
size_t tail_start = in.find_first_not_of(" \t", space_start);
size_t tail_end = in.find_last_not_of(" \t");
if (tail_start != std::string::npos && tail_end != std::string::npos)
{return in.substr(tail_start, tail_end - tail_start + 1);}
else if (tail_start != std::string::npos)
{return in.substr(tail_start);}
return "";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::string
mesh::firstToken(
std::string const & in
)
const
{
if (!in.empty())
{
size_t token_start = in.find_first_not_of(" \t\r\n");
if (token_start != std::string::npos)
{
size_t token_end = in.find_first_of(" \t\r\n", token_start);
if (token_end != std::string::npos)
{return in.substr(token_start, token_end - token_start);}
else
{return in.substr(token_start);}
}
}
return "";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
} // namespace rdf
} // namespace enve
#endif