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.
525 lines
13 KiB
525 lines
13 KiB
3 months ago
|
#ifndef MESH3D_H
|
||
|
#define MESH3D_H
|
||
|
|
||
|
#include <vector>
|
||
|
#include <string>
|
||
|
#include <cstring>
|
||
|
#include <cmath>
|
||
|
#include <algorithm>
|
||
|
#include <map>
|
||
|
#include <iostream>
|
||
|
#include <fstream>
|
||
|
#include <cassert>
|
||
|
#include <iomanip>
|
||
|
#include <queue>
|
||
|
#include <array>
|
||
|
#include <cstdlib>
|
||
|
|
||
|
#include "TinyVector.h"
|
||
|
|
||
|
/** \defgroup MeshCore Mesh data structure */
|
||
|
|
||
|
namespace MeshLib
|
||
|
{
|
||
|
//declare classes for the compiler
|
||
|
template <typename Real> class HE_vert;
|
||
|
template <typename Real> class HE_face;
|
||
|
template <typename Real> class HE_edge;
|
||
|
|
||
|
//! vertex class \ingroup MeshCore
|
||
|
/*!
|
||
|
* The basic vertex class for half-edge structure.
|
||
|
*/
|
||
|
template <typename Real>
|
||
|
class HE_vert
|
||
|
{
|
||
|
public:
|
||
|
TinyVector<Real, 3> pos; //!< 3D coordinate
|
||
|
HE_edge<Real> *edge; //!< one of the half-edges_list emanating from the vertex
|
||
|
TinyVector<Real, 3> normal; //!< vertex normal
|
||
|
ptrdiff_t id; //!< index
|
||
|
unsigned int degree; //!< the degree of vertex
|
||
|
bool tag; //!< tag for programming easily
|
||
|
public:
|
||
|
//! constructor
|
||
|
HE_vert(const TinyVector<Real, 3> &v)
|
||
|
: pos(v), edge(0), id(-1), degree(0), tag(false)
|
||
|
{
|
||
|
}
|
||
|
//destructor
|
||
|
~HE_vert()
|
||
|
{
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//! edge class \ingroup MeshCore
|
||
|
/*!
|
||
|
* The basic edge class for half-edge structure.
|
||
|
*/
|
||
|
template <typename Real>
|
||
|
class HE_edge
|
||
|
{
|
||
|
public:
|
||
|
HE_vert<Real> *vert; //!< vertex at the end of the half-edge
|
||
|
HE_edge<Real> *pair; //!< oppositely oriented adjacent half-edge
|
||
|
HE_face<Real> *face; //!< face the half-edge borders
|
||
|
HE_edge<Real> *next; //!< next half-edge around the face
|
||
|
HE_edge<Real> *prev; //!< prev half-edge around the face
|
||
|
ptrdiff_t id; //!< index
|
||
|
bool tag; //!< tag for programming easily
|
||
|
public:
|
||
|
|
||
|
//!constructor
|
||
|
HE_edge()
|
||
|
: vert(0), pair(0), face(0), next(0), prev(0), id(-1), tag(false)
|
||
|
{
|
||
|
}
|
||
|
//!destructor
|
||
|
~HE_edge()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
//! compute the middle point
|
||
|
inline TinyVector<Real, 3> GetMidPoint()
|
||
|
{
|
||
|
return (Real)0.5 * (vert->pos + pair->vert->pos);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//! face class \ingroup MeshCore
|
||
|
/*!
|
||
|
* The basic face class for half-edge structure.
|
||
|
*/
|
||
|
template <typename Real>
|
||
|
class HE_face
|
||
|
{
|
||
|
public:
|
||
|
HE_edge<Real> *edge; //!< one of the half-edges_list bordering the face
|
||
|
unsigned int valence; //!< the number of edges_list
|
||
|
TinyVector<Real, 3> normal; //!< face normal
|
||
|
int id; //!< index
|
||
|
bool tag; //!< tag for programming easily
|
||
|
std::vector<ptrdiff_t> texture_indices; //! texture indices
|
||
|
std::vector<ptrdiff_t> normal_indices; //! texture indices
|
||
|
int groupid;
|
||
|
public:
|
||
|
//!constructor
|
||
|
HE_face()
|
||
|
: edge(0), id(-1), tag(false), groupid(-1)
|
||
|
{
|
||
|
}
|
||
|
//!destructor
|
||
|
~HE_face()
|
||
|
{
|
||
|
}
|
||
|
//! compute the barycenter
|
||
|
inline TinyVector<Real, 3> GetCentroid()
|
||
|
{
|
||
|
TinyVector<Real, 3> V(0, 0, 0);
|
||
|
HE_edge<Real> *he = edge;
|
||
|
int i = 0;
|
||
|
do
|
||
|
{
|
||
|
V += he->vert->pos;
|
||
|
he = he->next;
|
||
|
i++;
|
||
|
}
|
||
|
while(he != edge);
|
||
|
return V / Real(i);
|
||
|
}
|
||
|
//! whether texture_indices exists
|
||
|
bool has_texture_map()
|
||
|
{
|
||
|
return (!texture_indices.empty()) && (texture_indices.size() == (size_t)valence);
|
||
|
}
|
||
|
//! whether normal_indices exists
|
||
|
bool has_normal_map()
|
||
|
{
|
||
|
return (!normal_indices.empty()) && (normal_indices.size() == (size_t)valence);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
template <typename Real>
|
||
|
bool CompareEdgeID (HE_edge<Real> *he1, HE_edge<Real> *he2 )
|
||
|
{
|
||
|
return he1->id < he2->id;
|
||
|
}
|
||
|
|
||
|
template <typename Real>
|
||
|
bool CompareVertexID (HE_vert<Real> *hv1, HE_vert<Real> *hv2 )
|
||
|
{
|
||
|
return hv1->id < hv2->id;
|
||
|
}
|
||
|
|
||
|
template <typename Real>
|
||
|
bool CompareFaceID (HE_face<Real> *hf1, HE_face<Real> *hf2 )
|
||
|
{
|
||
|
return hf1->id < hf2->id;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
//! Mesh3D class: Half edge data structure \ingroup MeshCore
|
||
|
/*!
|
||
|
* a half-edge based mesh data structure
|
||
|
* For understanding half-edge structure,
|
||
|
* please read the article in http://www.flipcode.com/articles/article_halfedge.shtml
|
||
|
*/
|
||
|
template <typename Real>
|
||
|
class Mesh3D
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
// type definition
|
||
|
typedef std::vector<HE_vert<Real>* > VERTEX_LIST;
|
||
|
typedef std::vector<HE_face<Real>* > FACE_LIST;
|
||
|
typedef std::vector<HE_edge<Real>* > EDGE_LIST;
|
||
|
|
||
|
typedef VERTEX_LIST *PTR_VERTEX_LIST;
|
||
|
typedef FACE_LIST *PTR_FACE_LIST;
|
||
|
typedef EDGE_LIST *PTR_EDGE_LIST;
|
||
|
|
||
|
typedef typename VERTEX_LIST::iterator VERTEX_ITER;
|
||
|
typedef typename FACE_LIST::iterator FACE_ITER;
|
||
|
typedef typename EDGE_LIST::iterator EDGE_ITER;
|
||
|
|
||
|
typedef typename VERTEX_LIST::reverse_iterator VERTEX_RITER;
|
||
|
typedef typename FACE_LIST::reverse_iterator FACE_RITER;
|
||
|
typedef typename EDGE_LIST::reverse_iterator EDGE_RITER;
|
||
|
typedef std::pair<HE_vert<Real>*, HE_vert<Real>* > PAIR_VERTEX;
|
||
|
|
||
|
protected:
|
||
|
|
||
|
// mesh data
|
||
|
|
||
|
PTR_VERTEX_LIST vertices_list; //!< store vertices
|
||
|
PTR_EDGE_LIST edges_list; //!< store edges
|
||
|
PTR_FACE_LIST faces_list; //!< store faces
|
||
|
|
||
|
std::vector<TinyVector<float, 2> > texture_array;
|
||
|
std::vector<TinyVector<float, 3> > normal_array;
|
||
|
// mesh type
|
||
|
|
||
|
bool m_closed; //!< indicate whether the mesh is closed
|
||
|
bool m_quad; //!< indicate whether the mesh is quadrilateral
|
||
|
bool m_tri; //!< indicate whether the mesh is triangular
|
||
|
bool m_hex; //!< indicate whether the mesh is hexagonal
|
||
|
bool m_pentagon; //!< indicate whether the mesh is pentagonal
|
||
|
|
||
|
//! associate two end vertices with its edge: only useful in creating mesh
|
||
|
std::map<PAIR_VERTEX, HE_edge<Real>*> m_edgemap;
|
||
|
|
||
|
// mesh info
|
||
|
|
||
|
int m_num_components; //!< number of components
|
||
|
int m_num_boundaries; //!< number of boundaries
|
||
|
int m_genus; //!< the genus value
|
||
|
|
||
|
bool m_encounter_non_manifold;
|
||
|
|
||
|
public:
|
||
|
|
||
|
//! values for the bounding box
|
||
|
Real xmax, xmin, ymax, ymin, zmax, zmin;
|
||
|
|
||
|
//! store all the boundary vertices, each vector corresponds to one boundary
|
||
|
std::vector<std::vector<HE_vert<Real>*> > boundaryvertices;
|
||
|
std::vector<std::string> groupname;
|
||
|
public:
|
||
|
//! constructor
|
||
|
Mesh3D(void);
|
||
|
|
||
|
//! destructor
|
||
|
~Mesh3D(void);
|
||
|
|
||
|
//! get the pointer of vertices list
|
||
|
inline PTR_VERTEX_LIST get_vertices_list()
|
||
|
{
|
||
|
return vertices_list;
|
||
|
}
|
||
|
|
||
|
//! get the pointer of edges list
|
||
|
inline PTR_EDGE_LIST get_edges_list()
|
||
|
{
|
||
|
return edges_list;
|
||
|
}
|
||
|
|
||
|
//! get the pointer of faces list
|
||
|
inline PTR_FACE_LIST get_faces_list()
|
||
|
{
|
||
|
return faces_list;
|
||
|
}
|
||
|
|
||
|
//! get the total number of vertices
|
||
|
inline ptrdiff_t get_num_of_vertices()
|
||
|
{
|
||
|
return vertices_list ? (ptrdiff_t)vertices_list->size() : 0;
|
||
|
}
|
||
|
|
||
|
//! get the total number of faces
|
||
|
inline ptrdiff_t get_num_of_faces()
|
||
|
{
|
||
|
return faces_list ? (ptrdiff_t)faces_list->size() : 0;
|
||
|
}
|
||
|
|
||
|
//! get the total number of half-edges
|
||
|
inline ptrdiff_t get_num_of_edges()
|
||
|
{
|
||
|
return edges_list ? (ptrdiff_t)edges_list->size() : 0;
|
||
|
}
|
||
|
|
||
|
//! get the pointer of the id-th vertex
|
||
|
inline HE_vert<Real> *get_vertex(ptrdiff_t id)
|
||
|
{
|
||
|
return id >= get_num_of_vertices() || id < 0 ? NULL : (*vertices_list)[id];
|
||
|
}
|
||
|
|
||
|
//! get the pointer of the id-th edge
|
||
|
inline HE_edge<Real> *get_edge(ptrdiff_t id)
|
||
|
{
|
||
|
return id >= get_num_of_edges() || id < 0 ? NULL : (*edges_list)[id];
|
||
|
}
|
||
|
|
||
|
//! get the pointer of the id-th face
|
||
|
inline HE_face<Real> *get_face(ptrdiff_t id)
|
||
|
{
|
||
|
return id >= get_num_of_faces() || id < 0 ? NULL : (*faces_list)[id];
|
||
|
}
|
||
|
|
||
|
//! get the number of components
|
||
|
inline int get_num_of_components()
|
||
|
{
|
||
|
return m_num_components;
|
||
|
}
|
||
|
|
||
|
//! get the number of boundaries
|
||
|
inline int get_num_of_boundaries()
|
||
|
{
|
||
|
return m_num_boundaries;
|
||
|
}
|
||
|
|
||
|
//! get the genus
|
||
|
inline int genus()
|
||
|
{
|
||
|
return m_genus;
|
||
|
}
|
||
|
|
||
|
//! check whether the mesh is valid
|
||
|
inline bool is_valid()
|
||
|
{
|
||
|
if( get_num_of_vertices() == 0 || get_num_of_faces() == 0 )
|
||
|
{ return false; }
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//! check whether the mesh is closed
|
||
|
inline bool is_closed()
|
||
|
{
|
||
|
return m_closed;
|
||
|
}
|
||
|
|
||
|
//! check whether the mesh is triangular
|
||
|
inline bool is_tri()
|
||
|
{
|
||
|
return m_tri;
|
||
|
}
|
||
|
|
||
|
//! check whether the mesh is quadrilateral
|
||
|
inline bool is_quad()
|
||
|
{
|
||
|
return m_quad;
|
||
|
}
|
||
|
|
||
|
//! check whether the mesh is hexgaonal
|
||
|
inline bool is_hex()
|
||
|
{
|
||
|
return m_hex;
|
||
|
}
|
||
|
|
||
|
//! check whether the mesh is pentagonal
|
||
|
inline bool is_pentagon()
|
||
|
{
|
||
|
return m_pentagon;
|
||
|
}
|
||
|
|
||
|
//! insert a vertex
|
||
|
/*!
|
||
|
* \param v a 3d point
|
||
|
* \return a pointer to the created vertex
|
||
|
*/
|
||
|
HE_vert<Real> *insert_vertex(const TinyVector<Real, 3> &v);
|
||
|
|
||
|
//! insert a face
|
||
|
/*!
|
||
|
* \param vec_hv the vertices list of a face
|
||
|
* \param texture the pointer of texture vector
|
||
|
* \param normal the normal of texture vector
|
||
|
* \return a pointer to the created face
|
||
|
*/
|
||
|
HE_face<Real> *insert_face(VERTEX_LIST &vec_hv, std::vector<ptrdiff_t> *texture = 0, std::vector<ptrdiff_t> *normal = 0);
|
||
|
|
||
|
//! check whether the vertex is on border
|
||
|
bool is_on_boundary(HE_vert<Real> *hv);
|
||
|
//! check whether the face is on border
|
||
|
bool is_on_boundary(HE_face<Real> *hf);
|
||
|
//! check whether the edge is on border
|
||
|
bool is_on_boundary(HE_edge<Real> *he);
|
||
|
|
||
|
//FILE IO
|
||
|
|
||
|
//! load a 3D mesh from an OFF format file
|
||
|
bool load_off(const char *fins);
|
||
|
|
||
|
//modified by haoxiang on 03/10/2021
|
||
|
void load_mesh(const std::vector<std::array<double, 3>>& pos, const std::vector<std::vector<size_t>>& indices);
|
||
|
|
||
|
//! export the current mesh to an OFF format file
|
||
|
void write_off(const char *fouts);
|
||
|
//! load a 3D mesh from an OBJ format file
|
||
|
bool load_obj(const char *fins);
|
||
|
//! export the current mesh to an OBJ format file
|
||
|
void write_obj(const char *fouts);
|
||
|
//! export to a VTK format file
|
||
|
void write_vtk(const char *fouts);
|
||
|
|
||
|
//! update mesh:
|
||
|
/*!
|
||
|
* call it when you have created the mesh
|
||
|
*/
|
||
|
void update_mesh();
|
||
|
|
||
|
//! update normal
|
||
|
/*!
|
||
|
* compute all the normals of vertices and faces
|
||
|
*/
|
||
|
void update_normal(bool onlyupdate_facenormal = false);
|
||
|
|
||
|
//! compute the bounding box
|
||
|
void compute_boundingbox();
|
||
|
|
||
|
//! get a copy of the current
|
||
|
Mesh3D<Real> *make_copy();
|
||
|
|
||
|
//! return a face-orientation-changed mesh
|
||
|
Mesh3D<Real> *reverse_orientation();
|
||
|
|
||
|
//! init edge tags
|
||
|
/*!
|
||
|
* for a pair of edges, only one of them is tagged to be true.
|
||
|
*/
|
||
|
void init_edge_tag();
|
||
|
|
||
|
//! reset all the vertices' tag
|
||
|
void reset_vertices_tag(bool tag_status);
|
||
|
//! reset all the faces' tag
|
||
|
void reset_faces_tag(bool tag_status);
|
||
|
//! reset all the edges' tag
|
||
|
void reset_edges_tag(bool tag_status);
|
||
|
//! reset all tag exclude edges' tag2
|
||
|
void reset_all_tag(bool tag_status);
|
||
|
|
||
|
//! translate the mesh with tran_V
|
||
|
void translate(const TinyVector<Real, 3> &tran_V);
|
||
|
//! scale the mesh
|
||
|
void scale(Real factorx, Real factory, Real factorz);
|
||
|
|
||
|
//! check whether there is any non-manifold case
|
||
|
inline bool is_encounter_nonmanifold()
|
||
|
{
|
||
|
return m_encounter_non_manifold;
|
||
|
}
|
||
|
|
||
|
//! set texture array
|
||
|
void set_texture_array(const std::vector< TinyVector<float, 2> > &textures)
|
||
|
{
|
||
|
texture_array.assign(textures.begin(), textures.end());
|
||
|
}
|
||
|
//! set normal array
|
||
|
void set_normal_array(const std::vector< TinyVector<float, 3> > &normals)
|
||
|
{
|
||
|
normal_array.assign(normals.begin(), normals.end());
|
||
|
}
|
||
|
//! get texture array
|
||
|
std::vector< TinyVector<float, 2> > &get_texture_array()
|
||
|
{
|
||
|
return texture_array;
|
||
|
}
|
||
|
//! get texture array
|
||
|
const std::vector< TinyVector<float, 2> > &get_texture_array() const
|
||
|
{
|
||
|
return texture_array;
|
||
|
}
|
||
|
//! get normal array
|
||
|
std::vector< TinyVector<float, 3> > &get_normal_array()
|
||
|
{
|
||
|
return normal_array;
|
||
|
}
|
||
|
//! get normal array
|
||
|
const std::vector< TinyVector<float, 3> > &get_normal_array() const
|
||
|
{
|
||
|
return normal_array;
|
||
|
}
|
||
|
|
||
|
//! swap edge
|
||
|
/*!
|
||
|
* \param triedge an edge between two triangular faces
|
||
|
*/
|
||
|
void swap_edge(HE_edge<Real> *triedge, bool update_vertex_normal = true);
|
||
|
|
||
|
private:
|
||
|
|
||
|
//! insert an edge
|
||
|
HE_edge<Real> *insert_edge(HE_vert<Real> *vstart, HE_vert<Real> *vend);
|
||
|
|
||
|
//! clear all the data
|
||
|
void clear_data();
|
||
|
|
||
|
//! clear vertices
|
||
|
void clear_vertices();
|
||
|
//! clear edges
|
||
|
void clear_edges();
|
||
|
//! clear faces
|
||
|
void clear_faces();
|
||
|
|
||
|
//! check whether the mesh is closed
|
||
|
void check_closed();
|
||
|
//! check the mesh type
|
||
|
void check_meshtype();
|
||
|
|
||
|
//! compute all the normals of faces
|
||
|
void compute_faces_list_normal();
|
||
|
//! compute the normal of a face
|
||
|
void compute_perface_normal(HE_face<Real> *hf);
|
||
|
//! compute all the normals of vertices
|
||
|
void compute_vertices_list_normal();
|
||
|
//! compute the normal of a vertex
|
||
|
void compute_pervertex_normal(HE_vert<Real> *hv);
|
||
|
|
||
|
//! compute the number of components
|
||
|
void compute_num_components();
|
||
|
//! compute the number of boundaries
|
||
|
void compute_num_boundaries();
|
||
|
//! compute the genus
|
||
|
void compute_genus();
|
||
|
|
||
|
//! handle the boundary half edges specially
|
||
|
void set_nextedge_for_border_vertices();
|
||
|
|
||
|
//! remove the vertices which have no connection to others.
|
||
|
void remove_hanged_vertices();
|
||
|
|
||
|
//! align edges's id
|
||
|
/*!
|
||
|
set mesh's edge(vertex(startid), vertex(endid)->id = edgeid.
|
||
|
only used in make_copy
|
||
|
*/
|
||
|
void copy_edge_id(ptrdiff_t edgeid, ptrdiff_t startid, ptrdiff_t endid, Mesh3D<Real> *mesh);
|
||
|
};
|
||
|
} //end of namespace
|
||
|
|
||
|
//typedef MeshLib::Mesh3D<float> Mesh3f;
|
||
|
typedef MeshLib::Mesh3D<double> Mesh3d;
|
||
|
|
||
|
#endif //MESH3D_H
|