Files
茂之钳 11b606bd39
Build & Test / build-and-test (push) Waiting to run
Build & Test / python-bindings (push) Blocked by required conditions
CI / Build & Test (push) Failing after 33s
CI / Release Build (push) Failing after 32s
feat(v6.0): FFD freeform deformation + auto-dimensioning + PMI/MBD + Web viewer
v6.0.1 — FFD Freeform Deformation:
- ffd_deformation.h/.cpp: Bezier volume lattice, deform_brep/deform_mesh
- Bernstein polynomial mapping, topology-preserving
- Cage-based + lattice-based FFD, create_cage_lattice()

v6.0.2 — Auto-Dimensioning + PMI/MBD + GD&T:
- auto_dimensioning.h/.cpp: linear/angular/radial/diameter detection
- ISO/ANSI/JIS drawing standards, smart label placement
- gdt.h/.cpp: 14 GD&T symbols (ASME Y14.5), MMC/LMC/RFS material conditions
- pmi_mbd.h/.cpp: PMIAnnotation, attach_pmi, PMIView, STEP AP242 export
- 70/70 tests passing (23 auto-dim + 25 PMI + 22 GD&T regression)

v6.0.3 — Web 3D Viewer Enhancement:
- viewer/index.html + app.js: Three.js GLB/STL loading
- OrbitControls, face coloring, dimension overlay, GD&T display
- Measure tool (raycaster), clip plane slider, explode animation
- Drag-and-drop file upload, responsive layout
2026-07-26 21:55:16 +08:00

201 lines
7.2 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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