#pragma once #include "vde/curves/nurbs_surface.h" #include "vde/curves/nurbs_curve.h" #include "vde/core/point.h" #include #include namespace vde::curves { using core::Point3D; using core::Vector3D; /** * @brief NURBS 曲面等距偏移 * * 基于 Piegl & Tiller 近似方法:在每个控制点的 Greville 横坐标处 * 计算曲面法向,将控制点沿法向平移 distance。 * * @param surf 输入 NURBS 曲面 * @param distance 偏移距离(正值 = 沿法向外,负值 = 向内) * @return 偏移后的 NURBS 曲面(近似,阶次与原曲面相同) * * @note 这是几何近似,非精确偏移。对于大变曲率曲面,增大控制点数量 * 可提高精度。精确偏移需要更高阶曲面或细分方法。 * @note 偏移可能导致自交(distance 超过曲面局部曲率半径时) * @see trim_surface blend_surfaces * @ingroup curves */ [[nodiscard]] NurbsSurface offset_surface(const NurbsSurface& surf, double distance); /** * @brief NURBS 曲面参数域裁剪 * * 将原始定义域 [u_min,u_max]×[v_min,v_max] 通过节点重参数化 * 映射到 [0,1]×[0,1],不改变控制点和权重——仅缩放平移节点向量, * 曲面几何保持不变。 * * @param surf 输入曲面 * @param u_min,u_max 裁剪后的 u 参数范围(必须在原 domain 内) * @param v_min,v_max 裁剪后的 v 参数范围(必须在原 domain 内) * @return 裁剪后的 NURBS 曲面 * * @note 裁剪是"软裁剪"——几何不变,仅改变参数化。如需"硬裁剪" * (沿等参线切除曲面边缘),需结合曲面细分。 * @code{.cpp} * auto trimmed = trim_surface(surf, 0.2, 0.8, 0.1, 0.9); * // trimmed 的参数域为 [0,1]×[0,1],但几何仅对应原曲面的子区域 * @endcode * @ingroup curves */ [[nodiscard]] NurbsSurface trim_surface(const NurbsSurface& surf, double u_min, double u_max, double v_min, double v_max); /** * @brief 两 NURBS 曲面沿边界边的过渡面 * * 提取两个曲面的指定边界曲线,各沿法向向内偏移 blend_radius 后, * 在两偏移曲线之间创建直纹面作为过渡。 * * @param surf_a 第一个曲面 * @param surf_b 第二个曲面 * @param edge_a surf_a 的边界边索引(0=u_min, 1=u_max, 2=v_min, 3=v_max) * @param edge_b surf_b 的边界边索引(0=u_min, 1=u_max, 2=v_min, 3=v_max) * @param blend_radius 过渡半径 * @return 过渡 NURBS 曲面(在偏移边界曲线间的直纹面) * * @note 过渡面与原始曲面在边界处为 C⁰ 连续(非切线连续) * @code{.cpp} * // surf_a 的 u_max 边过渡到 surf_b 的 u_min 边 * auto blend = blend_surfaces(surf_a, surf_b, * 1, 0, // edge indices: umax → umin * 0.5); // blend radius * @endcode * @see ruled_surface * @ingroup curves */ [[nodiscard]] NurbsSurface blend_surfaces(const NurbsSurface& surf_a, const NurbsSurface& surf_b, int edge_a, int edge_b, double blend_radius); /** * @brief 两 NURBS 曲线间的直纹面 * * 在两条曲线之间线性插值生成曲面: * S(u,v) = (1-v)·C_a(u) + v·C_b(u) * 纵向保持输入曲线的阶次,直纹方向为线性(degree=1)。 * * @param curve_a 第一条曲线(v=0 边界) * @param curve_b 第二条曲线(v=1 边界) * @return 直纹 NURBS 曲面 * * @note 两条曲线需有兼容的阶次和节点结构(内部执行升阶和节点精化) * @code{.cpp} * auto ruled = ruled_surface(profile_bottom, profile_top); * @endcode * @see coons_patch blend_surfaces * @ingroup curves */ [[nodiscard]] NurbsSurface ruled_surface(const NurbsCurve& curve_a, const NurbsCurve& curve_b); /** * @brief 由四条边界曲线创建 Coons 曲面 * * 双线性混合: * S(u,v) = (1-u)·C_{v0}(v) + u·C_{v1}(v) * + (1-v)·C_{u0}(u) + v·C_{u1}(u) * - 角点修正项 * * 四条曲线须围成闭合环且有兼容的阶次/节点结构。 * * @param curve_u0 v=0 处边界(沿 u 方向) * @param curve_u1 v=1 处边界(沿 u 方向) * @param curve_v0 u=0 处边界(沿 v 方向) * @param curve_v1 u=1 处边界(沿 v 方向) * @return Coons 曲面 * * @note 仅保证边界插值,不保证内部形状与设计意图一致 * @code{.cpp} * auto patch = coons_patch(bottom, top, left, right); * @endcode * @see ruled_surface * @ingroup curves */ [[nodiscard]] NurbsSurface coons_patch(const NurbsCurve& curve_u0, const NurbsCurve& curve_u1, const NurbsCurve& curve_v0, const NurbsCurve& curve_v1); /** * @brief 沿方向向量拉伸 NURBS 曲线为曲面 * * 创建阶次 (d)×1 的 NURBS 曲面(d = 曲线阶次)。 * 第一排控制点 = 曲线控制点,最后一排 = 偏移后的控制点。 * * @param curve 截面曲线 * @param direction 拉伸方向(内部归一化) * @param length 拉伸长度 * @return 拉伸 NURBS 曲面 * * @code{.cpp} * auto surface = extrude_curve(profile, {0, 0, 1}, 10.0); * // 沿 Z 轴拉伸 10 单位 * @endcode * @ingroup curves */ [[nodiscard]] NurbsSurface extrude_curve(const NurbsCurve& curve, const Vector3D& direction, double length); /** * @brief 提取 NURBS 曲面的等参边界曲线 * * 沿曲面的 u/v 参数极值提取边界 NURBS 曲线。 * * @param surf 输入曲面 * @param edge 边界索引:0=u_min, 1=u_max, 2=v_min, 3=v_max * @return 指定边界上的 NURBS 曲线 * * @note 边界曲线继承原曲面该方向的阶次和节点向量 * @code{.cpp} * auto umin_curve = extract_boundary_curve(surf, 0); * auto vmax_curve = extract_boundary_curve(surf, 3); * @endcode * @ingroup curves */ [[nodiscard]] NurbsCurve extract_boundary_curve(const NurbsSurface& surf, int edge); /** * @brief 曲面点的曲率(平均曲率与高斯曲率) * * 基于第一基本形式 (E,F,G) 和第二基本形式 (L,M,N) 的微分几何定义: * - 平均曲率 H = (EN - 2FM + GL) / (2(EG - F²)) * - 高斯曲率 K = (LN - M²) / (EG - F²) * * @param surf 输入曲面 * @param u u 参数 * @param v v 参数 * @return (mean_curvature, gaussian_curvature) * * @note H > 0 表示曲面沿法向弯曲,K > 0 为椭圆点,K < 0 为双曲点 * @code{.cpp} * auto [H, K] = surface_curvature(surf, 0.5, 0.5); * @endcode * @see is_g2_continuous * @ingroup curves */ [[nodiscard]] std::pair surface_curvature( const NurbsSurface& surf, double u, double v); /** * @brief 检查两曲面沿共享边界的 G²(曲率)连续性 * * 沿 surf_a 的指定边与 surf_b 的对应边采样多个点, * 依次检查位置连续(G⁰)、切平面连续(G¹)和曲率连续(G²)。 * * @param surf_a 第一个曲面 * @param surf_b 第二个曲面 * @param edge surf_a 的边索引(0=umin, 1=umax, 2=vmin, 3=vmax) * @param samples 沿边界的采样点数(默认 10) * @return 所有采样点均满足 G² 连续时返回 true * * @note G² 连续性要求:位置、切平面和曲率在边界两侧一致 * @note 默认容差:位置 1e-6,法向量 1e-3,曲率相对误差 1e-3 * @code{.cpp} * bool is_smooth = is_g2_continuous(surf_a, surf_b, 1); * // 检查 surf_a 的 umax 边是否与 surf_b 的 umin 边 G² 连续 * @endcode * @see surface_curvature extend_surface * @ingroup curves */ [[nodiscard]] bool is_g2_continuous(const NurbsSurface& surf_a, const NurbsSurface& surf_b, int edge, int samples = 10); /** * @brief 沿边界边延伸 NURBS 曲面 * * 在指定边方向上追加一行(或一列)控制点, * 新控制点由边界控制点沿切向平移 distance 得到。 * 节点向量相应扩展,延伸区间的参数长度为 distance。 * * @param surf 输入曲面 * @param edge 延伸起始边(0=umin, 1=umax, 2=vmin, 3=vmax) * @param length 延伸长度(参数空间) * @return 延伸后的 NURBS 曲面 * * @note 延伸仅沿切向线性外推,不保证与原曲面 C² 连续 * @note 大延伸长度可能引起自交或形状失真 * @code{.cpp} * auto extended = extend_surface(surf, 1, 0.5); // 沿 umax 延伸 0.5 * @endcode * @see is_g2_continuous * @ingroup curves */ [[nodiscard]] NurbsSurface extend_surface(const NurbsSurface& surf, int edge, double length); /// Fill an N-sided hole with a smooth surface /// @param boundary_curves N boundary curves forming a closed loop /// @param continuity Desired continuity (1=G1 tangent, 2=G2 curvature) /// @return Filling NURBS surface [[nodiscard]] NurbsSurface fill_n_sided(const std::vector& boundary_curves, int continuity = 1); /// Check G3 (torsion) continuity between two surfaces along a shared boundary [[nodiscard]] bool is_g3_continuous(const NurbsSurface& surf_a, const NurbsSurface& surf_b, int edge, int samples = 10); /// Compute torsion of a surface at a point [[nodiscard]] double surface_torsion(const NurbsSurface& surf, double u, double v); } // namespace vde::curves