#pragma once #include "vde/core/point.h" #include "vde/curves/bspline_curve.h" #include #include namespace vde::curves { using core::Point3D; using core::Vector3D; class NurbsSurface { public: NurbsSurface(std::vector> control_grid, std::vector knots_u, std::vector knots_v, std::vector> weights, int degree_u, int degree_v); [[nodiscard]] Point3D evaluate(double u, double v) const; [[nodiscard]] Vector3D derivative_u(double u, double v) const; [[nodiscard]] Vector3D derivative_v(double u, double v) const; [[nodiscard]] Vector3D normal(double u, double v) const; [[nodiscard]] int degree_u() const { return degree_u_; } [[nodiscard]] int degree_v() const { return degree_v_; } [[nodiscard]] std::array num_control_points() const { return {static_cast(cp_.size()), static_cast(cp_.empty()?0:cp_[0].size())}; } [[nodiscard]] const std::vector& knots_u() const { return knots_u_; } [[nodiscard]] const std::vector& knots_v() const { return knots_v_; } [[nodiscard]] const std::vector>& control_points() const { return cp_; } [[nodiscard]] const std::vector>& weights() const { return weights_; } /// Create a ruled surface between two NURBS curves static NurbsSurface ruled(const NurbsCurve& c1, const NurbsCurve& c2); /// Create a surface of revolution static NurbsSurface revolve(const NurbsCurve& profile, const Point3D& axis_origin, const Vector3D& axis_dir, double angle_rad); /// Tessellate to triangle mesh [[nodiscard]] std::pair, std::vector>> tessellate(int res_u, int res_v) const; private: std::vector> cp_; std::vector knots_u_, knots_v_; std::vector> weights_; int degree_u_, degree_v_; }; } // namespace vde::curves