diff --git a/Geo/MNeighbour.h b/Geo/MNeighbour.h new file mode 100644 index 0000000000000000000000000000000000000000..a657127a01812b9315cd762eb2f78248cbe6c67b --- /dev/null +++ b/Geo/MNeighbour.h @@ -0,0 +1,1444 @@ +#ifndef _MNEIGHBOUR_H_ +#define _MNEIGHBOUR_H_ + +// Copyright (C) 2006 S. Guzik, C. Geuzaine, J.-F. Remacle +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems to <gmsh@geuz.org>. + +/******************************************************************************* + * + * - The classes in this file construct a database of the elements that share + * the lower-dimensional bounding objects (e.g., vertex, edge, or face). + * These lower-dimensional objects are referred to in general as polytopes. + * - Templated traits classes are used extensively to define the characteristics + * of the elements and the entities. + * + * ****************************************************************************/ + +#include <algorithm> +#include <iterator> +#include <vector> +#include "MElement.h" +#include "GEdge.h" +#include "GFace.h" +#include "GRegion.h" +#include "GmshDefines.h" + +// #define HAVE_HASH_MAP + +#if defined(HAVE_HASH_MAP) +#include "HashMap.h" +#endif + + +/*============================================================================== + * File scope types + *============================================================================*/ + +typedef std::list<MElement*> Neighbours; +typedef Neighbours::const_iterator NeighboursConstIterator; +typedef Neighbours::iterator NeighboursIterator; + +struct Range_t +{ + unsigned int num; + NeighboursIterator begin; + Range_t() : num(0) { } +}; + +//--Use a hash map for neighbour lookup if possible, otherwise a map will do + +#if defined(HAVE_HASH_MAP) +struct Hash_VertexPtr : public std::unary_function<MVertex*, size_t> +{ + size_t operator()(const MVertex *const v) const + { + return HashFNV1a<sizeof(MVertex*)>::eval(v); + } +}; +typedef HASH_MAP<MVertex*, Range_t, Hash_VertexPtr, std::equal_to<MVertex*> > +VertNRange; +typedef HASH_MAP<MEdge, Range_t, Hash_Edge, Equal_Edge> EdgeNRange; +typedef HASH_MAP<MFace, Range_t, Hash_Face, Equal_Face> FaceNRange; +#else +typedef std::map<MVertex*, Range_t, std::less<MVertex*> > VertNRange; +typedef std::map<MEdge, Range_t, Less_Edge> EdgeNRange; +typedef std::map<MFace, Range_t, Less_Face> FaceNRange; +#endif +typedef VertNRange::iterator VertNRangeIterator; +typedef VertNRange::const_iterator VertNRangeConstIterator; +typedef EdgeNRange::iterator EdgeNRangeIterator; +typedef EdgeNRange::const_iterator EdgeNRangeConstIterator; +typedef FaceNRange::iterator FaceNRangeIterator; +typedef FaceNRange::const_iterator FaceNRangeConstIterator; + + +/*============================================================================== + * Traits classes - that just perform compile-time checks for valid argument + * types + *============================================================================*/ + +//--This traits class checks for a pointer and strips it + +// NOTE: If the compiler sent you here, you should be using a pointer. +template <typename T> struct StripPointer; +template <typename T> struct StripPointer<T*> { typedef T Type; }; + +//--This traits class checks for valid types of entities and iterators when the +//--entity is explicitly specified + +// NOTE: If the compiler sent you here, you're using an invalid entity and/or +// invalid iterator. Valid pairs are shown below +template <typename Ent, typename Iter> struct ValidSpecEntityIterator; +template <> struct ValidSpecEntityIterator<GEdge, GEdge*> +{ typedef void Type; }; +template <> struct ValidSpecEntityIterator<GEdge, GEntity*> +{ typedef void Type; }; +template <> struct ValidSpecEntityIterator<GFace, GFace*> +{ typedef void Type; }; +template <> struct ValidSpecEntityIterator<GFace, GEntity*> +{ typedef void Type; }; +template <> struct ValidSpecEntityIterator<GRegion, GRegion*> +{ typedef void Type; }; +template <> struct ValidSpecEntityIterator<GRegion, GEntity*> +{ typedef void Type; }; + +//--This traits class checks for valid types of entities and iterators when the +//--entity is not specified. It also strips the pointer. + +// NOTE: If the compiler sent you here, you're using an invalid entity or +// iterator of entities +template <typename Iter> struct ValidEntityIterator; +template <> struct ValidEntityIterator<GEdge*> +{ typedef GEdge Type; }; +template <> struct ValidEntityIterator<GFace*> +{ typedef GFace Type; }; +template <> struct ValidEntityIterator<GRegion*> +{ typedef GRegion Type; }; + +//--This traits class checks for valid element types + +// NOTE: If the compiler sent you here, you're using an invalid iterator for an +// element. What's listed here are NOT the only valid types. Any iterator with +// a value type of a pointer to an element should work. +template <typename Elem_o1> struct ValidElement; +template <> struct ValidElement<MElement> { typedef void Type; }; +template <> struct ValidElement<MLine> { typedef void Type; }; +template <> struct ValidElement<MTriangle> { typedef void Type; }; +template <> struct ValidElement<MQuadrangle> { typedef void Type; }; +template <> struct ValidElement<MTetrahedron> { typedef void Type; }; +template <> struct ValidElement<MHexahedron> { typedef void Type; }; +template <> struct ValidElement<MPrism> { typedef void Type; }; +template <> struct ValidElement<MPyramid> { typedef void Type; }; + + +/*============================================================================== + * Traits classes - that return information about a type + *============================================================================*/ + +//--This traits class gives the first-order base type for a second-order element + +template <typename Order2> struct ElemBaseOrder +{ typedef Order2 Order1; }; +template <> struct ElemBaseOrder<MLine3> +{ typedef MLine Order1; }; +template <> struct ElemBaseOrder<MTriangle6> +{ typedef MTriangle Order1; }; +template <> struct ElemBaseOrder<MQuadrangle8> +{ typedef MQuadrangle Order1; }; +template <> struct ElemBaseOrder<MQuadrangle9> +{ typedef MQuadrangle Order1; }; +template <> struct ElemBaseOrder<MTetrahedron10> +{ typedef MTetrahedron Order1; }; +template <> struct ElemBaseOrder<MHexahedron20> +{ typedef MHexahedron Order1; }; +template <> struct ElemBaseOrder<MHexahedron27> +{ typedef MHexahedron Order1; }; +template <> struct ElemBaseOrder<MPrism15> +{ typedef MPrism Order1; }; +template <> struct ElemBaseOrder<MPrism18> +{ typedef MPrism Order1; }; +template <> struct ElemBaseOrder<MPyramid13> +{ typedef MPyramid Order1; }; +template <> struct ElemBaseOrder<MPyramid14> +{ typedef MPyramid Order1; }; + +//--This traits class describes describes the lower dimensional bounding +//--polytopes of a first-order element + +template <typename Elem> struct ElemTr; +template <> struct ElemTr<MElement> +{ enum { numVertex = 0, numEdge = 0, numFace = 0 }; }; +template <> struct ElemTr<MLine> +{ enum { numVertex = 2, numEdge = 0, numFace = 0 }; }; +template <> struct ElemTr<MTriangle> +{ enum { numVertex = 3, numEdge = 3, numFace = 0 }; }; +template <> struct ElemTr<MQuadrangle> +{ enum { numVertex = 4, numEdge = 4, numFace = 0 }; }; +template <> struct ElemTr<MTetrahedron> +{ enum { numVertex = 4, numEdge = 6, numFace = 4 }; }; +template <> struct ElemTr<MHexahedron> +{ enum { numVertex = 8, numEdge = 12, numFace = 6 }; }; +template <> struct ElemTr<MPrism> +{ enum { numVertex = 6, numEdge = 9, numFace = 5 }; }; +template <> struct ElemTr<MPyramid> +{ enum { numVertex = 5, numEdge = 8, numFace = 5 }; }; + +//--This traits class gives the number of element types in entity Ent + +template <typename Ent> struct EntTr; +template <> struct EntTr<GEdge> { enum { numElemTypes = 1 }; }; +template <> struct EntTr<GFace> { enum { numElemTypes = 2 }; }; +template <> struct EntTr<GRegion> { enum { numElemTypes = 4 }; }; + +//--This traits class gives iterator types and begin and end iterators for +//--element type number N in entity Ent. + +template <typename Ent, unsigned int N> struct EntElemTr; +template <> struct EntElemTr<GEdge, 1> { + typedef MLine Elem; + typedef std::vector<MLine*>::const_iterator ConstElementIterator; + typedef std::vector<MLine*>::iterator ElementIterator; + static ConstElementIterator begin(const GEdge *const edge) + { + return edge->lines.begin(); + } + static ConstElementIterator end(const GEdge *const edge) + { + return edge->lines.end(); + } +}; +template <> struct EntElemTr<GFace, 1> { + typedef MQuadrangle Elem; + typedef std::vector<MQuadrangle*>::const_iterator ConstElementIterator; + typedef std::vector<MQuadrangle*>::iterator ElementIterator; + static ConstElementIterator begin(const GFace *const face) + { + return face->quadrangles.begin(); + } + static ConstElementIterator end(const GFace *const face) + { + return face->quadrangles.end(); + } +}; +template <> struct EntElemTr<GFace, 2> { + typedef MTriangle Elem; + typedef std::vector<MTriangle*>::const_iterator ConstElementIterator; + typedef std::vector<MTriangle*>::iterator ElementIterator; + static ConstElementIterator begin(const GFace *const face) + { + return face->triangles.begin(); + } + static ConstElementIterator end(const GFace *const face) + { + return face->triangles.end(); + } +}; +template <> struct EntElemTr<GRegion, 1> { + typedef MPyramid Elem; + typedef std::vector<MPyramid*>::const_iterator ConstElementIterator; + typedef std::vector<MPyramid*>::iterator ElementIterator; + static ConstElementIterator begin(const GRegion *const region) + { + return region->pyramids.begin(); + } + static ConstElementIterator end(const GRegion *const region) + { + return region->pyramids.end(); + } +}; +template <> struct EntElemTr<GRegion, 2> { + typedef MPrism Elem; + typedef std::vector<MPrism*>::const_iterator ConstElementIterator; + typedef std::vector<MPrism*>::iterator ElementIterator; + static ConstElementIterator begin(const GRegion *const region) + { + return region->prisms.begin(); + } + static ConstElementIterator end(const GRegion *const region) + { + return region->prisms.end(); + } +}; +template <> struct EntElemTr<GRegion, 3> { + typedef MHexahedron Elem; + typedef std::vector<MHexahedron*>::const_iterator ConstElementIterator; + typedef std::vector<MHexahedron*>::iterator ElementIterator; + static ConstElementIterator begin(const GRegion *const region) + { + return region->hexahedra.begin(); + } + static ConstElementIterator end(const GRegion *const region) + { + return region->hexahedra.end(); + } +}; +template <> struct EntElemTr<GRegion, 4> { + typedef MTetrahedron Elem; + typedef std::vector<MTetrahedron*>::const_iterator ConstElementIterator; + typedef std::vector<MTetrahedron*>::iterator ElementIterator; + static ConstElementIterator begin(const GRegion *const region) + { + return region->tetrahedra.begin(); + } + static ConstElementIterator end(const GRegion *const region) + { + return region->tetrahedra.end(); + } +}; + +//--This is a traits/policy class for the lower-dimension polytopes that bound +//--an element (i.e., vertex, edge, or face). It returns the corresponding +//--range type and extracts from the element the function to get the polytope. +//--Note that MVertex is a pointer because it exists somewhere whereas MEdge and +//--MFace are constructed using MVertex's by getEdge() and getFace(). + +template <typename Polytope> struct PolytopeTr; +template <> struct PolytopeTr<MVertex*> { + typedef VertNRange PolytopeNRange; + typedef VertNRangeConstIterator PNRConstIterator; + template <typename Elem> + static MVertex *getPolytope(Elem *const element, + const unsigned int nPolytope) + { + return element->getVertex(nPolytope); + } +}; +template <> struct PolytopeTr<MEdge> { + typedef EdgeNRange PolytopeNRange; + typedef EdgeNRangeConstIterator PNRConstIterator; + template <typename Elem> + static MEdge getPolytope(Elem *const element, + const unsigned int nPolytope) + { + return element->getEdge(nPolytope); + } +}; +template <> struct PolytopeTr<MFace> { + typedef FaceNRange PolytopeNRange; + typedef FaceNRangeConstIterator PNRConstIterator; + template <typename Elem> + static MFace getPolytope(Elem *const element, + const unsigned int nPolytope) + { + return element->getFace(nPolytope); + } +}; + + +/******************************************************************************* + * + * class: PolytopeIterator + * + * Purpose + * ======= + * + * Provides an iterator to iterate through the unique vertices, edges and, + * faces defined by the (hash_)maps. An iterator to the (hash_)map has a + * value type of a (key, value) pair. This iterator makes the container look + * like it only contains the bounding polytope. + * + * Constructors + * ============ + * + * The class takes one template argument <Polytope> which should be either + * MVertex*, MEdge, or MFace. + * + * PolytopeIterator() + * -- default constructor + * + * PolytopeIterator(const BaseIterator &baseIter_in) + * -- the base iterator is the real iterator to the + * (hash_)map + * + * PolytopeIterator(const PolytopeIterator &iter) + * -- copy + * + * Destructor + * ========== + * + * ~PolytopeIterator -- synthesized + * + * Member Functions + * ================ + * + * unsigned int num_neighbours() + * -- returns number of elements sharing the polytope + * + * Operators + * ========= + * + * Includes typical bidirectional iterator operators {=, ==, !=, *, ->, ++(), + * --(), ()++, ()--} with * and -> dereferencing to the polytope. + * + * Notes + * ===== + * + * - Only constant iterators are supported. + * + ******************************************************************************/ + +template<typename Polytope> +class PolytopeIterator // Actually only a const_iterator +{ + + public: + + // The base iterator iterates through the (hash_)maps defining the range of + // element neighbours for a polytope + typedef typename PolytopeTr<Polytope>::PNRConstIterator BaseIterator; + typedef PolytopeIterator Self; + + // Standard traits + typedef std::bidirectional_iterator_tag iterator_category; + typedef Polytope value_type; + typedef BaseIterator difference_type; + typedef const Polytope* pointer; + typedef const Polytope& reference; + +//--Constructors + + PolytopeIterator() : baseIter() { } + PolytopeIterator(const BaseIterator &baseIter_in) : baseIter(baseIter_in) { } + PolytopeIterator(const PolytopeIterator &iter) : baseIter(iter.baseIter) { } + PolytopeIterator& operator=(const PolytopeIterator& iter) + { + if(&iter != this) baseIter = iter.baseIter; + return *this; + } + +//--Comparison + + bool operator==(const Self& iter) const { return baseIter == iter.baseIter; } + bool operator!=(const Self& iter) const { return baseIter != iter.baseIter; } + +//--Dereference and arrow operator + + reference operator*() const { return baseIter->first; } + pointer operator->() const { return &baseIter->first; } + +//--Increment + + // Prefix + Self& operator++() + { + ++baseIter; + return *this; + } + + // Postfix + Self operator++(int) + { + Self tmp = *this; + ++*this; + return tmp; + } + +//--Decrement + + // Prefix + Self& operator--() + { + --baseIter; + return *this; + } + + // Postfix + Self operator--(int) + { + Self tmp = *this; + --*this; + return tmp; + } + +//--Special + + unsigned int num_neighbours() { return baseIter->second.num; } + + private: + NeighboursConstIterator begin_neighbours() { return baseIter->second.begin; } + +//--Date members + + BaseIterator baseIter; + +//--Friends + + friend class MNeighbour; + +}; + + +/******************************************************************************* + * + * class: MNeighbour + * + * Purpose + * ======= + * + * Generates a database for quick lookup of elements sharing a + * MVertex*, MEdge, or MFace (referred to in general as polytopes. I.e., a + * geometrical construct bounding the element with a lower dimension than the + * element). The neighbour elements are stored in a list. Maps or hash maps + * provide an index into the list for a given polytope. In addition to the + * element neighbours, this class provides iterators to the unique vertices, + * edges, and faces in the database. + * + * Iterators + * ========= + * + * Vertex_const_iterator + * -- iterator to sequence of unique vertices + * Edge_const_iterator + * -- iterator to sequence of unique edges + * Face_const_iterator + * -- iterator to sequence of unique faces + * + * Constructors + * ============ + * + * MNeighbour() -- default constructor does nothing + * + * Destructor + * ========== + * + * ~MNeighbour() -- synthesized + * + * Member Functions + * ================ + * + * Iterators + * --------- + * + * Vertex_const_iterator vertex_begin() + * -- first unique vertex + * + * Vertex_const_iterator vertex_end() + * -- one-past-last unique vertex + * + * Edeg_const_iterator edge_begin() + * -- first unique edge + * + * Edge_const_iterator edge_end() + * -- one-past-last unique edge + * + * Face_const_iterator face_begin() + * -- first unique face + * + * Face_const_iterator face_end() + * -- one-past-last unique face + * + * Routines for adding elements + * ---------------------------- + * + * The routines that generate a database of neighbours from container of + * entities (add_elements_in_entitie) require knowledge of the specific type + * of entity. In cases where a container contains specific entities, the type + * need not be stated. In cases where the container contains GEntity*, the + * user must state the actual entity type. Extensive compile-time type + * checking is employed to make sure the routines are used correctly. + * + * template <typename Ent, typename EntIter> + * void add_elements_in_entities(EntIter begin, EntIter end) + * -- adds elements in entities to neighbours database. + * Entity type <Ent> must be explicitly specified. The + * value type of the iterators must be a pointer to an + * entity. It is expected, but not required to be a + * pointer to a GEntity. + * begin (I) iterator/pointer to first entity pointer + * end (I) iterator/pointer to one-past-last entity pointer + * + * template <typename Ent, typename EntP> + * void add_elements_in_entities(EntP **pEnt, unsigned int n) + * -- adds elements in entities to neighbours database. + * Entity type <Ent> must be explicitly specified. The + * array element must be a pointer to an element. It is + * expected, but not required to be a pointer to a + * GEntity. + * pEnt (I) first entity in the array + * n (I) number of entities in the array + * + * template <typename EntIter> + * void add_elements_in_entities(EntIter begin, EntIter end) + * -- adds elements in entities to neighbours database. + * The entity type must not be GEntity. The value type + * of the iterators must be a pointer to an entity. + * begin (I) iterator/pointer to first entity pointer + * end (I) iterator/pointer to one-past-last entity pointer + * + * template <typename Ent> + * void add_elements_in_entities(Ent **pEnt, unsigned int n) + * -- adds elements in entities to neighbours database. + * The entity type must not be GEntity. The array + * element must be a pointer to an element. + * pEnt (I) first entity in the array + * n (I) number of entities in the array + * + * template <typename EntPtr> + * void add_elements_in_entity(EntPtr entity) + * -- adds elements in a single entity to the neighbours + * database. The entity type must not be GEntity. The + * dereferenced quantity must be a pointer to an entity. + * entity (I) pointer to an entity + * + * The routines that generate a database of neighbours from containers of + * elements do not require the user to state the specific type of element. + * If the container constains a specific element pointer, compiler-time + * polymorphism is used. If the container contains the base pointers + * MElement*, run-time switching based on element introspection is used. + * + * template <typename ElemIter> + * void add_elements(ElemIter begin, ElemIter end) + * -- adds elements from iterator sequence to the neighbours + * database. + * begin (I) iterator/pointer to first element pointer + * end (I) iterator/pointer to one-past-last element pointer + * + * template <typename Elem> + * void add_elements(Elem **pElem, const unsigned int n) + * -- adds elements in an array to the neighbours database. + * pElem (I) first element in the array + * n (I) number of elements in the array + * + * Routines for querying the neighbours database + * --------------------------------------------- + * + * unsigned int max_vertex_neighbours() + * -- returns max number of elements sharing a vertex. This + * is also the max number of elements sharing any + * bounding polytope. + * + * unsigned int max_edge_neighbours() + * -- returns max number of elements sharing an edge + * + * unsigned int max_face_neighbours() + * -- returns max number of elements sharing a face + * + * int vertex_neighbours(Vertex_const_iterator &itVert, + * std::vector<MElement*> &vElem) + * -- return all elements sharing a vertex + * itVert (I) iterator to a unique vertex. Avoids a find() + * vElem (O) vector with elements loaded via push_back + * return number of neighbour elements + * + * int vertex_neighbours(Vertex_const_iterator &itVert, MElement **pElem) + * -- return all elements sharing a vertex + * itVert (I) iterator to a unique vertex. Avoids a find() + * pElem (O) array with elements loaded starting at pElem[0] + * return number of neighbour elements + * + * int vertex_neighbours(MVertex *const vertex, std::vector<MElement*> &vElem) + * -- returns all elements sharing a vertex + * vertex (I) pointer to vertex. It must be found in (hash_)map + * vElem (O) vector with elements loaded via push_back + * return number of neighbour elements. 0 if vertex not found + * + * int vertex_neighbours(MVertex *const vertex, MElement **pElem) + * -- returns all elements sharing a vertex + * vertex (I) pointer to vertex. It must be found in (hash_)map + * pElem (O) array with elements loaded starting at pElem[0] + * return number of neighbour elements. 0 if vertex not found + * + * void edge_neighbours(Edge_const_iterator &itEdge, + * std::vector<MElement*> &vElem) + * -- return all elements sharing a edge + * itEdge (I) iterator to a unique edge. Avoids a find() + * vElem (O) vector with elements loaded via push_back + * return number of neighbour elements + * + * void edge_neighbours(Edge_const_iterator &itEdge, MElement **pElem) + * -- return all elements sharing a edge + * itEdge (I) iterator to a unique edge. Avoids a find() + * pElem (O) array with elements loaded starting at pElem[0] + * return number of neighbour elements + * + * int edge_neighbours(MEdge *const edge, std::vector<MElement*> &vElem) + * -- returns all elements sharing a edge + * edge (I) pointer to edge. It must be found in (hash_)map + * vElem (O) vector with elements loaded via push_back + * return number of neighbour elements. 0 if edge not found + * + * int edge_neighbours(MEdge *const edge, MElement **pElem) + * -- returns all elements sharing a edge + * edge (I) pointer to edge. It must be found in (hash_)map + * pElem (O) array with elements loaded starting at pElem[0] + * return number of neighbour elements. 0 if edge not found + * + * void face_neighbours(Face_const_iterator &itFace, + * std::vector<MElement*> &vElem) + * -- return all elements sharing a face + * itFace (I) iterator to a unique face. Avoids a find() + * vElem (O) vector with elements loaded via push_back + * return number of neighbour elements + * + * void face_neighbours(Face_const_iterator &itFace, MElement **pElem) + * -- return all elements sharing a face + * itFace (I) iterator to a unique face. Avoids a find() + * pElem (O) array with elements loaded starting at pElem[0] + * return number of neighbour elements + * + * int face_neighbours(MFace *const face, std::vector<MElement*> &vElem) + * -- returns all elements sharing a face + * face (I) pointer to face. It must be found in (hash_)map + * vElem (O) vector with elements loaded via push_back + * return number of neighbour elements. 0 if face not found + * + * int face_neighbours(MFace *const face, MElement **pElem) + * -- returns all elements sharing a face + * face (I) pointer to face. It must be found in (hash_)map + * pElem (O) array with elements loaded starting at pElem[0] + * return number of neighbour elements. 0 if face not found + * + * unsigned int vertex_num_neighbours(MVertex *const vertex) const + * -- returns the number of elements sharing a vertex + * + * unsigned int edge_num_neighbours(const MEdge& edge) const + * -- returns the number of elements sharing an edge + * + * unsigned int edge_num_neighbours(const MFace& face) const + * -- returns the number of elements sharing a face + * + * void clear() -- clears the neighbours database. Use this before + * constructing a new database of element neighbours. + * Otherwise, new elements are added to the existing + * database. + * + * MElement *element_neighbour(MElement *const element, + * const unsigned int iPolytope) const + * -- find the neighbour element across the d-1 bounding + * polytope. E.g., for a triangle, find an element + * across an edge. + * element (I) element to find + * iPolytope (I) which polytope to find. E.g., edge 1 + * return the neighbour element or 0 if polytope not found + * in neighbours database. + * + * Example + * ======= + * + *------------------------------------------------------------------------------ + + // Examples for adding elements from containers (the type of container doesn't + // matter. + + MNeighbour meshNeighbour; + + std::list<GEntity*> faceEnt1; // Assume known to be GFace type + meshNeighbour.add_elements_in_entities<GFace>(faceEnt1.begin(), + faceEnt1.end()); + + std::vector<GFace*> faceEnt2; + meshNeighbour.add_elements_in_entities(faceEnt2.begin(), faceEnt2.end()); + meshNeighbour.add_elements_in_entity(faceEnt2.begin()); + + GEntity *faceEnt3[2]; // Assume known to be GFace type + meshNeighbour.add_elements_in_entities<GFace>(faceEnt3, 2); + + GFace *faceEnt4[10]; + meshNeighbour.add_elements_in_entities(faceEnt4, 10); + + std::list<MElement*> elem1; + // Run time introspection. Elements can be mixed. + meshNeighbour.add_elements(elem1.begin(), elem1.end()); + + std::vector<MTriangle*> elem2; + // Compile time introspection. + meshNeighbour.add_elements(elem2.begin(), elem2.end()); + + MElement *elem3[5]; + // Run time introspection. Elements can be mixed. + meshNeighbour.add_elements(elem3, 5); + + MQuadrangle *elem4[6]; + // Compile time introspection. + meshNeighbour.add_elements(elem4, 6); + + *------------------------------------------------------------------------------ + * + ******************************************************************************/ + +class MNeighbour +{ + + +/*============================================================================== + * Iterators + *============================================================================*/ + + public: + + // Iterators over polytopes + typedef PolytopeIterator<MVertex*> Vertex_const_iterator; + typedef PolytopeIterator<MEdge> Edge_const_iterator; + typedef PolytopeIterator<MFace> Face_const_iterator; + + // Begin and end points for these iterators + Vertex_const_iterator vertex_begin() + { + return Vertex_const_iterator(vertNRange.begin()); + } + Vertex_const_iterator vertex_end() + { + return Vertex_const_iterator(vertNRange.end()); + } + Edge_const_iterator edge_begin() + { + return Edge_const_iterator(edgeNRange.begin()); + } + Edge_const_iterator edge_end() + { + return Edge_const_iterator(edgeNRange.end()); + } + Face_const_iterator face_begin() + { + return Face_const_iterator(faceNRange.begin()); + } + Face_const_iterator face_end() + { + return Face_const_iterator(faceNRange.end()); + } + + +/*============================================================================== + * Template meta-programming classes + *============================================================================*/ + + private: + + template <typename Elem, typename Polytope, unsigned int NP> + struct FindNeighbours; + template <typename Ent, unsigned int N = EntTr<Ent>::numElemTypes> + struct FindNeighboursInEntity; + + +/*============================================================================== + * Member functions and data + *============================================================================*/ + + public: + +//--Default constructor. + + // The constructor cannot really do anything because the initialization + // functions (find_neighbours_*) cannot perform template argument deduction. + MNeighbour() : maxVertNeighbours(0), maxEdgeNeighbours(0), + maxFaceNeighbours(0) { } + +/*--------------------------------------------------------------------* + * Elements added from entities. + *--------------------------------------------------------------------*/ + +//--Compute database of neighbour elements. The entity pointers may be of a +//--base or specific type and the call must state the specific type. + + template <typename Ent, typename EntIter> + void add_elements_in_entities(EntIter begin, EntIter end) { + + // Check the Ent and EntIter types + // NOTE: If the compiler sent you here, you're using an invalid entity as a + // template parameter and/or and invalid iterator. See struct + // ValidEntityIterator above for valid types + typedef typename ValidSpecEntityIterator<Ent, + typename EntIter::value_type>::Type Check; + + // Find the neighbours of each vertex, edge, and face + for(EntIter itEnt = begin; itEnt != end; ++itEnt) { + Ent *entity = static_cast<Ent*>(*itEnt); + FindNeighboursInEntity<Ent>::eval(entity, vertNRange, edgeNRange, + faceNRange, neighbours); + } + maxNeighbours(); + } + +//--Same as the routine above except the arguments are pointers instead of +//--iterators. Hence, value_type does not exist. + + template <typename Ent, typename EntP> + void add_elements_in_entities(EntP **pEnt, unsigned int n) { + + // Check the Ent and EntP types + // NOTE: If the compiler sent you here, you're using an invalid entity as a + // template parameter and/or invalid pointers. See struct + // ValidEntityIterator above for valid types + typedef typename ValidSpecEntityIterator<Ent, EntP*>::Type Check; + + // Find the neighbours of each vertex, edge, and face + while(n--) { + Ent *entity = static_cast<Ent*>(*pEnt++); + FindNeighboursInEntity<Ent>::eval(entity, vertNRange, edgeNRange, + faceNRange, neighbours); + } + maxNeighbours(); + } + +//--Compute database of neighbour elements. The entity pointers must be of a +//--specific type (not a base class). The type of entity is determined from +//--Iterator::value_type and does not need to be stated. + + template <typename EntIter> + void add_elements_in_entities(EntIter begin, EntIter end) { + + // Check the value type in EntIter (it must not be GEntity*) + // NOTE: If the compiler sent you here, you're using an invalid entity as a + // template parameter and/or and invalid iterator for the constructor. See + // struct ValidEntityIterator above for valid types + typedef typename ValidEntityIterator<typename EntIter::value_type>:: + Type Ent; + + // Find the neighbours of each vertex, edge, and face + for(EntIter itEnt = begin; itEnt != end; ++itEnt) { + FindNeighboursInEntity<Ent>::eval(*itEnt, vertNRange, edgeNRange, + faceNRange, neighbours); + } + maxNeighbours(); + } + +//--Same as the routine above except the arguments are pointers instead of +//--iterators. Hence, value_type does not exist. + + template <typename Ent> + void add_elements_in_entities(Ent **pEnt, unsigned int n) { + + // Check the type Ent (it must not be GEntity) + // NOTE: If the compiler sent you here, you're using an invalid entity as a + // pointer See struct ValidEntityIterator above for valid types + typedef typename ValidEntityIterator<Ent*>::Type Check; + + // Find the neighbours of each vertex, edge, and face + while(n--) { + FindNeighboursInEntity<Ent>::eval(*pEnt++, vertNRange, edgeNRange, + faceNRange, neighbours); + } + maxNeighbours(); + } + +//--Find neighbours from the elements attached to a pointer to a single entity. +//--The type of entity does not need to be stated. + + template <typename EntPtr> + void add_elements_in_entity(EntPtr entity) { + + // Check the type of EntPtr (it must not be GEntity*) + // NOTE: If the compiler sent you here, you're using an invalid entity as a + // pointer See struct ValidEntityIterator above for valid types + typedef typename ValidEntityIterator<EntPtr>::Type Ent; + + // Find the neighbours of each vertex, edge, and face + FindNeighboursInEntity<Ent>::eval(entity, vertNRange, edgeNRange, + faceNRange, neighbours); + maxNeighbours(); + } + +/*--------------------------------------------------------------------* + * Elements added directly + *--------------------------------------------------------------------*/ + +//--Add elements from a container using iterators + + template <typename ElemIter> + void add_elements(ElemIter begin, ElemIter end) { + + // Strip the pointer to the element type and convert it to first order + typedef typename ElemBaseOrder< + typename StripPointer< + typename ElemIter::value_type + >::Type + >::Order1 Elem_1o; + + // Check for a valid type of element + // NOTE: If the compiler sent you here, you're using an invalid iterator. + // The dereferenced object needs to be a pointer to an element. + typedef typename ValidElement<Elem_1o>::Type Check; + + add_elements1<Elem_1o, ElemIter>(begin, end); + } + +//--Add elements from an array of pointers (value_type does not exist) + + template <typename Elem> + void add_elements(Elem **pElem, const unsigned int n) { + + // Convert the element type to first order + typedef typename ElemBaseOrder<Elem>::Order1 Elem_1o; + + // Check for a valid type of element + // NOTE: If the compiler sent you here, you're using an invalid pointer. + // The dereferenced object needs to be a pointer to an element. + typedef typename ValidElement<Elem_1o>::Type Check; + + add_elements1<Elem_1o, Elem**>(pElem, pElem+n); + } + +/*--------------------------------------------------------------------* + * Query the database + *--------------------------------------------------------------------*/ + +//--Get the max number of elements sharing a vertex, edge, or face + + unsigned int max_vertex_neighbours() const { return maxVertNeighbours; } + unsigned int max_edge_neighbours() const { return maxEdgeNeighbours; } + unsigned int max_face_neighbours() const { return maxFaceNeighbours; } + +//--Return elements that share a vertex + + // From a vertex iterator + int vertex_neighbours(Vertex_const_iterator &itVert, + std::vector<MElement*> &vElem) const + { + NeighboursConstIterator itElem = itVert.begin_neighbours(); + for(unsigned int n = itVert.num_neighbours(); n--;) + vElem.push_back(*itElem++); + return itVert.num_neighbours(); + } + int vertex_neighbours(Vertex_const_iterator &itVert, MElement **pElem) const + { + NeighboursConstIterator itElem = itVert.begin_neighbours(); + for(unsigned int n = itVert.num_neighbours(); n--;) + *pElem++ = *itElem++; + return itVert.num_neighbours(); + } + // From a vertex + int vertex_neighbours(MVertex *const vertex, + std::vector<MElement*> &vElem) const + { + VertNRangeConstIterator itVert = vertNRange.find(vertex); + if(itVert == vertNRange.end()) return 0; // Vertex not found + NeighboursConstIterator itElem = itVert->second.begin; + for(unsigned int n = itVert->second.num; n--;) vElem.push_back(*itElem++); + return itVert->second.num; + } + int vertex_neighbours(MVertex *const vertex, MElement **pElem) const + { + VertNRangeConstIterator itVert = vertNRange.find(vertex); + if(itVert == vertNRange.end()) return 0; // Vertex not found + NeighboursConstIterator itElem = itVert->second.begin; + for(unsigned int n = itVert->second.num; n--;) *pElem++ = *itElem++; + return itVert->second.num; + } + +//--Return elements that share an edge + + // From an edge iterator + int edge_neighbours(Edge_const_iterator &itEdge, + std::vector<MElement*> &vElem) const + { + NeighboursConstIterator itElem = itEdge.begin_neighbours(); + for(unsigned int n = itEdge.num_neighbours(); n--;) + vElem.push_back(*itElem++); + return itEdge.num_neighbours(); + } + int edge_neighbours(Edge_const_iterator &itEdge, MElement **pElem) const + { + NeighboursConstIterator itElem = itEdge.begin_neighbours(); + for(unsigned int n = itEdge.num_neighbours(); n--;) + *pElem++ = *itElem++; + return itEdge.num_neighbours(); + } + // From an edge + int edge_neighbours(const MEdge& edge, std::vector<MElement*> &vElem) const + { + EdgeNRangeConstIterator itEdge = edgeNRange.find(edge); + if(itEdge == edgeNRange.end()) return 0; // Edge not found + NeighboursConstIterator itElem = itEdge->second.begin; + for(unsigned int n = itEdge->second.num; n--;) vElem.push_back(*itElem++); + return itEdge->second.num; + } + int edge_neighbours(const MEdge& edge, MElement **pElem) const + { + EdgeNRangeConstIterator itEdge = edgeNRange.find(edge); + if(itEdge == edgeNRange.end()) return 0; // Edge not found + NeighboursConstIterator itElem = itEdge->second.begin; + for(unsigned int n = itEdge->second.num; n--;) *pElem++ = *itElem++; + return itEdge->second.num; + } + +//--Return elements that share a face + + // From a face iterator + int face_neighbours(Face_const_iterator &itFace, + std::vector<MElement*> &vElem) const + { + NeighboursConstIterator itElem = itFace.begin_neighbours(); + for(unsigned int n = itFace.num_neighbours(); n--;) + vElem.push_back(*itElem++); + return itFace.num_neighbours(); + } + int face_neighbours(Face_const_iterator &itFace, MElement **pElem) const + { + NeighboursConstIterator itElem = itFace.begin_neighbours(); + for(unsigned int n = itFace.num_neighbours(); n--;) + *pElem++ = *itElem++; + return itFace.num_neighbours(); + } + // From a face + int face_neighbours(const MFace& face, std::vector<MElement*> &vElem) const + { + FaceNRangeConstIterator itFace = faceNRange.find(face); + if(itFace == faceNRange.end()) return 0; // Face not found + NeighboursConstIterator itElem = itFace->second.begin; + for(unsigned int n = itFace->second.num; n--;) vElem.push_back(*itElem++); + return itFace->second.num; + } + int face_neighbours(const MFace& face, MElement **pElem) const + { + FaceNRangeConstIterator itFace = faceNRange.find(face); + if(itFace == faceNRange.end()) return 0; // Face not found + NeighboursConstIterator itElem = itFace->second.begin; + for(unsigned int n = itFace->second.num; n--;) *pElem++ = *itElem++; + return itFace->second.num; + } + +//--Return the number of elements that share a vertex + + unsigned int vertex_num_neighbours(MVertex *const vertex) const + { + VertNRangeConstIterator itVert = vertNRange.find(vertex); + if(itVert == vertNRange.end()) return 0; // Vertex not found + return itVert->second.num; + } + +//--Return the number of elements that share an edge + + unsigned int edge_num_neighbours(const MEdge& edge) const + { + EdgeNRangeConstIterator itEdge = edgeNRange.find(edge); + if(itEdge == edgeNRange.end()) return 0; // Edge not found + return itEdge->second.num; + } + +//--Return the number of elements that share a face + + unsigned int face_num_neighbours(const MFace& face) const + { + FaceNRangeConstIterator itFace = faceNRange.find(face); + if(itFace == faceNRange.end()) return 0; // Face not found + return itFace->second.num; + } + +//--Clear the containers + + void clear() + { + vertNRange.clear(); + edgeNRange.clear(); + faceNRange.clear(); + neighbours.clear(); + maxVertNeighbours = 0; + maxEdgeNeighbours = 0; + maxFaceNeighbours = 0; + } + +//--Return the element neighbour across a d-1 polytope + + MElement *element_neighbour(MElement *const element, + const unsigned int iPolytope) const + { + unsigned int num; + NeighboursConstIterator itElem; + switch(element->getTypeForMSH()) { + case MSH_LIN_2: + case MSH_LIN_3: + { + MVertex *vertex = element->getVertex(iPolytope); + VertNRangeConstIterator itVert = vertNRange.find(vertex); + if(itVert == vertNRange.end()) return 0; + num = itVert->second.num; + itElem = itVert->second.begin; + } + break; + case MSH_TRI_3: + case MSH_TRI_6: + case MSH_QUA_4: + case MSH_QUA_8: + case MSH_QUA_9: + { + MEdge edge = element->getEdge(iPolytope); + EdgeNRangeConstIterator itEdge = edgeNRange.find(edge); + if(itEdge == edgeNRange.end()) return 0; + num = itEdge->second.num; + itElem = itEdge->second.begin; + } + break; + case MSH_TET_4: + case MSH_TET_10: + case MSH_HEX_8: + case MSH_HEX_20: + case MSH_HEX_27: + case MSH_PRI_6: + case MSH_PRI_15: + case MSH_PRI_18: + case MSH_PYR_5: + case MSH_PYR_13: + case MSH_PYR_14: { + MFace face = element->getFace(iPolytope); + FaceNRangeConstIterator itFace = faceNRange.find(face); + if(itFace == faceNRange.end()) return 0; + num = itFace->second.num; + itElem = itFace->second.begin; + } + break; + } + if(*itElem != element) return *itElem; + if(num > 1) { + ++itElem; + if(*itElem != element) return *itElem; + } + return 0; + } + +private: + +//--Data members + + VertNRange vertNRange; + EdgeNRange edgeNRange; + FaceNRange faceNRange; + Neighbours neighbours; + unsigned int maxVertNeighbours; + unsigned int maxEdgeNeighbours; + unsigned int maxFaceNeighbours; + +//--Working routine to determine the neighbours from elements + + template <typename Elem, typename ElemIter> + void add_elements1(ElemIter begin, ElemIter end) + { + // Test if the type of element is known + if(ElemTr<Elem>::numVertex) { // 0 only for MElement + // Find the neighbours of each vertex, edge, and face + for(ElemIter itElem = begin; itElem != end; ++itElem) { + // Find neighbours for vertices + FindNeighbours<Elem, MVertex*, ElemTr<Elem>::numVertex>:: + eval(*itElem, vertNRange, neighbours); + // Find neighbours for edges + FindNeighbours<Elem, MEdge, ElemTr<Elem>::numEdge>:: + eval(*itElem, edgeNRange, neighbours); + // Find neighbours for faces + FindNeighbours<Elem, MFace, ElemTr<Elem>::numFace>:: + eval(*itElem, faceNRange, neighbours); + } + } + else { + // We only have an iterator to an MElement* and have to check the type in + // run-time. + for(ElemIter itElem = begin; itElem != end; ++itElem) { + switch((*itElem)->getTypeForMSH()) { + case MSH_LIN_2: + case MSH_LIN_3: + find_polytope_neighbours<MLine>(*itElem); + break; + case MSH_TRI_3: + case MSH_TRI_6: + find_polytope_neighbours<MTriangle>(*itElem); + break; + case MSH_QUA_4: + case MSH_QUA_8: + case MSH_QUA_9: + find_polytope_neighbours<MQuadrangle>(*itElem); + break; + case MSH_TET_4: + case MSH_TET_10: + find_polytope_neighbours<MTetrahedron>(*itElem); + break; + case MSH_HEX_8: + case MSH_HEX_20: + case MSH_HEX_27: + find_polytope_neighbours<MHexahedron>(*itElem); + break; + case MSH_PRI_6: + case MSH_PRI_15: + case MSH_PRI_18: + find_polytope_neighbours<MPrism>(*itElem); + break; + case MSH_PYR_5: + case MSH_PYR_13: + case MSH_PYR_14: + find_polytope_neighbours<MPyramid>(*itElem); + break; + } + } + } + maxNeighbours(); + } + +//--Find the neighbours sharing each polytope + + template <typename Elem> + void find_polytope_neighbours(MElement *element) + { + // Find neighbours for vertices + FindNeighbours<Elem, MVertex*, ElemTr<Elem>::numVertex>:: + eval(static_cast<Elem*>(element), vertNRange, neighbours); + // Find neighbours for edges + FindNeighbours<Elem, MEdge, ElemTr<Elem>::numEdge>:: + eval(static_cast<Elem*>(element), edgeNRange, neighbours); + // Find neighbours for faces + FindNeighbours<Elem, MFace, ElemTr<Elem>::numFace>:: + eval(static_cast<Elem*>(element), faceNRange, neighbours); + } + +//--Compute max neighbours + + void maxNeighbours() + { + maxVertNeighbours = 0; + for(VertNRangeConstIterator itVert = vertNRange.begin(); + itVert != vertNRange.end(); ++itVert) + maxVertNeighbours = std::max(maxVertNeighbours, itVert->second.num); + maxEdgeNeighbours = 0; + for(EdgeNRangeConstIterator itEdge = edgeNRange.begin(); + itEdge != edgeNRange.end(); ++itEdge) + maxEdgeNeighbours = std::max(maxEdgeNeighbours, itEdge->second.num); + maxFaceNeighbours = 0; + for(FaceNRangeConstIterator itFace = faceNRange.begin(); + itFace != faceNRange.end(); ++itFace) + maxFaceNeighbours = std::max(maxFaceNeighbours, itFace->second.num); + } + +}; + + +/*============================================================================== + * Template meta-programming classes + *============================================================================*/ + +/*-------------------------------------------------------------------- + * This is the main working routine for finding the elements sharing + * a lower-dimension polytope (i.e, the structures bounding the + * element: vertex, edge, or face). It is templated for any type of + * polytope and uses template meta-programming to unroll the loop over + * the number of that type of polytope in the element. + *--------------------------------------------------------------------*/ + +//--Entry point + +template <typename Elem, // Elem is the type of element + typename Polytope, // Polytope is a lower dimensional + // bounding object (MVertex*, MEdge, or + // MFace) of the element. We want to + // find the elements sharing a given + // Polytope. + unsigned int NP> // NP is an index through the number + // of Polytope in the element (e.g., + // number of vertices) +struct MNeighbour::FindNeighbours +{ + typedef typename PolytopeTr<Polytope>::PolytopeNRange PolytopeNRange; + static void eval(Elem *element, PolytopeNRange &polytopeNRange, + Neighbours &neighbours) + { + Polytope polytope = PolytopeTr<Polytope>::template + getPolytope<Elem>(element, NP-1); + Range_t &range = polytopeNRange[polytope]; + if(range.num == 0) range.begin = neighbours.end(); + range.begin = neighbours.insert(range.begin, element); + ++range.num; + FindNeighbours<Elem, Polytope, NP-1>::eval(element, polytopeNRange, + neighbours); + } +}; + +//--Terminate loop when NP == 1 + +template <typename Elem, typename Polytope> +struct MNeighbour::FindNeighbours<Elem, Polytope, 1> +{ + typedef typename PolytopeTr<Polytope>::PolytopeNRange PolytopeNRange; + static void eval(Elem *element, PolytopeNRange &polytopeNRange, + Neighbours &neighbours) + { + Polytope polytope = PolytopeTr<Polytope>::template + getPolytope<Elem>(element, 0); + Range_t &range = polytopeNRange[polytope]; + if(range.num == 0) range.begin = neighbours.end(); + range.begin = neighbours.insert(range.begin, element); + ++range.num; + } +}; + +//--Nothing to do if the dimension of this polytope is equal to or greater than +//--that of the element (e.g., no faces (2D) in a 2D element). This is +//--indicated by NP = 0. + +template <typename Elem, typename Polytope> +struct MNeighbour::FindNeighbours<Elem, Polytope, 0> +{ + typedef typename PolytopeTr<Polytope>::PolytopeNRange PolytopeNRange; + static void eval(Elem *element, PolytopeNRange &polytopeNRange, + Neighbours &neighbours) { } +}; + +/*--------------------------------------------------------------------* + * This class uses traits to determine the element types in an entity + * and iterate over them. A template meta-programming loop is used to + * iterate over the types of elements. + *--------------------------------------------------------------------*/ + +//--Entry point + +template <typename Ent, unsigned int N> +struct MNeighbour::FindNeighboursInEntity { + typedef typename EntElemTr<Ent, N>::Elem Elem; + static void eval(const Ent *const entity, VertNRange &vertNRange, + EdgeNRange &edgeNRange, FaceNRange &faceNRange, + Neighbours &neighbours) + { + for(typename EntElemTr<Ent, N>::ConstElementIterator itElem = + EntElemTr<Ent, N>::begin(entity); + itElem != EntElemTr<Ent, N>::end(entity); ++itElem) { + // Find neighbours for vertices + FindNeighbours<Elem, MVertex*, ElemTr<Elem>::numVertex>:: + eval(*itElem, vertNRange, neighbours); + // Find neighbours for edges + FindNeighbours<Elem, MEdge, ElemTr<Elem>::numEdge>:: + eval(*itElem, edgeNRange, neighbours); + // Find neighbours for faces + FindNeighbours<Elem, MFace, ElemTr<Elem>::numFace>:: + eval(*itElem, faceNRange, neighbours); + } + FindNeighboursInEntity<Ent, N-1>::eval(entity, vertNRange, edgeNRange, + faceNRange, neighbours); + } +}; + +//--Terminate loop when N = 1 + +template <typename Ent> +struct MNeighbour::FindNeighboursInEntity<Ent, 1> { + typedef typename EntElemTr<Ent, 1>::Elem Elem; + static void eval(const Ent *const entity, VertNRange &vertNRange, + EdgeNRange &edgeNRange, FaceNRange &faceNRange, + Neighbours &neighbours) + { + for(typename EntElemTr<Ent, 1>::ConstElementIterator itElem = + EntElemTr<Ent, 1>::begin(entity); + itElem != EntElemTr<Ent, 1>::end(entity); ++itElem) { + // Find neighbours for vertices + FindNeighbours<Elem, MVertex*, ElemTr<Elem>::numVertex>:: + eval(*itElem, vertNRange, neighbours); + // Find neighbours for edges + FindNeighbours<Elem, MEdge, ElemTr<Elem>::numEdge>:: + eval(*itElem, edgeNRange, neighbours); + // Find neighbours for faces + FindNeighbours<Elem, MFace, ElemTr<Elem>::numFace>:: + eval(*itElem, faceNRange, neighbours); + } + } +}; + +#endif