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.
 
 
 
 
 
 

1422 lines
33 KiB

#define _CRT_SECURE_NO_WARNINGS
#include "Mesh3D.h"
#include <list>
namespace MeshLib
{
//////////////////////////////////////////////////////////////////////////
template <typename Real>
Mesh3D<Real>::Mesh3D(void)
{
//initialization
vertices_list = NULL;
faces_list = NULL;
edges_list = NULL;
xmax = ymax = zmax = (Real)1.0;
xmin = ymin = zmin = (Real) - 1.0;
m_closed = true;
m_quad = false;
m_tri = false;
m_hex = false;
m_pentagon = false;
m_num_components = 0;
m_num_boundaries = 0;
m_genus = 0;
m_encounter_non_manifold = false;
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
Mesh3D<Real>::~Mesh3D(void)
{
clear_data();
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::clear_data()
{
clear_vertices();
clear_edges();
clear_faces();
normal_array.resize(0);
texture_array.resize(0);
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::clear_vertices()
{
if (vertices_list == NULL)
{ return; }
for (VERTEX_ITER viter = vertices_list->begin(); viter != vertices_list->end(); viter++)
{ delete *viter; }
delete vertices_list;
vertices_list = NULL;
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::clear_edges()
{
m_edgemap.clear();
if (edges_list == NULL)
{ return; }
for (EDGE_ITER eiter = edges_list->begin(); eiter != edges_list->end(); eiter++)
{ delete *eiter; }
delete edges_list;
edges_list = NULL;
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::clear_faces()
{
if (faces_list == NULL)
{ return; }
for (FACE_ITER fiter = faces_list->begin(); fiter != faces_list->end(); fiter++)
{ delete *fiter; }
delete faces_list;
faces_list = NULL;
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
HE_vert<Real> *Mesh3D<Real>::insert_vertex(const TinyVector<Real, 3> &v)
{
HE_vert<Real> *hv = new HE_vert<Real>(v);
if (vertices_list == NULL)
{ vertices_list = new VERTEX_LIST; }
hv->id = (ptrdiff_t)vertices_list->size();
vertices_list->push_back(hv);
return hv;
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
HE_face<Real> *Mesh3D<Real>::insert_face(VERTEX_LIST &vec_hv, std::vector<ptrdiff_t> *texture, std::vector<ptrdiff_t> *normal)
{
int vsize = (int)vec_hv.size();
if (vsize < 3)
{ return NULL; }
//////////////////////////////////////////////////////////////////////////
//detect non-manifold
bool b_find = false;
for (int i = 0; i < vsize; i++)
{
HE_edge<Real> *c_he = m_edgemap[PAIR_VERTEX(vec_hv[i], vec_hv[(i + 1) % vsize])];
if (c_he && c_he->face)
{
//detect nonmanifold
b_find = true;
break;
}
}
if (b_find)
{
m_encounter_non_manifold = true;
//guess there are faces with reverse orientation, try to reverse them.
//If these faces are inserted after their neighbor faces which have correct orientation,
//probably we can obtain correct meshes.
for (int i = 0; i < vsize; i++)
{
HE_edge<Real> *c_he = m_edgemap[PAIR_VERTEX(vec_hv[(i + 1) % vsize], vec_hv[i])];
if (c_he && c_he->face)
{
return NULL;
}
}
//it seems fine, reverse the vector.
std::reverse(vec_hv.begin(), vec_hv.end());
if (texture)
{
std::reverse(texture->begin(), texture->end());
}
if (normal)
{
std::reverse(normal->begin(), normal->end());
}
}
//////////////////////////////////////////////////////////////////////////
if (faces_list == NULL)
{ faces_list = new FACE_LIST; }
HE_face<Real> *hf = new HE_face<Real>;
hf->valence = vsize;
VERTEX_ITER viter = vec_hv.begin();
VERTEX_ITER nviter = vec_hv.begin();
nviter++;
HE_edge<Real> *he1, *he2;
std::vector<HE_edge<Real>* > v_he;
int i;
for (i = 0; i < vsize - 1; i++)
{
he1 = insert_edge( *viter, *nviter);
he2 = insert_edge( *nviter, *viter);
if (hf->edge == NULL)
{ hf->edge = he1; }
he1->face = hf;
he1->pair = he2;
he2->pair = he1;
v_he.push_back(he1);
viter++, nviter++;
}
nviter = vec_hv.begin();
he1 = insert_edge(*viter, *nviter);
he2 = insert_edge(*nviter , *viter);
he1->face = hf;
if (hf->edge == NULL)
{ hf->edge = he1; }
he1->pair = he2;
he2->pair = he1;
v_he.push_back(he1);
for (i = 0; i < vsize - 1; i++)
{
v_he[i]->next = v_he[i + 1];
v_he[i + 1]->prev = v_he[i];
}
v_he[i]->next = v_he[0];
v_he[0]->prev = v_he[i];
hf->id = (int)faces_list->size();
faces_list->push_back(hf);
if (texture)
{
hf->texture_indices.resize(texture->size());
std::copy(texture->begin(), texture->end(), hf->texture_indices.begin());
}
if (normal)
{
hf->normal_indices.resize(normal->size());
std::copy(normal->begin(), normal->end(), hf->normal_indices.begin());
}
return hf;
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
HE_edge<Real> *Mesh3D<Real>::insert_edge(HE_vert<Real> *vstart, HE_vert<Real> *vend)
{
if (vstart == NULL || vend == NULL)
{
return NULL;
}
if (edges_list == NULL)
{ edges_list = new EDGE_LIST; }
if( m_edgemap[PAIR_VERTEX(vstart, vend)] != NULL )
{ return m_edgemap[PAIR_VERTEX(vstart, vend)]; }
HE_edge<Real> *he = new HE_edge<Real>;
he->vert = vend;
he->vert->degree++;
vstart->edge = he;
m_edgemap[PAIR_VERTEX(vstart, vend)] = he;
he->id = (int)edges_list->size();
edges_list->push_back(he);
return he;
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::set_nextedge_for_border_vertices()
{
if (!is_valid())
{ return; }
EDGE_ITER eiter = edges_list->begin();
for (; eiter != edges_list->end(); eiter++)
{
if ((*eiter)->next == NULL && (*eiter)->face == NULL)
{ (*eiter)->pair->vert->edge = *eiter; }
}
for (eiter = edges_list->begin(); eiter != edges_list->end(); eiter++)
{
if ( (*eiter)->next == NULL )
{
HE_vert<Real> *hv = (*eiter)->vert;
if (hv->edge != (*eiter)->pair)
{
(*eiter)->next = hv->edge;
hv->edge->prev = *eiter;
}
}
}
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
bool Mesh3D<Real>::is_on_boundary(HE_vert<Real> *hv)
{
HE_edge<Real> *edge = hv->edge;
do
{
if (edge == NULL || edge->pair->face == NULL || edge->face == NULL)
{ return true; }
edge = edge->pair->next;
}
while (edge != hv->edge);
return false;
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
bool Mesh3D<Real>::is_on_boundary(HE_face<Real> *hf)
{
HE_edge<Real> *edge = hf->edge;
do
{
if (is_on_boundary(edge))
{ return true; }
edge = edge->next;
}
while (edge != hf->edge);
return false;
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
bool Mesh3D<Real>::is_on_boundary(HE_edge<Real> *he)
{
if(he->face == NULL || he->pair->face == NULL)
{ return true; }
return false;
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::check_closed()
{
m_closed = true;
VERTEX_ITER viter = vertices_list->begin();
for (; viter != vertices_list->end(); viter++)
{
if (is_on_boundary(*viter))
{
m_closed = false;
return;
}
}
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::check_meshtype()
{
if (get_num_of_faces() == 0)
{
m_tri = false;
m_quad = false;
m_hex = false;
return;
}
FACE_ITER fiter = faces_list->begin();
m_tri = true;
m_quad = true;
m_hex = true;
m_pentagon = true;
for (; fiter != faces_list->end(); fiter++)
{
int d = (*fiter)->valence;
if (d != 3)
{
m_tri = false;
}
if (d != 4)
{
m_quad = false;
}
if (d != 5)
{
m_pentagon = false;
}
if (d != 6)
{
m_hex = false;
}
}
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::update_mesh()
{
if (!is_valid())
{ return; }
//comment on 20200921
//remove_hanged_vertices();
set_nextedge_for_border_vertices();
check_closed();
check_meshtype();
m_edgemap.clear();
update_normal();
compute_boundingbox();
//comment on 20200921
//compute_genus();
}
//////////////////////////////////////////////////////////////////////////
//FILE IO
//////////////////////////////////////////////////////////////////////////
template <typename Real>
bool Mesh3D<Real>::load_off(const char *fins)
{
std::ifstream fin(fins);
try
{
clear_data();
int vsize, fsize, esize;
std::string head;
fin >> head;
if (head == "OFF")
{
}
else
{ return false; }
fin >> vsize >> fsize >> esize;
Real x, y, z;
for (int i = 0; i < vsize; i++)
{
fin >> x >> y >> z;
TinyVector<Real, 3> nvv(x, y, z) ;
insert_vertex(nvv);
}
for (int i = 0; i < fsize; i++)
{
VERTEX_LIST v_list;
int valence;
fin >> valence;
for (int j = 0; j < valence; j++)
{
int id;
fin >> id;
HE_vert<Real> *hv = get_vertex(id);
bool findit = false;
for (int i = 0; i < (int) v_list.size(); i++)
{
if (hv == v_list[i])
{
findit = true;
break;
}
}
if (findit == false && hv != NULL)
{
v_list.push_back(hv);
}
}
if ((int)v_list.size() >= 3)
{
insert_face(v_list);
}
}
update_mesh();
}
catch (...)
{
//catch any error
clear_data();
xmax = ymax = zmax = (Real)1.0;
xmin = ymin = zmin = (Real) - 1.0;
fin.close();
return false;
}
fin.close();
return is_valid();
}
template <typename Real>
void Mesh3D<Real>::load_mesh(const std::vector<std::array<double, 3>>& pos, const std::vector<std::vector<size_t>>& indices)
{
clear_data();
int vsize, fsize, esize;
//fin >> vsize >> fsize >> esize;
vsize = pos.size();
fsize = indices.size();
Real x, y, z;
for (int i = 0; i < vsize; i++)
{
//fin >> x >> y >> z;
x = pos[i][0];
y = pos[i][1];
z = pos[i][2];
TinyVector<Real, 3> nvv(x, y, z);
insert_vertex(nvv);
}
for (int i = 0; i < fsize; i++)
{
VERTEX_LIST v_list;
int valence = indices[i].size();
//fin >> valence;
for (int j = 0; j < valence; j++)
{
int id = indices[i][j];
HE_vert<Real>* hv = get_vertex(id);
bool findit = false;
for (int i = 0; i < (int)v_list.size(); i++)
{
if (hv == v_list[i])
{
findit = true;
break;
}
}
if (findit == false && hv != NULL)
{
v_list.push_back(hv);
}
}
if ((int)v_list.size() >= 3)
{
insert_face(v_list);
}
}
update_mesh();
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::write_off(const char *fouts)
{
std::ofstream fout(fouts);
fout.precision(16);
fout << "OFF\n";
//output the number of vertices_list, faces_list-> edges_list
fout << (int)vertices_list->size() << " " << (int)faces_list->size() << " " << (int)edges_list->size() / 2 << "\n";
//output coordinates of each vertex
VERTEX_ITER viter = vertices_list->begin();
for (; viter != vertices_list->end(); viter++)
{
fout << std::scientific << (*viter)->pos << "\n";
}
//output the valence of each face and its vertices_list' id
FACE_ITER fiter = faces_list->begin();
for (; fiter != faces_list->end(); fiter++)
{
fout << (*fiter)->valence;
HE_edge<Real> *edge = (*fiter)->edge;
do
{
fout << " " << edge->pair->vert->id;
edge = edge->next;
}
while (edge != (*fiter)->edge);
fout << "\n";
}
fout.close();
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
bool Mesh3D<Real>::load_obj(const char *fins)
{
FILE *m_pFile = fopen(fins, "r");
char *tok;
char temp[128];
groupname.clear();
std::vector<int> group_idlist;
try
{
clear_data();
//read vertices
fseek(m_pFile, 0, SEEK_SET);
char pLine[512];
while(fgets(pLine, 512, m_pFile))
{
if(pLine[0] == 'v' && pLine[1] == ' ')
{
TinyVector<Real, 3> nvv;
tok = strtok(pLine, " ");
for (int i = 0; i < 3; i++)
{
tok = strtok(NULL, " ");
strcpy(temp, tok);
temp[strcspn(temp, " ")] = 0;
nvv[i] = (Real)atof(temp);
}
insert_vertex(nvv);
}
else if(pLine[0] == 'v' && pLine[1] == 't')
{
TinyVector<float, 2> nvv;
tok = strtok(pLine, " ");
for (int i = 0; i < 2; i++)
{
tok = strtok(NULL, " ");
strcpy(temp, tok);
temp[strcspn(temp, " ")] = 0;
nvv[i] = (float)atof(temp);
}
texture_array.push_back(nvv);
}
else if(pLine[0] == 'v' && pLine[1] == 'n')
{
TinyVector<float, 3> nvv;
tok = strtok(pLine, " ");
for (int i = 0; i < 3; i++)
{
tok = strtok(NULL, " ");
strcpy(temp, tok);
temp[strcspn(temp, " ")] = 0;
nvv[i] = (float)atof(temp);
}
normal_array.push_back(nvv);
}
else if (pLine[0] == 'g')
{
tok = strtok(&pLine[1], " ");
strcpy(temp, tok);
std::string gname(temp, strlen(temp) - 1);
bool find = false;
for (size_t i = 0; i < groupname.size(); i++)
{
if (gname.compare(groupname[i]) == 0)
{
group_idlist.push_back((int)i);
find = true;
break;
}
}
if (!find)
{
group_idlist.push_back((int)groupname.size());
groupname.push_back(gname);
}
}
}
//read facets
fseek(m_pFile, 0, SEEK_SET);
int group_counter = -1;
while(fgets(pLine, 512, m_pFile))
{
char *pTmp = pLine;
if(pTmp[0] == 'f')
{
VERTEX_LIST s_faceid;
std::vector<ptrdiff_t> normal_ind, texture_ind;
tok = strtok(pLine, " ");
while ((tok = strtok(NULL, " ")) != NULL)
{
strcpy(temp, tok);
size_t len = strlen(temp);
int start_pos = 0;
int pos[2] = { -1, -1};
for (int k = 0; k < (int)len; k++)
{
if (temp[k] == '/')
{
pos[start_pos] = k;
start_pos++;
}
}
size_t end_pos = len;
if (start_pos == 1)
{
end_pos = pos[0];
std::string mstr(&temp[pos[0] + 1], len - pos[0] - 1);
int id = (int)strtol(mstr.c_str(), NULL, 10) - 1;
texture_ind.push_back(id);
}
else if (start_pos == 2)
{
end_pos = pos[0];
if (pos[0] + 1 != pos[1])
{
std::string mstr(&temp[pos[0] + 1], pos[1] - pos[0] - 1);
int id = (int)strtol(mstr.c_str(), NULL, 10) - 1;
texture_ind.push_back(id);
}
std::string mstr2(&temp[pos[1] + 1], len - pos[1] - 1);
int id2 = (int)strtol(mstr2.c_str(), NULL, 10) - 1;
normal_ind.push_back(id2);
}
std::string mstr(&temp[0], end_pos);
int id = (int)strtol(mstr.c_str(), NULL, 10) - 1;
HE_vert<Real> *hv = get_vertex(id);
bool findit = false;
for (int i = 0; i < (int) s_faceid.size(); i++)
{
if (hv == s_faceid[i]) //remove the redundant vertex id if it exists
{
findit = true;
break;
}
}
if (findit == false && hv != NULL)
{
s_faceid.push_back(hv);
}
}
if (s_faceid.size() >= 3)
{
HE_face<Real> *hf = insert_face(s_faceid, texture_ind.size() == s_faceid.size() ? &texture_ind : 0, normal_ind.size() == s_faceid.size() ? &normal_ind : 0);
hf->groupid = group_counter == -1 ? -1 : group_idlist[group_counter];
}
}
else if(pTmp[0] == 'g')
{
group_counter++;
}
}
update_mesh();
}
catch (...)
{
clear_data();
xmax = ymax = zmax = (Real)1.0;
xmin = ymin = zmin = (Real) - 1.0;
fclose(m_pFile);
return false;
}
fclose(m_pFile);
return is_valid();
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::write_obj(const char *fouts)
{
std::ofstream fout(fouts);
if (groupname.empty())
{ fout << "g object\n"; }
//fout.precision(16);
//output coordinates of each vertex
VERTEX_ITER viter = vertices_list->begin();
std::map<ptrdiff_t, ptrdiff_t> vmap;
ptrdiff_t count = 1;
for (; viter != vertices_list->end(); viter++)
{
fout << "v "/*<< std::scientific*/ << (*viter)->pos << "\n";
vmap[(*viter)->id] = count;
count++;
}
if (!normal_array.empty())
{
for (size_t i = 0; i < normal_array.size(); i++)
{
fout << "vn "/*<< std::scientific*/ << normal_array[i] << "\n";
}
}
else
{
for (viter = vertices_list->begin(); viter != vertices_list->end(); viter++)
{
fout << "vn "/*<< std::scientific*/ << (*viter)->normal << "\n";
}
}
if (!texture_array.empty())
{
for (size_t i = 0; i < texture_array.size(); i++)
{
fout << "vt " << std::scientific << texture_array[i] << "\n";
}
}
//output the valence of each face and its vertices_list' id
int last_groupid = -1;
FACE_ITER fiter = faces_list->begin();
for (; fiter != faces_list->end(); fiter++)
{
if ((*fiter)->groupid != -1)
{
if (last_groupid != (*fiter)->groupid )
{
last_groupid = (*fiter)->groupid;
fout << "g " << groupname[last_groupid] << std::endl;
}
}
fout << "f";
HE_edge<Real> *edge = (*fiter)->edge;
unsigned int count = 0;
do
{
fout << " " << vmap[edge->pair->vert->id];
if ((*fiter)->has_texture_map())
{
fout << "/" << (*fiter)->texture_indices[count] + 1;
}
else
{ fout << "/"; }
if ((*fiter)->has_normal_map())
{
fout << "/" << (*fiter)->normal_indices[count] + 1;
}
else
{ fout << "/" << edge->pair->vert->id + 1; }
edge = edge->next;
}
while (edge != (*fiter)->edge);
fout << "\n";
}
fout.close();
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::write_vtk(const char *fouts)
{
std::ofstream fout(fouts);
fout.precision(16);
fout << "# vtk DataFile Version 3.0\n"
<< "Polygonal Mesh\n"
<< "ASCII\n"
<< "DATASET POLYDATA\n"
<< "POINTS " << vertices_list->size() << " double\n";
//output coordinates of each vertex
VERTEX_ITER viter = vertices_list->begin();
for (; viter != vertices_list->end(); viter++)
{
fout << std::scientific << (*viter)->pos << "\n";
}
FACE_ITER fiter = faces_list->begin();
size_t count = 0;
for (; fiter != faces_list->end(); fiter++)
{
count += (*fiter)->valence + 1;
}
fout << "POLYGONS " << faces_list->size() << " " << count << "\n";
//output the valence of each face and its vertices_list' id
fiter = faces_list->begin();
for (; fiter != faces_list->end(); fiter++)
{
fout << (*fiter)->valence;
HE_edge<Real> *edge = (*fiter)->edge;
do
{
fout << " " << edge->pair->vert->id;
edge = edge->next;
}
while (edge != (*fiter)->edge);
fout << "\n";
}
fout.close();
}
//////////////////////////////////////////////////////////////////////////
//For rendering
template <typename Real>
void Mesh3D<Real>::compute_boundingbox()
{
if (vertices_list->size() < 3)
{ return; }
xmax = ymax = zmax = (Real) - 10e10;
xmin = ymin = zmin = (Real)10e10;
VERTEX_ITER viter = vertices_list->begin();
for (; viter != vertices_list->end(); viter++)
{
xmin = (*viter)->pos[0] < xmin ? (*viter)->pos[0] : xmin;
ymin = (*viter)->pos[1] < ymin ? (*viter)->pos[1] : ymin;
zmin = (*viter)->pos[2] < zmin ? (*viter)->pos[2] : zmin;
xmax = (*viter)->pos[0] > xmax ? (*viter)->pos[0] : xmax;
ymax = (*viter)->pos[1] > ymax ? (*viter)->pos[1] : ymax;
zmax = (*viter)->pos[2] > zmax ? (*viter)->pos[2] : zmax;
}
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::compute_faces_list_normal()
{
for (FACE_ITER fiter = faces_list->begin(); fiter != faces_list->end(); fiter++)
{
compute_perface_normal(*fiter);
}
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::compute_perface_normal(HE_face<Real> *hf)
{
size_t i = 0;
HE_edge<Real> *pedge = hf->edge;
HE_edge<Real> *nedge = hf->edge->next;
hf->normal = TinyVector<Real, 3>(0, 0, 0);
for (i = 0; i < hf->valence; i++)
{
//cross product
HE_vert<Real> *p = pedge->vert;
HE_vert<Real> *c = pedge->next->vert;
HE_vert<Real> *n = nedge->next->vert;
TinyVector<Real, 3> pc, nc;
pc = p->pos - c->pos;
nc = n->pos - c->pos;
hf->normal -= pc.Cross(nc);
pedge = nedge;
nedge = nedge->next;
if (hf->valence == 3)
{
break;
}
}
hf->normal.Normalize();
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::compute_vertices_list_normal()
{
VERTEX_ITER viter = vertices_list->begin();
for (; viter != vertices_list->end(); viter++)
{
compute_pervertex_normal(*viter);
}
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::compute_pervertex_normal(HE_vert<Real> *hv)
{
HE_edge<Real> *edge = hv->edge;
if (edge == NULL)
{
hv->normal = TinyVector<Real, 3>(0, 0, 0);
return;
}
hv->normal = TinyVector<Real, 3>(0, 0, 0);
do
{
if (edge->face != NULL)
{
hv->normal += edge->face->normal;
}
edge = edge->pair->next;
}
while (edge != hv->edge);
hv->normal.Normalize();
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::update_normal(bool onlyupdate_facenormal)
{
compute_faces_list_normal();
if (onlyupdate_facenormal == false)
{
compute_vertices_list_normal();
}
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::copy_edge_id(ptrdiff_t edgeid, ptrdiff_t startid, ptrdiff_t endid, Mesh3D<Real> *mesh)
{
mesh->m_edgemap[PAIR_VERTEX( mesh->get_vertex(startid), mesh->get_vertex(endid))]->id = edgeid;
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
Mesh3D<Real> *Mesh3D<Real>::make_copy()
{
Mesh3D<Real> *new_mesh = new Mesh3D<Real>;
VERTEX_ITER viter = vertices_list->begin();
for (; viter != vertices_list->end(); viter++)
{
new_mesh->insert_vertex((*viter)->pos);
}
FACE_ITER fiter = faces_list->begin();
for (; fiter != faces_list->end(); fiter++)
{
HE_face<Real> *hf = *fiter;
HE_edge<Real> *edge = hf->edge;
VERTEX_LIST mvlist;
do
{
mvlist.push_back(new_mesh->get_vertex(edge->pair->vert->id));
edge = edge->next;
}
while(edge != hf->edge);
new_mesh->insert_face(mvlist, hf->texture_indices.empty() ? 0 : &hf->texture_indices, hf->normal_indices.empty() ? 0 : &hf->normal_indices);
}
for (EDGE_ITER eiter = edges_list->begin(); eiter != edges_list->end(); eiter++)
{
HE_edge<Real> *he = *eiter;
copy_edge_id(he->id, he->pair->vert->id, he->vert->id, new_mesh);
}
PTR_EDGE_LIST edgelist = new_mesh->get_edges_list();
std::sort(edgelist->begin(), edgelist->end(), CompareEdgeID<Real>);
new_mesh->update_mesh();
VERTEX_ITER cviter = new_mesh->get_vertices_list()->begin();
for (viter = vertices_list->begin(); viter != vertices_list->end(); viter++, cviter++)
{
(*cviter)->edge = new_mesh->get_edge((*viter)->edge->id);
}
FACE_ITER cfiter = new_mesh->get_faces_list()->begin();
for (fiter = faces_list->begin(); fiter != faces_list->end(); fiter++ , cfiter++)
{
(*cfiter)->edge = new_mesh->get_edge((*fiter)->edge->id);
}
new_mesh->set_normal_array(normal_array);
new_mesh->set_texture_array(texture_array);
return new_mesh;
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
Mesh3D<Real> *Mesh3D<Real>::reverse_orientation()
{
Mesh3D<Real> *new_mesh = new Mesh3D<Real>;
VERTEX_ITER viter = vertices_list->begin();
for (; viter != vertices_list->end(); viter++)
{
new_mesh->insert_vertex((*viter)->pos);
}
FACE_ITER fiter = faces_list->begin();
for (; fiter != faces_list->end(); fiter++)
{
HE_face<Real> *hf = *fiter;
HE_edge<Real> *edge = hf->edge;
VERTEX_LIST mvlist;
do
{
mvlist.push_back(new_mesh->get_vertex(edge->pair->vert->id));
edge = edge->next;
}
while(edge != hf->edge);
std::reverse(mvlist.begin(), mvlist.end());
new_mesh->insert_face(mvlist);
}
new_mesh->update_mesh();
return new_mesh;
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::compute_num_components()
{
FACE_ITER fiter = faces_list->begin();
for (; fiter != faces_list->end(); fiter++ )
{
(*fiter)->tag = false;
}
m_num_components = 0;
for (fiter = faces_list->begin(); fiter != faces_list->end(); fiter++ )
{
HE_face<Real> *hf = *fiter;
if (hf->tag == false)
{
m_num_components++;
std::queue<HE_face<Real>* > facets;
facets.push(hf);
hf->tag = true;
while (!facets.empty())
{
HE_face<Real> *pFacet = facets.front();
facets.pop();
pFacet->tag = true;
HE_edge<Real> *he = pFacet->edge;
do
{
if(he->pair->face != NULL && he->pair->face->tag == false)
{
facets.push(he->pair->face);
he->pair->face->tag = true;
HE_edge<Real> *vhe = he->vert->edge;
do
{
if (vhe->face && vhe->face->tag == false)
{
facets.push(vhe->face);
vhe->face->tag = true;
HE_edge<Real> *mvhe = vhe->vert->edge;
do
{
if (mvhe->face && mvhe->face->tag == false)
{
facets.push(mvhe->face);
mvhe->face->tag = true;
}
mvhe = mvhe->pair->next;
}
while(mvhe != vhe->vert->edge);
}
vhe = vhe->pair->next;
}
while(vhe != he->vert->edge);
}
he = he->next;
}
while(he != pFacet->edge);
he = pFacet->edge;
}
}
}
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::compute_num_boundaries()
{
//if the mesh is not manifold, this function may report the wrong number
VERTEX_ITER viter = vertices_list->begin();
for (; viter != vertices_list->end(); viter++ )
{
(*viter)->tag = false;
}
boundaryvertices.clear();
m_num_boundaries = 0;
for(viter = vertices_list->begin(); viter != vertices_list->end(); viter++)
{
HE_vert<Real> *hv = *viter;
if (is_on_boundary(hv) && hv->tag == false)
{
std::vector<HE_vert<Real>*> vedges;
vedges.push_back(hv);
m_num_boundaries++;
std::list<HE_vert<Real>* > vertices;
hv->tag = true;
vertices.push_front(hv);
while (!vertices.empty())
{
HE_vert<Real> *pVertex = vertices.front();
pVertex->tag = true;
vertices.pop_front();
HE_edge<Real> *he = pVertex->edge;
do
{
if (is_on_boundary(he) && is_on_boundary(he->vert) && he->vert->tag == false)
{
he->vert->tag = true;
vertices.push_front(he->vert);
vedges.push_back(he->vert);
}
he = he->pair->next;
}
while(he != pVertex->edge);
}
HE_vert<Real> *hvtmp = vedges[0];
vedges[0] = vedges[1];
vedges[1] = hvtmp;
boundaryvertices.push_back(vedges);
}
}
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::compute_genus()
{
compute_num_components();
compute_num_boundaries();
int c = m_num_components;
int b = m_num_boundaries;
ptrdiff_t v = get_num_of_vertices();
ptrdiff_t e = get_num_of_edges() / 2;
ptrdiff_t f = get_num_of_faces();
m_genus = (int)(2 * c + e - b - f - v) / 2;
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::remove_hanged_vertices()
{
bool find = false;
VERTEX_ITER viter = vertices_list->begin();
for (; viter != vertices_list->end(); viter++)
{
if ((*viter)->edge == NULL)
{
find = true;
break;
}
}
if (find)
{
VERTEX_LIST *new_vertices_list = new VERTEX_LIST;
int i = 0;
for (viter = vertices_list->begin(); viter != vertices_list->end(); viter++)
{
if ((*viter)->edge != NULL)
{
new_vertices_list->push_back(*viter);
(*viter)->id = i;
i++;
}
else
{ delete *viter; }
}
delete vertices_list;
vertices_list = new_vertices_list;
EDGE_LIST *new_edges_list = new EDGE_LIST;
i = 0;
for (EDGE_ITER eiter = edges_list->begin(); eiter != edges_list->end(); eiter++)
{
if ((*eiter)->face != NULL || (*eiter)->pair->face != NULL)
{
new_edges_list->push_back(*eiter);
(*eiter)->id = i;
i++;
}
else
{ delete *eiter; }
}
delete edges_list;
edges_list = new_edges_list;
}
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::reset_vertices_tag(bool tag_status)
{
VERTEX_ITER viter = vertices_list->begin();
for (; viter != vertices_list->end(); viter++)
{ (*viter)->tag = tag_status; }
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::reset_faces_tag(bool tag_status)
{
FACE_ITER fiter = faces_list->begin();
for (; fiter != faces_list->end(); fiter++)
{ (*fiter)->tag = tag_status; }
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::reset_edges_tag(bool tag_status)
{
EDGE_ITER eiter = edges_list->begin();
for (; eiter != edges_list->end(); eiter++)
{ (*eiter)->tag = tag_status; }
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::reset_all_tag(bool tag_status)
{
reset_edges_tag(tag_status);
reset_faces_tag(tag_status);
reset_vertices_tag(tag_status);
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::translate(const TinyVector<Real, 3> &tran_V)
{
VERTEX_ITER viter = vertices_list->begin();
for (; viter != vertices_list->end(); viter++)
{
HE_vert<Real> *hv = *viter;
hv->pos += tran_V;
}
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::scale(Real factorx, Real factory, Real factorz)
{
VERTEX_ITER viter = vertices_list->begin();
for (; viter != vertices_list->end(); viter++)
{
HE_vert<Real> *hv = *viter;
hv->pos[0] *= factorx;
hv->pos[1] *= factory;
hv->pos[2] *= factorz;
}
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::init_edge_tag()
{
reset_edges_tag(false);
EDGE_ITER eiter = edges_list->begin();
for (; eiter != edges_list->end(); eiter++)
{
HE_edge<Real> *he = *eiter;
if (he->tag == false && he->pair->tag == false)
{
he->tag = true;
}
}
}
//////////////////////////////////////////////////////////////////////////
template <typename Real>
void Mesh3D<Real>::swap_edge(HE_edge<Real> *triedge, bool update_vertex_normal)
{
if (triedge == NULL || triedge->face == NULL || triedge->pair->face == NULL || triedge->face->valence != 3 || triedge->pair->face->valence != 3)
{
return;
}
HE_vert<Real> *hv2 = triedge->vert;
HE_vert<Real> *hv1 = triedge->pair->vert;
HE_vert<Real> *hv3 = triedge->next->vert;
HE_vert<Real> *hv4 = triedge->pair->next->vert;
//check whether the swap causes non_manifold
HE_edge<Real> *che = hv3->edge;
do
{
if (che->vert == hv4)
{
return;
}
che = che->pair->next;
}
while (che != hv3->edge);
HE_face<Real> *hf1 = triedge->face;
HE_face<Real> *hf2 = triedge->pair->face;
HE_edge<Real> *he1 = triedge->next->next;
HE_edge<Real> *he2 = triedge->next;
HE_edge<Real> *he3 = triedge->pair->next->next;
HE_edge<Real> *he4 = triedge->pair->next;
triedge->vert = hv3;
triedge->next = he1;
triedge->prev = he4;
triedge->pair->vert = hv4;
triedge->pair->next = he3;
triedge->pair->prev = he2;
hf1->edge = triedge;
hf2->edge = triedge->pair;
he1->face = hf1;
he2->face = hf2;
he3->face = hf2;
he4->face = hf1;
he1->next = he4;
he1->prev = triedge;
he2->next = triedge->pair;
he2->prev = he3;
he3->next = he2;
he3->prev = triedge->pair;
he4->next = triedge;
he4->prev = he1;
if (hv1->edge == triedge)
{
hv1->edge = he1->pair;
}
if (hv2->edge == triedge->pair)
{
hv2->edge = he3->pair;
}
hv1->degree--;
hv2->degree--;
hv3->degree++;
hv4->degree++;
compute_perface_normal(hf1);
compute_perface_normal(hf2);
if (update_vertex_normal)
{
compute_pervertex_normal(hv1);
compute_pervertex_normal(hv2);
compute_pervertex_normal(hv3);
compute_pervertex_normal(hv4);
}
}
} //end of namespace
template class MeshLib::Mesh3D<double>;
//template class MeshLib::Mesh3D<float>;
#undef _CRT_SECURE_NO_WARNINGS