201 lines
7.2 KiB
C++
201 lines
7.2 KiB
C++
|
|
#pragma once
|
|||
|
|
/**
|
|||
|
|
* @file ffd_deformation.h
|
|||
|
|
* @brief Freeform Deformation (FFD) — 自由变形
|
|||
|
|
*
|
|||
|
|
* FFD 是一种基于控制格 (lattice) 的体积变形技术,可以将任意
|
|||
|
|
* B-Rep 实体或网格进行拉伸、压缩、扭转等自由变形,保持拓扑不变。
|
|||
|
|
*
|
|||
|
|
* ## 核心概念
|
|||
|
|
*
|
|||
|
|
* - **FFD Lattice**: nx×ny×nz 的 Bézier 体积控制点网格。
|
|||
|
|
* - **参数空间映射**: 将世界坐标点映射到 lattice 的 (s,t,u) 参数空间。
|
|||
|
|
* - **Bernstein 多项式**: 用 Bernstein 基函数计算变形后的位置。
|
|||
|
|
*
|
|||
|
|
* ## FFD 类型
|
|||
|
|
*
|
|||
|
|
* | 类型 | 描述 |
|
|||
|
|
* |--------------|----------------------------------------|
|
|||
|
|
* | Lattice-based | 规则矩形网格,参数空间 [0,1]³ |
|
|||
|
|
* | Cage-based | 任意包围多面体,自动生成 lattice 控制点 |
|
|||
|
|
*
|
|||
|
|
* ## 使用示例
|
|||
|
|
*
|
|||
|
|
* @code{.cpp}
|
|||
|
|
* auto box = make_box(10, 5, 3);
|
|||
|
|
* auto bbox = box.bounds();
|
|||
|
|
* auto lattice = create_lattice(bbox, 3, 3, 3); // 3×3×3 控制点
|
|||
|
|
*
|
|||
|
|
* // 拉伸:移动顶面控制点
|
|||
|
|
* std::vector<Vector3D> displacements(27);
|
|||
|
|
* for (int i = 0; i < 3; ++i)
|
|||
|
|
* for (int j = 0; j < 3; ++j)
|
|||
|
|
* displacements[i*9 + j*3 + 2] = Vector3D(0, 0, 3.0); // z方向位移
|
|||
|
|
*
|
|||
|
|
* auto deformed = deform_brep(box, lattice, displacements);
|
|||
|
|
* @endcode
|
|||
|
|
*
|
|||
|
|
* @ingroup brep
|
|||
|
|
*/
|
|||
|
|
#include "vde/core/point.h"
|
|||
|
|
#include "vde/core/aabb.h"
|
|||
|
|
#include "vde/brep/brep.h"
|
|||
|
|
#include "vde/mesh/halfedge_mesh.h"
|
|||
|
|
#include <vector>
|
|||
|
|
|
|||
|
|
namespace vde::brep {
|
|||
|
|
|
|||
|
|
using core::Point3D;
|
|||
|
|
using core::Vector3D;
|
|||
|
|
using core::AABB3D;
|
|||
|
|
|
|||
|
|
// ═══════════════════════════════════════════════
|
|||
|
|
// FFD Lattice
|
|||
|
|
// ═══════════════════════════════════════════════
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief FFD 控制格结构
|
|||
|
|
*
|
|||
|
|
* 一个 nx×ny×nz 的 Bézier 体积控制点网格。
|
|||
|
|
* 控制点存储在 control_points 中,按 k-major、j-major、i-minor 排列:
|
|||
|
|
* index = (k * ny + j) * nx + i
|
|||
|
|
*
|
|||
|
|
* bbox 定义了 lattice 在世界空间中的边界,用于世界坐标 → 参数空间的映射。
|
|||
|
|
*/
|
|||
|
|
struct FFDLattice {
|
|||
|
|
int nx = 0; ///< X 方向控制点数
|
|||
|
|
int ny = 0; ///< Y 方向控制点数
|
|||
|
|
int nz = 0; ///< Z 方向控制点数
|
|||
|
|
std::vector<Point3D> control_points; ///< 控制点坐标 [nx*ny*nz]
|
|||
|
|
AABB3D bbox; ///< 世界空间包围盒
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 总控制点数
|
|||
|
|
*/
|
|||
|
|
[[nodiscard]] size_t num_points() const { return control_points.size(); }
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 获取控制点
|
|||
|
|
* @param i X 索引 (0..nx-1)
|
|||
|
|
* @param j Y 索引 (0..ny-1)
|
|||
|
|
* @param k Z 索引 (0..nz-1)
|
|||
|
|
*/
|
|||
|
|
[[nodiscard]] const Point3D& control_point(int i, int j, int k) const {
|
|||
|
|
return control_points[(k * ny + j) * nx + i];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** @brief 检查 lattice 是否有效 */
|
|||
|
|
[[nodiscard]] bool is_valid() const {
|
|||
|
|
return nx >= 2 && ny >= 2 && nz >= 2 &&
|
|||
|
|
control_points.size() == static_cast<size_t>(nx * ny * nz);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 创建规则格子 lattice
|
|||
|
|
*
|
|||
|
|
* 在给定包围盒内生成 nx×ny×nz 均匀分布的控制点网格。
|
|||
|
|
*
|
|||
|
|
* @param bbox 世界空间包围盒
|
|||
|
|
* @param nx X 方向控制点数(≥ 2)
|
|||
|
|
* @param ny Y 方向控制点数(≥ 2)
|
|||
|
|
* @param nz Z 方向控制点数(≥ 2)
|
|||
|
|
* @return FFDLattice 均匀控制格
|
|||
|
|
*/
|
|||
|
|
[[nodiscard]] FFDLattice create_lattice(const AABB3D& bbox, int nx, int ny, int nz);
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 从包围多面体生成 lattice (Cage-based FFD)
|
|||
|
|
*
|
|||
|
|
* 从一组顶点(包围多面体/cage 的顶点)计算包围盒,
|
|||
|
|
* 生成 resolution 大小的均匀控制格。
|
|||
|
|
*
|
|||
|
|
* @param cage_vertices 包围多面体的顶点坐标
|
|||
|
|
* @param nx X 方向分辨率(≥ 2)
|
|||
|
|
* @param ny Y 方向分辨率(≥ 2)
|
|||
|
|
* @param nz Z 方向分辨率(≥ 2)
|
|||
|
|
* @return FFDLattice 包围多面体的控制格
|
|||
|
|
*/
|
|||
|
|
[[nodiscard]] FFDLattice create_cage_lattice(const std::vector<Point3D>& cage_vertices,
|
|||
|
|
int nx, int ny, int nz);
|
|||
|
|
|
|||
|
|
// ═══════════════════════════════════════════════
|
|||
|
|
// Deformation API
|
|||
|
|
// ═══════════════════════════════════════════════
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 对 B-Rep 实体进行 FFD 变形
|
|||
|
|
*
|
|||
|
|
* 将 B-Rep 的所有顶点映射到 lattice 参数空间,使用 Bernstein 多项式
|
|||
|
|
* 计算变形后的位置。拓扑结构和面/边/壳关系保持不变。
|
|||
|
|
*
|
|||
|
|
* 算法:
|
|||
|
|
* 1. 复制 BrepModel(保留拓扑结构)
|
|||
|
|
* 2. 对每个顶点:
|
|||
|
|
* a. 映射世界坐标到 lattice 参数空间 (s,t,u) ∈ [0,1]³
|
|||
|
|
* b. 用 Bernstein 基函数求值,计算变形位移
|
|||
|
|
* c. 应用位移到顶点位置
|
|||
|
|
* 3. 返回变形后的 BrepModel
|
|||
|
|
*
|
|||
|
|
* @param body 输入 B-Rep 实体
|
|||
|
|
* @param lattice FFD 控制格
|
|||
|
|
* @param displacements 每个控制点的位移向量 [nx*ny*nz]
|
|||
|
|
* @return 变形后的 B-Rep 实体(拓扑不变)
|
|||
|
|
*
|
|||
|
|
* @pre displacements.size() == lattice.num_points()
|
|||
|
|
* @pre lattice.is_valid()
|
|||
|
|
*/
|
|||
|
|
[[nodiscard]] BrepModel deform_brep(const BrepModel& body,
|
|||
|
|
const FFDLattice& lattice,
|
|||
|
|
const std::vector<Vector3D>& displacements);
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 对三角网格进行 FFD 变形
|
|||
|
|
*
|
|||
|
|
* 将网格的所有顶点映射到 lattice 参数空间,用 Bernstein 多项式
|
|||
|
|
* 计算变形后的新位置。
|
|||
|
|
*
|
|||
|
|
* @param mesh 输入三角网格
|
|||
|
|
* @param lattice FFD 控制格
|
|||
|
|
* @param displacements 每个控制点的位移向量 [nx*ny*nz]
|
|||
|
|
* @return 变形后的网格(拓扑不变)
|
|||
|
|
*
|
|||
|
|
* @pre displacements.size() == lattice.num_points()
|
|||
|
|
* @pre lattice.is_valid()
|
|||
|
|
*/
|
|||
|
|
[[nodiscard]] mesh::HalfedgeMesh deform_mesh(const mesh::HalfedgeMesh& mesh,
|
|||
|
|
const FFDLattice& lattice,
|
|||
|
|
const std::vector<Vector3D>& displacements);
|
|||
|
|
|
|||
|
|
// ═══════════════════════════════════════════════
|
|||
|
|
// Internal: Bernstein evaluation
|
|||
|
|
// ═══════════════════════════════════════════════
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief Bernstein 基函数 B_{i,n}(t)
|
|||
|
|
*
|
|||
|
|
* B_{i,n}(t) = C(n,i) * t^i * (1-t)^{n-i}
|
|||
|
|
*
|
|||
|
|
* @param i 基函数索引 (0..n)
|
|||
|
|
* @param n 多项式阶数
|
|||
|
|
* @param t 参数值 ∈ [0,1]
|
|||
|
|
* @return 基函数值
|
|||
|
|
*/
|
|||
|
|
[[nodiscard]] double bernstein(int i, int n, double t);
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 用 FFD lattice 对单个点进行变形计算
|
|||
|
|
*
|
|||
|
|
* 将世界坐标点映射到 lattice 参数空间,计算变形位移并应用。
|
|||
|
|
*
|
|||
|
|
* @param point 输入世界坐标点
|
|||
|
|
* @param lattice FFD 控制格
|
|||
|
|
* @param displacements 控制点位移向量
|
|||
|
|
* @return 变形后的点坐标
|
|||
|
|
*/
|
|||
|
|
[[nodiscard]] Point3D deform_point(const Point3D& point,
|
|||
|
|
const FFDLattice& lattice,
|
|||
|
|
const std::vector<Vector3D>& displacements);
|
|||
|
|
|
|||
|
|
} // namespace vde::brep
|