/** * @file core.hpp * @author Simone Gasparini * @version 1.0 * * @section LICENSE * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * @section DESCRIPTION * * The core module providing some helper classes for manipulating mesh data * */ #pragma once // for mac osx #ifdef __APPLE__ #include #else // only for windows #ifdef _WIN32 #include #endif // for windows and linux #include #endif #ifdef __GNUC__ #define DEPRECATED(func) func __attribute__ ((deprecated)) #elif defined(_MSC_VER) #define DEPRECATED(func) __declspec(deprecated) func #else #pragma message("WARNING: You need to implement DEPRECATED for this compiler") #define DEPRECATED(func) func #endif //__attribute__ ((deprecated)) #include #include #include #include #include #define DEBUGGING 1 #if DEBUGGING #define PRINTVAR( a ) std::cout << #a << " = " << (a) << std::endl << std::endl; #else #define PRINTVAR( a ) #endif /** * Renaming, the type of an index is a unsigned int */ using idxtype = GLuint; /** * An edge is defined as a pair of indices of the vertices */ using edge = std::pair; /** * Function to print the values of an edge * * @param os the string to fill * @param p the edge to print * @return the string with the printed value of the edge */ inline std::ostream& operator<<( std::ostream& os, const edge& e ) { return os << "[" << e.first << "," << e.second << "]"; } /** * It checks whether two edges are equals: two edges are equal if their indices * are the same, no matter the order * * @param[in] a The first edge * @param[in] b The second edge * @return true if the edges are equal */ inline bool operator==( const edge& a, const edge& b ) { return ( ( ( a.first == b.first ) && ( a.second == b.second ) ) || ( ( a.first == b.second ) && ( a.second == b.first ) ) ); } /** * Return the sum of vertex indices of an edge * @param[in] e the edge * @return the sum of the indices */ inline idxtype sum( const edge &e ) { return (e.first + e.second ); } /** * return the min index of the two vertices * @param[in] e the edge * @return the min index */ inline idxtype min( const edge &e ) { return (( e.first > e.second ) ? ( e.second ) : ( e.first ) ); } /** * Structure used to compare two edges */ struct edgeEquivalent { bool operator( ) ( const edge &a, const edge &b ) const { // return !( ( (a.first == b.first) && (a.second == b.second) ) || // ( (a.first == b.second) && (a.second == b.first) ) ); // two edges are equal either their corresponding elements are equal or // they are inverted return ( ( ( a.first == b.first ) && ( a.second == b.second ) ) || ( ( a.first == b.second ) && ( a.second == b.first ) ) ); } }; // to be used with unordered struct edgeHash { size_t operator( ) ( const edge &a ) const { std::hash fun; return (fun( ( a.first > a.second ) ? ( "v" + std::to_string( a.second ) + "-" + std::to_string( a.first ) ) : ( "v" + std::to_string( a.first ) + "-" + std::to_string( a.second ) ) ) ); } }; /** * An edge list is a map of edges (the keys) and a index of the vertex */ using edge2vertex = std::unordered_map< edge, idxtype, edgeHash, edgeEquivalent >; inline std::ostream& operator<<( std::ostream& os, const edge2vertex & l ) { os << std::endl; for (const auto &it : l) os << "\t" << it.first << "\t" << it.second << std::endl; return os; } /** * A helper class containing the indices of the new vertices added with the subdivision * coupled with the edge that has generated them. More specifically, it is a list in which * each entry has a key (ie an identifier) and a value: the key is the edge that * generate the vertex, the value is the index of the new vertex. * The key (ie the edge) is unique, ie an edge cannot generate more than one vertex. The * edge is a pair of vertex indices, two edges are the same if they contain the * same pair of vertices, no matter their order, ie * edge(v1, v2) == edge(v2, v1) * * @see edge */ class EdgeList { public: EdgeList( ) = default; /** * Add the edge and the index of the new vertex generated on it * @param[in] e the edge * @param[in] idx the index of the new vertex generated on the edge */ void add( const edge &e, const idxtype &idx ) { list[e] = idx; } /** * Return true if the edge is in the map * @param[in] e the edge to search for * @return true if the edge is in the map */ bool contains( const edge &e ) const { return (list.find( e ) != list.end( ) ); } /** * Get the vertex index associated to the edge * @param e the edge * @return the index */ idxtype getIndex( const edge &e ) { return (list[e] ); } friend std::ostream& operator<<( std::ostream& os, const EdgeList& l ); private: edge2vertex list; }; inline std::ostream& operator<<( std::ostream& os, const EdgeList& l ) { return (os << l.list ); } /**************************************************************************/ /** * A generic vector of three elements */ struct v3f { float x; //!< the first component float y; //!< the second component float z; //!< the third component /** * Generic constructor * @param x the first element * @param y the second element * @param z the third element */ v3f( float x, float y, float z ) : x( x ), y( y ), z( z ) { } /** * Default constructor, everything is initialized to 0 */ v3f( ) : x( 0 ), y( 0 ), z( 0 ) { } /** * Constructor from an array of three elements * @param[in] a the array from which to copy the elements */ explicit v3f( const float a[3] ) : x( a[0] ), y( a[1] ), z( a[2] ) { } /** * Normalize the vector (ie divide by the norm) */ void normalize( ); /** * Return the dot product * @param[in] v the other vector * @return the dot product */ float dot( const v3f &v ) const; /** * Return the norm of the vector * @return the norm */ float norm( ) const; /** * Translate the vector * @param[in] x the delta x of the translation * @param[in] y the delta y of the translation * @param[in] z the delta z of the translation */ void translate( const float &x, const float &y, const float &z ); /** * Translate the vector * @param[in] t the translation */ void translate( const v3f &t ); /** * Scale each element of the vector by the corresponding value * @param[in] t a vector containing a factor scale to apply to each element */ void scale( const v3f &t ); /** * Scale each element of the vector by the corresponding value * @param x the scale value on x * @param y the scale value on y * @param z the scale value on z */ void scale( const float &x, const float& y, const float &z ); /** * Scale each element of the vector by the same value * @param a The scalar value to apply to each element */ void scale( const float &a ); /** * Set each element of the current vector to the minimum value wrt another vector * @param a the other vector */ void min( const v3f& a ); /** * Return the minimum value among the 3 elements * @return the minimum value */ float min( ) const; /** * Set each element of the current vector to the maximum value wrt another vector * @param a the other vector */ void max( const v3f& a ); /** * Return the maximum value among the 3 elements * @return the maximum value */ float max( ) const; /** * Return the cross product of two vectors * @param v the other vector * @return the cross product */ v3f cross( const v3f& v ) const; /** * Return the cross product of two vectors * @param v the other array * @return the cross product */ v3f cross( const float v[3] ) const; // element-wise addition v3f operator +( const v3f& a ) const; v3f& operator +=( const v3f& a ); v3f operator +( const float a[3] ) const; v3f& operator +=( const float a[3] ); v3f operator +( const float &a ) const; v3f& operator +=( const float &a ); // element-wise subtraction v3f operator -( const v3f& a ) const; v3f& operator -=( const v3f& a ); v3f operator -( const float a[3] ) const; v3f& operator -=( const float a[3] ); v3f operator -( const float &a ) const; v3f& operator -=( const float &a ); // element-wise product v3f operator *( const v3f& a ) const; v3f& operator *=( const v3f& a ); v3f operator *( const float a[3] ) const; v3f& operator *=( const float a[3] ); v3f operator *( const float &a ) const; v3f& operator *=( const float &a ); // element-wise ratio v3f operator /( const v3f& a ) const; v3f& operator /=( const v3f& a ); v3f operator /( const float a[3] ) const; v3f& operator /=( const float a[3] ); v3f operator /( const float &a ) const; v3f& operator /=( const float &a ); }; /** * Some definitions */ using point3d = struct v3f ; using vec3d = struct v3f; /** * Print the elements of a vector * @param os the string to fill with the vector values * @param p the vector * @return the string with the values */ inline std::ostream& operator<<( std::ostream& os, const v3f& p ) { return os << "[" << p.x << "," << p.y << "," << p.z << "]"; } /** * Print the elements of a vector of v3f elements * @param os the string to fill with the vector elements * @param p the vector * @return the string with the vector elements */ inline std::ostream& operator<<( std::ostream& os, const std::vector& p ) { os << std::endl; for (const auto& v : p) os << "\t" << v << std::endl; return os; } // REFLEXIVE OPERATORS FOR V3F inline v3f operator +( const float &a, const v3f& p ) { return (p + a ); } inline v3f operator +( const float a[3], const v3f& p ) { return (p + a ); } inline v3f operator -( const float &a, const v3f& p ) { return (p - a ); } inline v3f operator -( const float a[3], const v3f& p ) { return (p - a ); } inline v3f operator *( const float a[3], const v3f& p ) { return (p * a ); } inline v3f operator *( const float &a, const v3f& p ) { return (p * a ); } inline v3f operator /( const float a[3], const v3f& p ) { return (p / a ); } inline v3f operator /( const float &a, const v3f& p ) { return (p / a ); } /**************************************************************************/ /** * The face as a triplet of indices */ struct face { idxtype v1; //!< the first index idxtype v2; //!< the second index idxtype v3; //!< the third index /** * Default constructor, everything set to 0 */ face( ) : v1( 0 ), v2( 0 ), v3( 0 ) { } /** * Constructor from indices * @param v1 the first index * @param v2 the second index * @param v3 the third index */ face( idxtype v1, idxtype v2, idxtype v3 ) : v1( v1 ), v2( v2 ), v3( v3 ) { } /** * Return true if the edge e is contained in the triplet of indices. If it is * contained it also return the opposite vertex (ie the index of the vertex not * belonging to the edge) * * @param[in] e the edge to check * @param[out] oppositeVertex If the triplet contain the edge, this will be the (index of the) opposite * vertex wrt the edge in the triangle * @return true if the edge is contained (the order of the indices does not matter) */ bool containsEdge( const edge &e, idxtype &oppositeVertex ) const; face operator +( const face& a ) const; face& operator +=( const face& a ); face operator +( const idxtype &a ) const; face& operator +=( const idxtype &a ); face operator -( const face& a ) const; face& operator -=( const face& a ); face operator -( const idxtype &a ) const; face& operator -=( const idxtype &a ); face operator *( const face& a ) const; face& operator *=( const face& a ); face operator *( const idxtype &a ) const; face& operator *=( const idxtype &a ); /** * Two index triplets are equal if their corresponding elements are equal */ bool operator==( const face& rhs ) const; /** * Two index triplets are different if... they are not equal */ bool operator!=( const face& rhs ) const; }; /** * Print the face values on a string * @param os the string to fill with the values * @param p the face to print * @return the string filled with the values */ inline std::ostream& operator<<( std::ostream& os, const face& p ) { return os << "[" << p.v1 << "," << p.v2 << "," << p.v3 << "]"; } /** * Print a vector of faces on a string * @param[in,out] os the string to fill with the faces * @param[in] p the vector of faces to print * @return the string filled with the faces */ inline std::ostream& operator<<( std::ostream& os, const std::vector& p ) { os << std::endl; for (auto v : p) os << "\t" << v << std::endl; return os; } /** * It checks if the edge e is a boundary edge in the list of triangle. It also * return the indices of the two opposite vertices of the edge or only one of * them if it is a boundary edge * * @param[in] e the edge to check * @param[in] triangleList the list of triangles * @param[out] oppVert1 the index of the first opposite vertices (the only one if the edge is a boundary edge) * @param[out] oppVert2 the index of the second opposite vertices (only if the edge is not a boundary edge) * @return true if the edge is not a boundary edge */ bool isBoundaryEdge( const edge &e, const std::vector &triangleList, idxtype &oppVert1, idxtype &oppVert2 );