VirtualRefinement does all of this switch() statements for you. It defines a common virtual base class per dimension, and derives one class for each geometryType and coerceTo from that class. The derived classes simply wrap the non-virtual classes from Refinement. This makes it possible to treat each geometryType (of a given dimension) the same, and thus eleminates the many repetitions of lots of code.
But the case statements are not totally gone yet. VirtualRefinement does these statements once and for all by wrapping them into the buildRefinement() function.
The user interface is modelled closely after the the Refinement interface. The main differences are:
refinementInstace.nElements(level);
RefinementTypedef::nElements(level);
template<int dimension> class VirtualRefinement { public: template<int Codimension> struct Codim { class SubEntityIterator; }; typedef VertexIterator; // These are aliases for Codim<codim>::SubEntityIterator typedef ElementIterator; typedef IndexVector; // This is a std::vector typedef CoordVector; // This is a FieldVector virtual int nVertices(int level) const; VertexIterator vBegin(int level) const; VertexIterator vEnd(int level) const; virtual int nElements(int level) const; ElementIterator eBegin(int level) const; ElementIterator eEnd(int level) const; };
The iterators have the same interface as the Refinement iterators except that IndexVector is a std::vector instead of a FieldVector (see above). Also the restriction that the Iterators are not derefencable applies.
template<int dimension> class VertexIterator { public: typedef VirtualRefinement<dimension> Refinement; int index() const; Refinement::CoordVector coords() const; }; template<int dimension> class ElementIterator { public: typedef VirtualRefinement<dimension> Refinement; int index() const; Refinement::IndexVector vertexIndices() const; };
template<int dimension, class CoordType> VirtualRefinement<dimension, CoordType> &buildRefinement(GeometryType geometryType, GeometryType coerceTo);
It is expected that you know the dimension and the coordinate type of the elements you want to refine at compile time.
The simple case is that you want to refine, say, quadrilaterals and the subentities should look like quadrilaterals as well. In that case you would call buildRefinement() like
VirtualRefinement<2, CoordType> &refinement = buildRefinement<2, CoordType>(quadrilateral, quadrilateral);
The more complicated case is that your entity is a quadrilateral, but the subentities should look like triangles. In this case call buildRefinement() like
VirtualRefinement<2, CoordType> &refinement = buildRefinement<2, CoordType>(quadrilateral, triangle);
Summary: geometryType is the geometry type of the entity you want to refine, while coerceTo is the geometry type of the subentities.
Everything else has been done for you automatically.
For each class Refinement<geometryType, CoordType, coercTo, dim> we provide a class VirtualRefinementImp<geometryType, CoordType, coercTo, dim>, which wraps the matching class Refinement<geometryType, CoordType, coercTo, dim> and derives from the matching base class VirtualRefinement<dimension, CoordType>. Each VirtualRefinementImp is a singleton and has a static instance() method which will return this instance as a reference to the base class VirtualRefinement. All this is done in a single template class.
What we do instead is having a wrapper class which conforms to the iterator interface and is the same for all VirtualRefinementIterators of a given dimension. This class contains a pointer to a polymorph backend object implementing the iterator. The various VirtualRefinementImps then derive from the abstract backend class and pass a pointer to a concrete backend object when instantiating an iterator.
The workaround is to create a class RefinementBuilder with a lone static method build() and to call that from buildRefinement(). Since RefinementBuilder is a class and not a function we can do partial specialisations.
It is probably possible to automatically generate the switch statements with linked lists of template structs, functions implementing the cases, and a recursive template function that will iterate over the list, but it is probably not worth the effort, as long as buildRefinement() is enough for the job.