You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

243 lines
9.7 KiB

#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 <medusa/Config.hpp>
#include <medusa/bits/utils/memutils.hpp>
#include <medusa/bits/types/Vec_fwd.hpp>
#include <iosfwd>
#include <utility>
#include <ostream>
#include <functional>
namespace mm
{
template <class vec_t>
class deep_copy_unique_ptr;
template <class vec_t>
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 <typename vec_t>
class ShapeUnion;
template <typename vec_t>
class ShapeDifference;
template <typename vec_t>
class TranslatedShape;
template <typename vec_t>
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 <typename vec_t>
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<vec_t> add(const DomainShape &other) const;
/// Operator form of DomainShape::add. @sa add
ShapeUnion<vec_t> operator+(const DomainShape &other) const { return add(other); }
/// Returns a shape representing a difference of `*this` and `other`.
ShapeDifference<vec_t> subtract(const DomainShape &other) const;
/// Operator form of DomainShape::subtract. @sa subtract
ShapeDifference<vec_t> operator-(const DomainShape &other) const { return subtract(other); }
/// Project point to boundary using bisection along the line define by `unit_normal`.
virtual std::pair<bool, vec_t> 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<vec_t, vec_t> 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<vec_t> 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<vec_t> 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<vec_t> 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<vec_t> 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<vec_t> discretizeWithDensity(
const std::function<scalar_t(vec_t)> &dr, int internal_type, int boundary_type) const;
/// Overload for fill engine.
template <typename func_t, typename fill_t>
DomainDiscretization<vec_t> discretizeWithDensity(const func_t &dr, const fill_t &fill,
int internal_type, int boundary_type) const
{
DomainDiscretization<vec_t> domain = discretizeBoundaryWithDensity(dr, boundary_type);
fill(domain, dr, internal_type);
return domain;
}
/// Overload with default types.
DomainDiscretization<vec_t> discretizeWithDensity(
const std::function<scalar_t(vec_t)> &dr) const
{
return discretizeWithDensity(dr, 0, 0);
}
/// Overload for fill engine with default types.
template <typename func_t, typename fill_t>
DomainDiscretization<vec_t> 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<vec_t> discretizeBoundaryWithDensity(
const std::function<scalar_t(vec_t)> &dr, int type) const = 0;
/// Overload with default type.
DomainDiscretization<vec_t> discretizeBoundaryWithDensity(
const std::function<scalar_t(vec_t)> &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<vec_t> 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<vec_t> rotate(const Eigen::Matrix<scalar_t, dim, dim> &Q);
/// 2D version of @ref rotate accepting an angle.
RotatedShape<vec_t> rotate(scalar_t angle);
template <typename V>
friend std::ostream &operator<<(std::ostream &os, const DomainShape<V> &shape);
};
/**
* Output info about given shape to ostream. Calls polymorphic DomainShape::print function.
* @sa print
*/
template <typename V>
std::ostream &operator<<(std::ostream &os, const DomainShape<V> &shape)
{
return shape.print(os);
}
} // namespace mm
#endif // MEDUSA_BITS_DOMAINS_DOMAINSHAPE_FWD_HPP_