#ifndef MEDUSA_BITS_DOMAINS_DOMAINSHAPE_FWD_HPP_ #define MEDUSA_BITS_DOMAINS_DOMAINSHAPE_FWD_HPP_ /** * @file * Declaration of base class for domain shapes. * * @example test/domains/DomainShape_test.cpp */ #include #include #include #include #include #include #include namespace mm { template class deep_copy_unique_ptr; template class DomainDiscretization; // These must be hidden during a doxygen run due to a bug in processing forward declarations. // See https://github.com/doxygen/doxygen/issues/8177 #ifndef DOXYGEN_RUN template class ShapeUnion; template class ShapeDifference; template class TranslatedShape; template class RotatedShape; #endif /** * Base class for geometric shapes of domains. This class implements the interface and * utilities for working with and discretizing geometric shapes. * * Usage example: * @snippet domains/DomainShape_test.cpp Domain shape usage example * @ingroup domains */ template class DomainShape { public: typedef vec_t vector_t; ///< Vector data type used in computations. typedef typename vec_t::Scalar scalar_t; ///< Scalar data type used in computation. /// Store dimension of the domain. enum { /** Dimensionality of the domain. */ dim = vec_t::dim }; protected: /** * Tolerance for the geometric operation of the domain. The domain should behave as if * it was `margin_` thicker. Default margin is `1e-10`. */ scalar_t margin_; public: /// Construct domain with default margin. DomainShape() : margin_(1e-10) {} /// Virtual destructor to properly destruct base class when invoked polymorphically. virtual ~DomainShape() = default; /// Returns current margin. scalar_t margin() const { return margin_; } /// Sets domain margin to `margin`. virtual void setMargin(scalar_t margin) { margin_ = margin; } /// Toggles the margin from positive to negative. void toggleMargin() { setMargin(-margin()); } /// Returns a shape representing a union of `*this` and `other`. ShapeUnion add(const DomainShape &other) const; /// Operator form of DomainShape::add. @sa add ShapeUnion operator+(const DomainShape &other) const { return add(other); } /// Returns a shape representing a difference of `*this` and `other`. ShapeDifference subtract(const DomainShape &other) const; /// Operator form of DomainShape::subtract. @sa subtract ShapeDifference operator-(const DomainShape &other) const { return subtract(other); } /// Project point to boundary using bisection along the line define by `unit_normal`. virtual std::pair projectPointToBoundary(const vec_t &point, const vec_t &unit_normal) const; /// Return true if `point` is not more than `margin()` outside the domain. virtual bool contains(const vec_t &point) const = 0; /// Return true if shape has `contains()` method implemented virtual bool hasContains() const { return true; } /** * Return the bounding box of the domain. Bounding box is returned in format * `bbox() == {{mx, my, ...}, {MX, MY, ...}}`, such that `mx <= Mx` and `my <= My` etc.\ * and that the whole domain is contained in the cuboid `[mx, my, ...] x [Mx, My, ...]`. */ virtual std::pair bbox() const = 0; /// Polymorphic clone pattern. virtual DomainShape *clone() const = 0; /// Output information about this shape to given output stream `os`. virtual std::ostream &print(std::ostream &os) const = 0; // Two types of discretizations: uniform step and density (will possibly add random later). // STEP -- calls density by default /** * Returns a discretization of the boundary of this shape with approximately uniform * distance `step` between nodes. `step` must be positive. Added nodes * are of type `type`, which must be non-positive. Value 0 indicates that types are * dependant on the implementation of concrete shape. */ virtual DomainDiscretization discretizeBoundaryWithStep(scalar_t step, int type) const { return discretizeBoundaryWithDensity([=](const vec_t &) { return step; }, type); } /** * Returns a discretization of the boundary of this shape with approximately uniform * distance `step` between nodes. Node type are decided by the underlying shape. */ DomainDiscretization discretizeBoundaryWithStep(scalar_t step) const { return this->discretizeBoundaryWithStep(step, 0); } /** * Returns a discretization of this shape with approximately uniform distance `step` between * nodes. `step` must be positive. * @param step Desired internodal distance. * @param internal_type User supplied type of internal nodes. Must be non-negative. * @param boundary_type User supplied type of boundary nodes. Must be non-positive. * If any of the types is 0, the underlying shape provides the default. */ virtual DomainDiscretization discretizeWithStep( scalar_t step, int internal_type, int boundary_type) const { return discretizeWithDensity([=](const vec_t &) { return step; }, internal_type, boundary_type); } /// @ref discretizeWithStep but with default types as assigned by the shape. DomainDiscretization discretizeWithStep(scalar_t step) const { return this->discretizeWithStep(step, 0, 0); } // DENSITY -- calls fill engine in interior /** * Returns a discretization of the domain with spatially variable step. * @param dr Function giving desired internodal distance at each point. * @param internal_type User supplied type of internal nodes. Must be non-negative. * @param boundary_type User supplied type of boundary nodes. Must be non-positive. * If any of the types is 0, the underlying shape provides the default. * @return Discretization with nodes distributed according to `dr`. */ virtual DomainDiscretization discretizeWithDensity( const std::function &dr, int internal_type, int boundary_type) const; /// Overload for fill engine. template DomainDiscretization discretizeWithDensity(const func_t &dr, const fill_t &fill, int internal_type, int boundary_type) const { DomainDiscretization domain = discretizeBoundaryWithDensity(dr, boundary_type); fill(domain, dr, internal_type); return domain; } /// Overload with default types. DomainDiscretization discretizeWithDensity( const std::function &dr) const { return discretizeWithDensity(dr, 0, 0); } /// Overload for fill engine with default types. template DomainDiscretization discretizeWithDensity(const func_t &dr, const fill_t &fill) const { return discretizeWithDensity(dr, fill, 0, 0); } /** * Discretizes boundary with given density and fill engine. * If type is 0, the underlying shape provides the default. */ virtual DomainDiscretization discretizeBoundaryWithDensity( const std::function &dr, int type) const = 0; /// Overload with default type. DomainDiscretization discretizeBoundaryWithDensity( const std::function &dr) const { return this->discretizeBoundaryWithDensity(dr, 0); } /** * Translate the shape by given vector `a`. * @note It is usually faster to first discretize the domain and than translate the whole * discretization using DomainDiscretization::translate. */ TranslatedShape translate(const vec_t &a); /** * Transform the shape by given orthogonal matrix `Q`. * @note It is usually faster to first discretize the domain and than transform the whole * discretization using DomainDiscretization::rotate. */ RotatedShape rotate(const Eigen::Matrix &Q); /// 2D version of @ref rotate accepting an angle. RotatedShape rotate(scalar_t angle); template friend std::ostream &operator<<(std::ostream &os, const DomainShape &shape); }; /** * Output info about given shape to ostream. Calls polymorphic DomainShape::print function. * @sa print */ template std::ostream &operator<<(std::ostream &os, const DomainShape &shape) { return shape.print(os); } } // namespace mm #endif // MEDUSA_BITS_DOMAINS_DOMAINSHAPE_FWD_HPP_