diff --git a/dumux/geometry/geometricentityset.hh b/dumux/geometry/geometricentityset.hh index 4b69c89c9ae3b2e175560acea4216078c98b4364..78b308f7ac8c44594267d9312e678c4375e52cd1 100644 --- a/dumux/geometry/geometricentityset.hh +++ b/dumux/geometry/geometricentityset.hh @@ -14,7 +14,12 @@ #ifndef DUMUX_GEOMETRY_GEOMETRIC_ENTITY_SET_HH #define DUMUX_GEOMETRY_GEOMETRIC_ENTITY_SET_HH +#include <array> +#include <vector> #include <memory> +#include <utility> +#include <initializer_list> + #include <dune/grid/common/mcmgmapper.hh> #include <dune/geometry/multilineargeometry.hh> #include <dumux/common/entitymap.hh> @@ -98,6 +103,52 @@ private: std::shared_ptr<const EntityMap> entityMap_; }; +} // end namespace Dumux + +#ifndef DOXYGEN +namespace Dumux::Detail::GeometricEntity { + +/*! +* \brief Wrapper to turn a geometry into a geometric entity +*/ +template<class GeoType> +class EntityWrapper +{ +public: + using Geometry = GeoType; + + /*! + * \brief Constructor + */ + EntityWrapper(const Geometry& geo, const std::size_t index) : geo_(geo), index_(index) {} + + /*! + * \brief Constructor + */ + EntityWrapper(Geometry&& geo, const std::size_t index) : geo_(std::move(geo)), index_(index) {} + + /*! + * \brief Returns the geometry + */ + const Geometry& geometry() const + { return geo_; } + + /*! + * \brief Returns the index of the geometry + */ + std::size_t index() const + { return index_; } + +private: + Geometry geo_; + std::size_t index_; +}; + +} // end namespace Dumux::Detail::GeometricEntity +#endif // DOXYGEN + +namespace Dumux { + /*! * \ingroup Geometry * \brief An interface for a set of geometric entities @@ -107,43 +158,8 @@ private: template<class GeoType> class GeometriesEntitySet { - /*! - * \brief Wrapper to turn a geometry into a geometric entity - */ - class EntityWrapper - { - public: - using Geometry = GeoType; - - /*! - * \brief Constructor - */ - EntityWrapper(const Geometry& geo, const std::size_t index) : geo_(geo), index_(index) {} - - /*! - * \brief Constructor - */ - EntityWrapper(Geometry&& geo, const std::size_t index) : geo_(std::move(geo)), index_(index) {} - - /*! - * \brief Returns the geometry - */ - const Geometry& geometry() const - { return geo_; } - - /*! - * \brief Returns the index of the geometry - */ - std::size_t index() const - { return index_; } - - private: - Geometry geo_; - std::size_t index_; - }; - public: - using Entity = EntityWrapper; + using Entity = Detail::GeometricEntity::EntityWrapper<GeoType>; /*! * \brief Constructor for initializer_list @@ -223,6 +239,90 @@ private: std::vector<Entity> entities_; }; +/*! + * \ingroup Geometry + * \brief An interface for a fixed-size set of geometric entities + * \note This can be used e.g. to construct a bounding box volume hierarchy of a grid + * It defines the minimum requirement for such a set + */ +template<class GeoType, std::size_t N> +class FixedSizeGeometriesEntitySet +{ + template<class GT, std::size_t... I> + FixedSizeGeometriesEntitySet(GT&& gt, std::index_sequence<I...>) + : entities_{{ Entity(std::get<I>(gt), I)... }} + { static_assert(sizeof...(I) == N, "Number of geometries must match the size of the entity set"); } + +public: + using Entity = Detail::GeometricEntity::EntityWrapper<GeoType>; + + /*! + * \brief Constructor with one or more geometries as arguments + * \note The number of geometries must match the size of the entity set + */ + template<class... G> + FixedSizeGeometriesEntitySet(G&&... g) + : FixedSizeGeometriesEntitySet(std::forward_as_tuple(std::forward<G>(g)...), std::make_index_sequence<N>{}) + {} + + /*! + * \brief The world dimension of the entity set + */ + static constexpr int dimensionworld = Entity::Geometry::coorddimension; + + /*! + * \brief the coordinate type + */ + using ctype = typename Entity::Geometry::ctype; + + /*! + * \brief the number of entities in this set + */ + constexpr auto size() const + { return entities_.size(); } + + /*! + * \brief begin iterator to enable range-based for iteration + */ + decltype(auto) begin() const + { return entities_.begin(); } + + /*! + * \brief end iterator to enable range-based for iteration + */ + decltype(auto) end() const + { return entities_.end(); } + + /*! + * \brief get an entities index + */ + template<class Entity> + std::size_t index(const Entity& e) const + { return e.index(); } + + /*! + * \brief get an entity from an index + */ + const Entity& entity(std::size_t index) const + { assert(index < entities_.size()); return entities_[index]; } + +private: + std::array<Entity, N> entities_; +}; + +/*! + * \ingroup Geometry + * \brief An interface for a geometric entity set with a single geometry + */ +template<class GeoType> +class SingleGeometryEntitySet +: public FixedSizeGeometriesEntitySet<GeoType, 1> +{ + using ParentType = FixedSizeGeometriesEntitySet<GeoType, 1>; +public: + using ParentType::ParentType; +}; + } // end namespace Dumux #endif diff --git a/test/geometry/test_intersectionentityset.cc b/test/geometry/test_intersectionentityset.cc index 1aa6520075b2b840629f6c17454dc600a9ed4943..2e6703ce151dac45c0fee946f844fedc37e6a955 100644 --- a/test/geometry/test_intersectionentityset.cc +++ b/test/geometry/test_intersectionentityset.cc @@ -152,6 +152,31 @@ int main (int argc, char *argv[]) testPolyLineIntersections(i, j); } + { + std::cout << "\nIntersect two polylines testing fixed size geometric entity sets:\n" << std::endl; + std::cout << "-- Test number of segments: " << 1 << " and " << 2 << "\n"; + + using Geo = Dune::AffineGeometry<double, 1, 2>; + using Point = Geo::GlobalCoordinate; + + // once test constructor with l-values + const auto geo1 = Geo(Dune::GeometryTypes::line, std::array<Point, 2>{{Point({0.0, 0.0}), Point({1.0, 1.0})}}); + const auto geo2 = Geo(Dune::GeometryTypes::line, std::array<Point, 2>{{Point({1.0, 1.0}), Point({2.0, 2.0})}}); + auto geoSet0 = std::make_shared<FixedSizeGeometriesEntitySet<Geo, 2>>(geo1, geo2); + + // once test constructor with move semantics + auto geoSet1 = std::make_shared<SingleGeometryEntitySet<Geo>>( + Geo(Dune::GeometryTypes::line, std::array<Point, 2>{{Point({0.0, 0.0}), Point({2.0, 2.0})}}) + ); + + IntersectionEntitySet<FixedSizeGeometriesEntitySet<Geo, 2>, SingleGeometryEntitySet<Geo>> intersectionEntitySet; + intersectionEntitySet.build(geoSet0, geoSet1); + + if (intersectionEntitySet.size() != 2) + DUNE_THROW(Dune::Exception, "Wrong number of line segment intersections." + << " Expected " << 2 << " got " << intersectionEntitySet.size()); + } + std::cout << "All tests passed!" << std::endl; return 0; }