255 lines
9.2 KiB
C++
255 lines
9.2 KiB
C++
#pragma once
|
||
#include "vde/curves/nurbs_surface.h"
|
||
#include "vde/curves/nurbs_curve.h"
|
||
#include "vde/core/point.h"
|
||
#include <utility>
|
||
#include <vector>
|
||
|
||
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<double, double> 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<NurbsCurve>& 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
|