#ifndef MEDUSA_BITS_DOMAINS_NURBSPATCH_FWD_HPP_ #define MEDUSA_BITS_DOMAINS_NURBSPATCH_FWD_HPP_ /** * @file * Declaration of the NURBS patch class. * * @example test/domains/NURBSPatch_test.cpp */ #include #include #include #include #include namespace mm { /** * Implementation details of NURBSPatch, contains structures for partial class specialization. */ namespace nurbs_patch_internal { /** * Internal structure of NURBSPatch that helps with partial class specialization. * All of its functions have the same signature (apart from accepting a reference to NURBSPatch) * as the corresponding functions of NURBSPatch. NURBSPatch holds an instance of this class * and calls its functions when specialized functions are requested. * * Note: partial class specialization can also be done by having a base class with functions, * that are not specialized (NURBSPatchBase) and a fully specialized class (NURBSPatch) that * inherits from it. This approach was chosen to keep Medusa's class hierarchy cleaner. */ template struct NURBSPatchHelper { }; /** * Struct for declaring a nested Range. * @tparam dim Number of dimensions (nestings). * @tparam T Type. */ template struct NestedRange { /// Type of the multidimensional Range. typedef Range::type> type; }; /// @cond template struct NestedRange<0, T> { typedef T type; }; /// @endcond } // namespace nurbs_patch_internal /** * Class representing a single NURBS patch in an arbitrary dimensional space, * defined on an arbitrary dimensional domain and generated by * a tensor product of NURBS curves. * * @warning Currently only supports NURBS surfaces (2D domain) and NURBS * curves (1D domain). * * Usage example: * @snippet domains/NURBSPatch_test.cpp NURBSPatch usage example * * @tparam param_vec_t Vector type of the parametric space. * @tparam vec_t Vector type of ambient space. * * @ingroup domains */ template class NURBSPatch { friend struct nurbs_patch_internal::NURBSPatchHelper; public: typedef typename vec_t::scalar_t scalar_t; ///< Scalar type. /// Store dimensionality. enum { /** Dimensionality of space after projection. */ dim = vec_t::dim, /** Dimensionality of space before projection. */ proj_dim = dim + 1, /** Dimensionality of parametric space. */ param_dim = param_vec_t::dim }; typedef Vec proj_vec_t; ///< Vector type before projection. template /// Range of param_dim dimensions. using NdRange = typename nurbs_patch_internal::NestedRange::type; private: std::array p; ///< Underlying B-spline orders. NdRange weighted_control_points; ///< Multidimensional Range of control points. std::array, param_dim> knots; ///< Array of Ranges of knots (knot vector). /// NURBS surfaces needed for derivative calculation. std::unique_ptr, param_dim>> der_structure; public: /** * Construct NURBS patch with weighted control points. * @param wcp Multidimensional Range of weighted control points, * e. g. `Vec(w * x, w * y, w * z, w)`. * @param ks Array of Ranges of knots (pair of knot vectors). * @param in_p Array of underlying B-spline orders (starting from order 0). */ NURBSPatch(const NdRange &wcp, const std::array, param_dim> &ks, const std::array &in_p); /** * Construct NURBS patch with control points and weights. * @param cp Multidimensional Range of control points. * @param w Multidimensional Range of weights. * @param ks Array of Ranges of knots (pair of knot vectors). * @param in_p Array of underlying B-spline orders (starting from order 0). */ NURBSPatch(const NdRange &cp, const NdRange &w, const std::array, param_dim> &ks, const std::array &in_p); /// Copy constructor. NURBSPatch(const NURBSPatch &patch) noexcept; /// Copy assignment. NURBSPatch &operator=(const NURBSPatch &) noexcept; /// Move constructor. NURBSPatch(NURBSPatch &&) noexcept = default; /// Move assignment. NURBSPatch &operator=(NURBSPatch &&) noexcept = default; /// Calculate data needed for derivative evaluation. void computeDerivativeStructure(); /** * Evaluate NURBS patch in one point along the second dimension. * @param t Point of evaluation. * @param w Variable in which the weight is stored. * @return Vector to the point on the NURBS surface corresponding to parameter `t`. */ vec_t evaluate(const param_vec_t &t, scalar_t *w) const; /** * Overload if weight is not required. * @param t Point of evaluation. * @return Vector to the point on the NURBS surface corresponding to parameter `t`. */ vec_t evaluate(const param_vec_t &t) const; /** * Evaluate NURBS patch in one point. * @param t Point of evaluation. * @return Vector to the weighted point on the NURBS patch corresponding to parameter `t`. */ proj_vec_t evaluateWeighted(const param_vec_t &t) const; /** * Evaluate NURBS jacobian matrix in one point. * @param t Point of evaluation. * @param pt Point on the NURBS patch corresponding to `t`. * @param w Weight of `pt`. * @return Jacobian matrix of the NURBS patch at point `t`. * @warning `computeDerivativeStructure()` must be called on the object before calling * this function. */ Eigen::Matrix jacobian(const param_vec_t &t, const vec_t &pt, const scalar_t &w) const; /** * Overload that calculates the point automatically. * @warning Less efficient. * @param t Point of evaluation. * @return Jacobian matrix of the NURBS patch at point `t`. * @warning `computeDerivativeStructure()` must be called on the object before calling * this function. */ Eigen::Matrix jacobian(const param_vec_t &t) const; /** * Evaluate NURBS and its jacobian matrix in one parameter. * @param t Parameter of evaluation. * @return Pair of point on the NURBS and jacobian matrix of the NURBS at parameter `t`. */ std::pair> evaluatePointAndJacobian( const param_vec_t &t) const; /** * Get domain of the NURBS patch. * @return Domain of the NURBS in the form of a BoxShape. */ BoxShape getDomain() const; /** * Get all boundaries of the NURBS patch as a Range of NURBS patches. * @return An array of NURBS curves representing the boundaries. */ Range>> getBoundaries() const; /** * Get vector from the parametric domain of the NURBS patch from the * parameter of the NURBS patch representing one of the boundaries of the NURBS. * Patch parameter can be generated `epsilon` times the length of the domain away * from the boundary. This is useful when normals are not defined at the boundary of the patch. * @param t Parameter of the NURBS patch representing the boundary. * @param i Index of the boundary. * @param epsilon Epsilon. * @return Vector from the parametric domain of the NURBS patch corresponding * to the input parameter. */ param_vec_t getPatchParameterFromBoundaryParameter(const Vec &t, int i, scalar_t epsilon = 0) const; /** * Get parameter from the parametric domain of the NURBS patch representing the * boundary of the NURBS patch corresponding to a parameter from the parametric domain * of the NURBS surface. * @param t Parameter of the NURBS patch. * @param i Index of the boundary. * @return Parameter from the parametric domain of the NURBS boundary curve corresponding * to the input parameter. */ Vec getBoundaryParameterFromPatchParameter(const param_vec_t &t, int i) const; }; } // namespace mm #endif // MEDUSA_BITS_DOMAINS_NURBSPATCH_FWD_HPP_