163 KiB
ViewDesignEngine API 参考手册
版本 3.2.0 | 76 个头文件
基础模块 (vde::foundation)
error_codes.h
全局错误码枚举
enum class ErrorCode : int32_t {
exact_predicates.h
二维定向测试结果
enum class Orientation { Clockwise, CounterClockwise, Collinear }
圆测试结果
enum class CircleTest { Inside, On, Outside }
自适应精度二维定向测试(Shewchuk 算法)
Orientation orient_2d(const Point2D& a, const Point2D& b, const Point2D& c)
| 参数 | 说明 |
|---|---|
a |
第一个点 |
b |
第二个点 |
c |
第三个点 |
返回: Orientation::Collinear 若三点共线
Delaunay 三角剖分、凸包计算等几何算法的核心原语
参见: orient_3d, in_circle
自适应精度三维定向测试
Orientation orient_3d(const Point3D& a, const Point3D& b,
| 参数 | 说明 |
|---|---|
a |
第一个点 |
b |
第二个点 |
c |
第三个点 |
d |
第四个点(测试点) |
返回: Orientation::Collinear 若四点共面
三维 Delaunay 剖分和凸包计算的核心原语
参见: orient_2d, in_circle
自适应精度圆内测试(In-Circle Test)
CircleTest in_circle(const Point2D& a, const Point2D& b,
| 参数 | 说明 |
|---|---|
a |
三角形第一个顶点 |
b |
三角形第二个顶点 |
c |
三角形第三个顶点 |
d |
待测试点 |
返回: CircleTest::Outside 若 d 在三角形外接圆外部
Delaunay 三角剖分的空圆性质检查核心原语
参见: orient_2d, orient_3d
自适应双精度谓词后端(默认)
二维定向测试
static exact::Orientation orient_2d(const Point2D& a, const Point2D& b, const Point2D& c) {
| 参数 | 说明 |
|---|---|
a,b,c |
三个二维点 |
返回: 定向结果
参见: exact::orient_2d
三维定向测试
static exact::Orientation orient_3d(const Point3D& a, const Point3D& b,
| 参数 | 说明 |
|---|---|
a,b,c,d |
四个三维点 |
返回: 定向结果
参见: exact::orient_3d
圆内测试
static exact::CircleTest in_circle(const Point2D& a, const Point2D& b,
| 参数 | 说明 |
|---|---|
a,b,c |
三角形三顶点 |
d |
待测试点 |
返回: 圆测试结果
参见: exact::in_circle
exact_predicates_gmp.h
GMP 精确算术谓词后端
struct GmpExact {
仅在定义了 VDE_USE_GMP 宏且链接了 GMP 库时可用
精确有理数二维定向测试
static Orientation orient_2d(const Point2D& a, const Point2D& b, const Point2D& c) {
| 参数 | 说明 |
|---|---|
a |
第一个点 |
b |
第二个点 |
c |
第三个点 |
返回: 定向结果(保证正确,无舍入误差)
参见: GmpExact::orient_3d, GmpExact::in_circle
精确有理数三维定向测试
static Orientation orient_3d(const Point3D& a, const Point3D& b,
| 参数 | 说明 |
|---|---|
a,b,c |
定义平面的三点 |
d |
待测试点 |
返回: 定向结果(零误差)
参见: GmpExact::orient_2d
精确有理数圆内测试
static CircleTest in_circle(const Point2D& a, const Point2D& b,
| 参数 | 说明 |
|---|---|
a,b,c |
三角形三顶点 |
d |
待测试点 |
返回: 圆测试结果(零误差)
参见: GmpExact::orient_2d
format_utils.h
以 CAD 级别精度格式化双精度浮点数
inline std::string fmt_double(double v, int precision = 12) {
| 参数 | 说明 |
|---|---|
v |
要格式化的双精度数 |
precision |
有效数字位数(默认 12) |
返回: 格式化后的字符串,如 "1.234567890123e+02"
总是确保指数部分带符号(如 "e+00" 而非 "e00"),便于解析器统一处理
参见: fmt_iges_real, fmt_point
IGES 格式实数输出
inline std::string fmt_iges_real(double v, int /*precision*/ = 12) {
| 参数 | 说明 |
|---|---|
v |
要格式化的双精度数 |
返回: IGES 格式字符串,如 "3.141592653590D+00"
参见: fmt_double
格式化三维点为逗号分隔字符串
inline std::string fmt_point(const core::Point3D& p, bool use_d = false) {
| 参数 | 说明 |
|---|---|
p |
三维点 |
use_d |
若为 true,使用 IGES 风格 D 指数标记 |
返回: 逗号分隔的坐标字符串
参见: fmt_double, fmt_iges_real
将字符串填充到恰好 72 个字符
inline std::string pad72(const std::string& s) {
| 参数 | 说明 |
|---|---|
s |
输入字符串 |
返回: 恰好 72 字符的字符串(不足右侧补空格,超出截断)
参见: format_iges_line
格式化 IGES 段落行
inline std::string format_iges_line(const std::string& data, char section_char, int seq) {
| 参数 | 说明 |
|---|---|
data |
数据内容(最多 72 字符,超出截断) |
section_char |
段落标识符(如 'P' 参数段, 'D' 目录段) |
seq |
行序号(1-based) |
返回: 完整 IGES 行(含换行符),共 81 字符
参见: pad72
interval.h
双精度区间算术类
从单值构造精确区间(退化为点)
Interval(double v) : lo(v), hi(v) {}
| 参数 | 说明 |
|---|---|
v |
区间值,[v, v] |
从上下界构造区间
Interval(double l, double h) : lo(std::min(l,h)), hi(std::max(l,h)) {}
| 参数 | 说明 |
|---|---|
l |
下界 |
h |
上界 |
区间中点
[[nodiscard]] double mid() const { return (lo + hi) * 0.5; }
返回: (lo + hi) / 2
区间宽度
[[nodiscard]] double width() const { return hi - lo; }
返回: hi - lo
判断区间是否包含给定值
[[nodiscard]] bool contains(double v) const { return lo <= v && v <= hi; }
| 参数 | 说明 |
|---|---|
v |
测试值 |
返回: true 若 lo ≤ v ≤ hi
判断区间是否足够窄(收敛)
[[nodiscard]] bool is_exact(double eps = 1e-12) const { return width() < eps; }
| 参数 | 说明 |
|---|---|
eps |
宽度阈值(默认 1e-12) |
返回: true 若区间宽度 < eps
判断两个区间是否有重叠
[[nodiscard]] bool overlaps(const Interval& o) const {
| 参数 | 说明 |
|---|---|
o |
另一个区间 |
返回: true 若存在公共点
确定性区间比较
[[nodiscard]] int cmp(const Interval& o) const {
| 参数 | 说明 |
|---|---|
o |
另一个区间 |
返回: 0 若区间重叠,无法确定
区间加法
Interval operator+(const Interval& o) const {
返回: [this.lo + o.lo, this.hi + o.hi]
区间减法
Interval operator-(const Interval& o) const {
返回: [this.lo - o.hi, this.hi - o.lo](保守估计)
区间乘法
Interval operator*(const Interval& o) const {
返回: [min(ac,ad,bc,bd), max(ac,ad,bc,bd)]
区间除法
Interval operator/(const Interval& o) const {
返回: 结果区间或 [-∞, +∞](除数为零区间)
区间平方根
[[nodiscard]] Interval sqrt() const {
返回: [sqrt(max(0, lo)), sqrt(max(0, hi))]
从双精度值创建区间(含舍入误差带)
static Interval from_double(double v, double error = 0) {
| 参数 | 说明 |
|---|---|
v |
中心值 |
error |
误差半径(默认 0) |
返回: [v - error, v + error]
从坐标值创建区间(含 ULP 误差带)
static Interval from_coord(double v) {
| 参数 | 说明 |
|---|---|
v |
坐标值 |
返回: 包含浮点舍入误差的区间
二维定向行列式的区间验证
inline Interval orient_2d_interval(double ax, double ay, double bx, double by, double cx, double cy) {
| 参数 | 说明 |
|---|---|
ax,ay |
点 a 的坐标 |
bx,by |
点 b 的坐标 |
cx,cy |
点 c 的坐标 |
返回: 行列式的区间值
参见: orient_2d_verified
使用区间算术验证 orient_2d 结果
inline int orient_2d_verified(double ax, double ay, double bx, double by, double cx, double cy) {
| 参数 | 说明 |
|---|---|
ax,ay |
点 a 的坐标 |
bx,by |
点 b 的坐标 |
cx,cy |
点 c 的坐标 |
返回: 1 确认 CounterClockwise
参见: orient_2d_interval, Interval::cmp
io_gltf.h
glTF 2.0 导出选项
struct GltfOptions {
导出网格为 glTF 2.0 / GLB 格式
bool write_gltf(const std::string& filepath, const mesh::HalfedgeMesh& mesh,
| 参数 | 说明 |
|---|---|
filepath |
输出文件路径(.glb 或 .gltf) |
mesh |
要导出的半边网格 |
options |
导出选项(格式、法线、颜色等) |
返回: false 导出失败(文件无法创建等)
生成的 glTF 符合 2.0 规范,兼容 Blender、three.js、Unreal Engine 等工具
参见: write_brep_gltf, GltfOptions
导出 B-Rep 模型为 GLB 格式(通过面片化)
bool write_brep_gltf(const std::string& filepath, const brep::BrepModel& model,
| 参数 | 说明 |
|---|---|
filepath |
输出文件路径(建议 .glb) |
model |
要导出的 B-Rep 模型 |
tessellation_res |
每条边的离散段数(默认 32),越大越精确 |
返回: false 导出失败
参见: write_gltf
io_obj.h
OBJ 文件解析结果数据结构
struct ObjMeshData {
每个面的顶点索引列表(0-based)
std::vector<std::vector<int>> faces
每个面的纹理坐标索引列表(0-based)
std::vector<std::vector<int>> face_texcoords
每个面的法线索引列表(0-based)
std::vector<std::vector<int>> face_normals
每个面对应的材质名称
std::vector<std::string> face_materials
读取 Wavefront OBJ 文件
ObjMeshData read_obj(const std::string& filepath)
| 参数 | 说明 |
|---|---|
filepath |
OBJ 文件路径 |
返回: 解析后的 ObjMeshData
不解析 MTL 材质文件,仅记录 usemtl 指令中的材质名称
面索引在内部转换为 0-based;若文件中使用相对索引(负值),自动转换为正向
参见: write_obj, ObjMeshData
写入 Wavefront OBJ 文件
void write_obj(const std::string& filepath, const ObjMeshData& data)
| 参数 | 说明 |
|---|---|
filepath |
输出文件路径 |
data |
要写出的网格数据 |
输出的面索引为 1-based(OBJ 标准)
参见: read_obj
io_ply.h
读取 PLY 文件(Stanford Polygon Format)
mesh::HalfedgeMesh read_ply(const std::string& filepath)
| 参数 | 说明 |
|---|---|
filepath |
PLY 文件路径 |
返回: 解析后的半边网格
自动检测文件头部 magic number 判断 ASCII / 二进制格式
二进制格式仅支持小端序(little-endian)
返回类型为 HalfedgeMesh,内部自动建立半边拓扑
参见: write_ply
写入 PLY 文件(ASCII 格式)
void write_ply(const std::string& filepath, const mesh::HalfedgeMesh& mesh)
| 参数 | 说明 |
|---|---|
filepath |
输出文件路径 |
mesh |
要导出的半边网格 |
输出的 PLY 为 ASCII 编码,易于人工阅读和编辑
若需要二进制输出以提高性能,请使用 BinarySerializer
参见: read_ply, BinarySerializer
io_stl.h
STL 三角形面片
struct StlTriangle {
读取 STL 文件(自动检测格式)
std::vector<StlTriangle> read_stl(const std::string& filepath)
| 参数 | 说明 |
|---|---|
filepath |
STL 文件路径 |
返回: 三角形面片列表
自动格式检测:二进制 STL 的 80 字节头后跟 4 字节三角形数量
ASCII STL 以 "solid name" 开头
参见: write_stl, write_stl_ascii
写入二进制 STL 文件
void write_stl(const std::string& filepath, const std::vector<StlTriangle>& tris)
| 参数 | 说明 |
|---|---|
filepath |
输出文件路径 |
tris |
三角形面片列表 |
二进制 STL 格式:80 字节头 + 4 字节三角形数 + 每三角形 50 字节
法向量在写入时自动归一化
参见: read_stl, write_stl_ascii
写入 ASCII STL 文件
void write_stl_ascii(const std::string& filepath, const std::vector<StlTriangle>& tris)
| 参数 | 说明 |
|---|---|
filepath |
输出文件路径 |
tris |
三角形面片列表 |
参见: read_stl, write_stl
math_types.h
通用 N 维点类型(使用 Eigen 列向量)
template <typename T, size_t Dim>
通用 N 维向量类型(与 Point 相同的列向量表示)
template <typename T, size_t Dim>
基础模块提供 VDE 引擎的核心基础设施:
/** @} */ // end of foundation group
memory_pool.h
固定块大小的内存池
template <typename T>
内存池不调用对象的构造函数/析构函数,仅管理原始内存
适合 POD 类型或通过 placement new 手动管理生命周期的类型
构造内存池
explicit MemoryPool(size_t chunk_size = 1024) : chunk_size_(chunk_size) {}
| 参数 | 说明 |
|---|---|
chunk_size |
每个内存块可容纳的对象数(默认 1024) |
析构内存池,释放所有已分配的内存块
~MemoryPool() { for (auto* p : chunks_) ::operator delete(p); }
从池中分配 n 个 T 对象的内存
T* allocate(size_t n = 1) {
| 参数 | 说明 |
|---|---|
n |
对象数量(当前未使用,保留用于 API 兼容) |
返回: 指向未初始化内存的指针
将内存归还到池中
void deallocate(T* p, size_t = 1) {
| 参数 | 说明 |
|---|---|
p |
之前从 allocate() 获取的指针 |
分配一个新的内存块并初始化空闲链表
void allocate_chunk() {
predicates.h
统一谓词接口 — 编译时选择 GMP 或自适应双精度后端
struct Predicates {
二维定向测试
static exact::Orientation orient_2d(const Point2D& a, const Point2D& b, const Point2D& c) {
| 参数 | 说明 |
|---|---|
a,b,c |
三点 |
返回: 定向结果
三维定向测试
static exact::Orientation orient_3d(const Point3D& a, const Point3D& b,
| 参数 | 说明 |
|---|---|
a,b,c,d |
四点 |
返回: 定向结果
圆内测试
static exact::CircleTest in_circle(const Point2D& a, const Point2D& b,
| 参数 | 说明 |
|---|---|
a,b,c |
三角形三顶点 |
d |
测试点 |
返回: 圆测试结果
二维定向测试便捷封装
inline exact::Orientation orient(const Point2D& a, const Point2D& b, const Point2D& c) {
| 参数 | 说明 |
|---|---|
a,b,c |
三个二维点 |
返回: Orientation::Clockwise / CounterClockwise / Collinear
三维定向测试便捷封装
inline exact::Orientation orient(const Point3D& a, const Point3D& b, const Point3D& c, const Point3D& d) {
| 参数 | 说明 |
|---|---|
a,b,c |
定义平面的三点 |
d |
测试点 |
返回: Orientation::Clockwise / CounterClockwise / Collinear
圆内测试便捷封装
inline exact::CircleTest in_circle(const Point2D& a, const Point2D& b, const Point2D& c, const Point2D& d) {
| 参数 | 说明 |
|---|---|
a,b,c |
三角形三顶点 |
d |
测试点 |
返回: CircleTest::Inside / On / Outside
serializer.h
二进制序列化格式的网格数据结构
struct SerializedMesh {
二进制序列化器
该格式专为 VDE 内部快速读写设计,不适用于跨平台数据交换
使用 glTF/OBJ/STL 进行外部交换,此格式用于本地缓存
序列化网格到二进制缓冲区
static std::vector<uint8_t> serialize(const mesh::HalfedgeMesh& mesh)
| 参数 | 说明 |
|---|---|
mesh |
要序列化的半边网格 |
返回: 压缩后的二进制数据(含文件头)
从二进制缓冲区反序列化网格
static mesh::HalfedgeMesh deserialize(const std::vector<uint8_t>& data)
| 参数 | 说明 |
|---|---|
data |
之前由 serialize() 生成的二进制数据 |
返回: 恢复的半边网格
序列化并写入文件
static bool write_file(const std::string& path, const mesh::HalfedgeMesh& mesh)
| 参数 | 说明 |
|---|---|
path |
输出文件路径 |
mesh |
要保存的半边网格 |
返回: false 文件创建失败
参见: read_file
从文件读取并反序列化
static mesh::HalfedgeMesh read_file(const std::string& path)
| 参数 | 说明 |
|---|---|
path |
VDE 二进制格式文件路径 |
返回: 恢复的半边网格
参见: write_file
VDE 二进制文件魔数:"VDEGEOM\0"
VDE 二进制格式当前版本号
tolerance.h
分层容差管理类
构造容差对象
Tolerance(double absolute = 1e-6, double relative = 1e-8,
| 参数 | 说明 |
|---|---|
absolute |
绝对容差,默认 1e-6 |
relative |
相对容差,默认 1e-8 |
angular |
角度容差(弧度),默认 1e-8 |
snapping |
吸附容差,默认 1e-4 |
判断两点是否相等(基于绝对容差)
bool points_equal(const Eigen::MatrixXd& a, const Eigen::MatrixXd& b) const {
| 参数 | 说明 |
|---|---|
a |
第一个点(Eigen 矩阵) |
b |
第二个点(Eigen 矩阵) |
返回: true 若两点的欧氏距离 < absolute_
判断值是否接近零
template <typename T>
| 参数 | 说明 |
|---|---|
value |
测试值 |
返回: true 若 |value| < absolute_
混合容差相等判断
template <typename T>
| 参数 | 说明 |
|---|---|
a |
第一个值 |
b |
第二个值 |
返回: true 若两值在容差范围内相等
收紧容差
Tolerance tighten(double factor = 0.1) const {
| 参数 | 说明 |
|---|---|
factor |
收紧因子(默认 0.1) |
返回: 收紧后的新容差对象
放宽容差
Tolerance relax(double factor = 10.0) const {
| 参数 | 说明 |
|---|---|
factor |
放宽因子(默认 10.0) |
返回: 放宽后的新容差对象
合并两个容差,取更严格的(更小的)
static Tolerance min(const Tolerance& a, const Tolerance& b) {
| 参数 | 说明 |
|---|---|
a |
第一个容差 |
b |
第二个容差 |
返回: 每项取 min 的新容差
获取全局容差实例
static Tolerance& global() { return global_; }
返回: 全局容差的引用
设置全局容差
static void set_global(const Tolerance& tol) { global_ = tol; }
| 参数 | 说明 |
|---|---|
tol |
新的全局容差 |
推荐使用 ToleranceScope 进行临时修改,确保自动恢复
局部容差作用域(RAII)
进入新的容差作用域
explicit ToleranceScope(const Tolerance& tol) : previous_(Tolerance::global()) {
| 参数 | 说明 |
|---|---|
tol |
此作用域内使用的容差 |
退出容差作用域,恢复之前的全局容差
~ToleranceScope() { Tolerance::set_global(previous_); }
核心几何 (vde::core)
aabb.h
轴对齐包围盒(AABB)
template <typename T>
初始状态为空(min = +∞, max = -∞),需要通过 expand() 初始化
构造空包围盒
AABB() : min_(Point3D::Constant(std::numeric_limits<T>::max())),
从两个角点构造包围盒
AABB(const Point3D& min, const Point3D& max) : min_(min), max_(max) {}
| 参数 | 说明 |
|---|---|
min |
最小角点 |
max |
最大角点 |
扩展包围盒以包含给定点
void expand(const Point3D& p) {
| 参数 | 说明 |
|---|---|
p |
要包含的点 |
扩展包围盒以包含另一个 AABB
void expand(const AABB& other) {
| 参数 | 说明 |
|---|---|
other |
另一个包围盒 |
包围盒中心点
[[nodiscard]] Point3D center() const { return (min_ + max_) * 0.5; }
返回: (min + max) / 2
包围盒对角线向量(从 min 到 max)
[[nodiscard]] Vector3D extent() const { return max_ - min_; }
返回: max - min
包围盒表面积
[[nodiscard]] T surface_area() const {
返回: 2 * (dxdy + dydz + dz*dx)
包围盒体积
[[nodiscard]] T volume() const {
返回: dx * dy * dz
测试点是否在包围盒内部(含边界)
[[nodiscard]] bool contains(const Point3D& p) const {
| 参数 | 说明 |
|---|---|
p |
测试点 |
返回: true 若 min ≤ p ≤ max(各分量)
测试两个包围盒是否相交(含边界接触)
[[nodiscard]] bool intersects(const AABB& other) const {
| 参数 | 说明 |
|---|---|
other |
另一个包围盒 |
返回: true 若存在交集
convex_hull.h
二维凸包计算(Graham Scan 算法)
std::vector<Point2D> convex_hull_2d(const std::vector<Point2D>& points)
| 参数 | 说明 |
|---|---|
points |
输入点集(至少 3 个不共线点) |
返回: 凸包顶点序列(逆时针排列),不含共线的中间点
自动过滤共线点,返回严格的凸包顶点
若所有点共线,返回两个端点
参见: convex_hull_3d, Polygon2D::convex_hull_2d
三维凸包计算(QuickHull 算法)
std::vector<std::array<Point3D, 3>> convex_hull_3d(const std::vector<Point3D>& points)
| 参数 | 说明 |
|---|---|
points |
输入点集(至少 4 个不共面点) |
返回: 凸包三角形列表,每个三角形三顶点按逆时针排列(从外部观察)
返回的三角形法线方向朝外
共面/退化点被自动丢弃
参见: convex_hull_2d
distance.h
两点之间的欧氏距离
double distance(const Point3D& a, const Point3D& b)
| 参数 | 说明 |
|---|---|
a |
第一个点 |
b |
第二个点 |
返回: ||b - a||
点到直线的距离
double distance(const Point3D& p, const Line3D<double>& line)
| 参数 | 说明 |
|---|---|
p |
测试点 |
line |
直线 |
返回: 垂直距离
点到线段的距离
double distance(const Point3D& p, const Segment3D<double>& seg)
| 参数 | 说明 |
|---|---|
p |
测试点 |
seg |
线段 |
返回: 最短距离
点到平面的距离
double distance(const Point3D& p, const Plane<double>& plane)
| 参数 | 说明 |
|---|---|
p |
测试点 |
plane |
平面 |
返回: 绝对垂直距离
参见: Plane::signed_distance
点到三角形的距离
double distance(const Point3D& p, const Triangle<double>& tri)
| 参数 | 说明 |
|---|---|
p |
测试点 |
tri |
三角形 |
返回: 最短距离
点到包围盒的距离
double distance(const Point3D& p, const AABB<double>& box)
| 参数 | 说明 |
|---|---|
p |
测试点 |
box |
包围盒 |
返回: 最短距离(内部点返回 0)
两条线段之间的最短距离
double distance(const Segment3D<double>& a, const Segment3D<double>& b)
| 参数 | 说明 |
|---|---|
a |
第一条线段 |
b |
第二条线段 |
返回: 最短距离(若相交则为 0)
两条直线之间的最短距离
double distance(const Line3D<double>& a, const Line3D<double>& b)
| 参数 | 说明 |
|---|---|
a |
第一条直线 |
b |
第二条直线 |
返回: 最短距离
两个包围盒之间的最短距离
double distance(const AABB<double>& a, const AABB<double>& b)
| 参数 | 说明 |
|---|---|
a |
第一个包围盒 |
b |
第二个包围盒 |
返回: 最短距离
两个三角形之间的最短距离
double distance(const Triangle<double>& a, const Triangle<double>& b)
| 参数 | 说明 |
|---|---|
a |
第一个三角形 |
b |
第二个三角形 |
返回: 最短距离(若相交则为 0)
三角形上距给定点最近的点
Point3D closest_point(const Point3D& p, const Triangle<double>& tri)
| 参数 | 说明 |
|---|---|
p |
查询点 |
tri |
三角形 |
返回: 三角形上距离 p 最近的点
线段上距给定点最近的点
Point3D closest_point(const Point3D& p, const Segment3D<double>& seg)
| 参数 | 说明 |
|---|---|
p |
查询点 |
seg |
线段 |
返回: 线段上距离 p 最近的点(可能为端点)
包围盒上距给定点最近的点
Point3D closest_point(const Point3D& p, const AABB<double>& box)
| 参数 | 说明 |
|---|---|
p |
查询点 |
box |
包围盒 |
返回: 包围盒边界上(或内部)距离 p 最近的点
平面上距给定点最近的点(正交投影)
Point3D closest_point(const Point3D& p, const Plane<double>& plane)
| 参数 | 说明 |
|---|---|
p |
查询点 |
plane |
平面 |
返回: 点 p 在平面上的正交投影
参见: Plane::project
icp.h
ICP(迭代最近点)配准结果
struct ICPResult {
配准后的均方根误差
double rms_error
迭代最近点(ICP)刚体点云配准
[[nodiscard]] ICPResult icp_register(const std::vector<Point3D>& source,
| 参数 | 说明 |
|---|---|
source |
源点云(将被移动) |
target |
目标点云(固定参考) |
max_iter |
最大迭代次数(默认 50) |
tolerance |
收敛容差:相邻两次 RMS 变化的阈值(默认 1e-6) |
返回: 配准结果,包含最终变换和误差
source 和 target 点数可以不同
初始对齐越好,收敛越快;若初始偏差太大,可能收敛到局部最优
line.h
三维无限直线
template <typename T>
从原点和方向构造直线
Line3D(const Point3D& origin, const Vector3D& direction)
| 参数 | 说明 |
|---|---|
origin |
直线上一点 |
direction |
方向向量(自动归一化) |
参数方程求点
[[nodiscard]] Point3D point_at(T t) const { return origin_ + direction_ * t; }
| 参数 | 说明 |
|---|---|
t |
参数值 |
返回: origin + direction * t
三维线段
template <typename T>
从两个端点构造线段
Segment3D(const Point3D& p0, const Point3D& p1) : p0_(p0), p1_(p1) {}
| 参数 | 说明 |
|---|---|
p0 |
起点 |
p1 |
终点 |
方向向量(未归一化)
[[nodiscard]] Vector3D direction() const { return p1_ - p0_; }
返回: p1 - p0
线段长度
[[nodiscard]] T length() const { return direction().norm(); }
返回: ||p1 - p0||
三维射线
template <typename T>
从原点和方向构造射线
Ray3D(const Point3D& origin, const Vector3D& direction)
| 参数 | 说明 |
|---|---|
origin |
射线起点 |
direction |
方向向量(自动归一化) |
参数方程求点(t ≥ 0)
[[nodiscard]] Point3D point_at(T t) const { return origin_ + direction_ * t; }
| 参数 | 说明 |
|---|---|
t |
参数值(应为非负) |
返回: origin + direction * t
plane.h
三维平面
template <typename T>
从点和法线构造平面
Plane(const Point3D& point, const Vector3D& normal)
| 参数 | 说明 |
|---|---|
point |
平面上一点 |
normal |
法向量(自动归一化) |
从三点构造平面
Plane(const Point3D& a, const Point3D& b, const Point3D& c)
| 参数 | 说明 |
|---|---|
a,b,c |
平面上不共线的三点(右手定则决定法线方向) |
获取平面方程常数 d
[[nodiscard]] T d() const { return d_; }
返回: d 值
有向点到平面距离
[[nodiscard]] T signed_distance(const Point3D& p) const { return normal_.dot(p) + d_; }
| 参数 | 说明 |
|---|---|
p |
测试点 |
返回: normal · p + d
绝对点到平面距离
[[nodiscard]] T distance(const Point3D& p) const { return std::abs(signed_distance(p)); }
| 参数 | 说明 |
|---|---|
p |
测试点 |
返回: |signed_distance(p)|
点在平面上的正交投影
[[nodiscard]] Point3D project(const Point3D& p) const {
| 参数 | 说明 |
|---|---|
p |
原点 |
返回: 投影点(满足在平面上且连线垂直于平面)
point.h
核心模块提供 VDE 引擎的几何操作 API:
通用 N 维点类型(重新导出,便于 core 模块使用)
template <typename T, size_t Dim>
通用 N 维向量类型(重新导出)
template <typename T, size_t Dim>
polygon.h
二维平面多边形
内部假设简单多边形(无自交),非简单多边形的行为未定义
所有几何计算基于(假设的)XY 平面
从顶点列表构造多边形
explicit Polygon2D(std::vector<Point2D> vertices) : vertices_(std::move(vertices)) {}
| 参数 | 说明 |
|---|---|
vertices |
顶点序列(逆时针或顺时针均可) |
有向面积(Shoelace 公式)
[[nodiscard]] double signed_area() const
返回: 有向面积
绝对面积
[[nodiscard]] double area() const { return std::abs(signed_area()); }
返回: |signed_area()|
周长(各边长之和)
[[nodiscard]] double perimeter() const
返回: 总边长
面积加权质心
[[nodiscard]] Point2D centroid() const
返回: 质心坐标
二维轴对齐包围盒
[[nodiscard]] AABB<double> bounding_box() const
返回: 包围盒
点包含测试(射线法)
[[nodiscard]] bool contains(const Point2D& p) const
| 参数 | 说明 |
|---|---|
p |
测试点 |
返回: true 若点在多边形内部或边界上
边界上的点也返回 true
多边形是否为逆时针方向
[[nodiscard]] bool is_ccw() const { return signed_area() > 0; }
返回: signed_area() > 0
Douglas-Peucker 简化
[[nodiscard]] Polygon2D simplify(double tolerance) const
| 参数 | 说明 |
|---|---|
tolerance |
允许的最大偏差 |
返回: 简化后的新多边形
参见: triangulate
耳切法三角剖分(Ear Clipping)
[[nodiscard]] std::vector<std::array<int, 3>> triangulate() const
返回: 三角形列表,每个元素为 {i, j, k} 表示顶点索引
时间复杂度 O(n²),适用于顶点数 < 1000 的多边形
参见: simplify
Andrew's Monotone Chain 二维凸包
static Polygon2D convex_hull_2d(const std::vector<Point2D>& points)
| 参数 | 说明 |
|---|---|
points |
输入点集 |
返回: 凸包多边形(CCW,不含共线中间点)
参见: convex_hull_2d
transform.h
三维仿射变换类型
using Transform3D = Eigen::Transform<double, 3, Eigen::Affine>
创建平移变换
inline Transform3D translate(const Vector3D& v) {
| 参数 | 说明 |
|---|---|
v |
平移向量 |
返回: 平移变换矩阵
创建平移变换(分量形式)
inline Transform3D translate(double x, double y, double z) {
| 参数 | 说明 |
|---|---|
x |
X 方向位移 |
y |
Y 方向位移 |
z |
Z 方向位移 |
返回: 平移变换矩阵
创建旋转变换(轴-角表示)
inline Transform3D rotate(const Vector3D& axis, double angle_rad) {
| 参数 | 说明 |
|---|---|
axis |
旋转轴(自动归一化) |
angle_rad |
旋转角度(弧度) |
返回: 旋转变换矩阵
绕 X 轴旋转
inline Transform3D rotate_x(double rad) { return rotate(Vector3D::UnitX(), rad); }
| 参数 | 说明 |
|---|---|
rad |
旋转角度(弧度) |
返回: 旋转变换矩阵
绕 Y 轴旋转
inline Transform3D rotate_y(double rad) { return rotate(Vector3D::UnitY(), rad); }
| 参数 | 说明 |
|---|---|
rad |
旋转角度(弧度) |
返回: 旋转变换矩阵
绕 Z 轴旋转
inline Transform3D rotate_z(double rad) { return rotate(Vector3D::UnitZ(), rad); }
| 参数 | 说明 |
|---|---|
rad |
旋转角度(弧度) |
返回: 旋转变换矩阵
创建非均匀缩放变换
inline Transform3D scale(double sx, double sy, double sz) {
| 参数 | 说明 |
|---|---|
sx |
X 方向缩放因子 |
sy |
Y 方向缩放因子 |
sz |
Z 方向缩放因子 |
返回: 缩放变换矩阵
非均匀缩放可能导致法线方向不准确;使用场景中应考虑法线变换 = (M^{-1})^T
创建均匀缩放变换
inline Transform3D scale(double s) { return scale(s, s, s); }
| 参数 | 说明 |
|---|---|
s |
各方向统一的缩放因子 |
返回: 缩放变换矩阵
triangle.h
三维三角形
template <typename T>
从三个顶点构造三角形
Triangle(const Point3D& v0, const Point3D& v1, const Point3D& v2)
| 参数 | 说明 |
|---|---|
v0 |
第一个顶点 |
v1 |
第二个顶点 |
v2 |
第三个顶点 |
获取第 i 个顶点
[[nodiscard]] const Point3D& v(int i) const { return v_[i]; }
| 参数 | 说明 |
|---|---|
i |
顶点索引(0, 1, 2) |
返回: 顶点引用
三角形单位法向量
[[nodiscard]] Vector3D normal() const {
返回: 单位法向量
若三角形退化(面积为零),返回零向量
三角形面积
[[nodiscard]] T area() const {
返回: 0.5 * ||(v1 - v0) × (v2 - v0)||
三角形质心(几何中心)
[[nodiscard]] Point3D centroid() const {
返回: (v0 + v1 + v2) / 3
重心坐标包含测试
[[nodiscard]] bool contains(const Point3D& p) const {
| 参数 | 说明 |
|---|---|
p |
测试点(三维空间中的任意点) |
返回: true 若投影点在三角形内部或边界上
该测试等效于三维点在三角形上的包含测试(先投影再测试)
voronoi.h
Voronoi 单元格
struct VoronoiCell {
单元格边界顶点(按逆时针顺序排列)
std::vector<Point2D> vertices
单元格边界边
std::vector<std::array<int, 2>> edges
二维 Voronoi 图生成(通过 Delaunay 对偶图)
std::vector<VoronoiCell> voronoi_2d(const std::vector<Point2D>& points)
| 参数 | 说明 |
|---|---|
points |
输入点集(站点) |
返回: 每个站点对应的 VoronoiCell 列表(顺序与输入一致)
对于凸包边界上的站点,对应的 Voronoi 单元格无界,顶点不完全闭合
内部使用 Delaunay 三角剖分作为中间步骤
曲线曲面 (vde::curves)
bezier_curve.h
任意阶 Bézier 曲线
构造 Bézier 曲线
explicit BezierCurve(std::vector<Point3D> control_points)
| 参数 | 说明 |
|---|---|
control_points |
控制点序列,点数 = degree + 1,最少 2 个 |
控制点数量决定了曲线阶次;点数越多,曲线越灵活但计算越昂贵
在参数 t 处求值曲线点
[[nodiscard]] Point3D evaluate(double t) const
| 参数 | 说明 |
|---|---|
t |
参数值,范围 [0, 1] |
返回: 曲线上对应 t 的点坐标
使用 de Casteljau 递推算法,O(n²) 复杂度
在参数 t 处求导数
[[nodiscard]] Vector3D derivative(double t, int order = 1) const
| 参数 | 说明 |
|---|---|
t |
参数值,范围 [0, 1] |
order |
导数阶数,1 = 一阶(切向量),2 = 二阶(曲率相关) |
返回: 导数向量
高阶导数通过降阶 Bézier 曲线计算:
曲线阶次
[[nodiscard]] int degree() const { return static_cast<int>(cp_.size()) - 1; }
返回: 阶次 = 控制点数 - 1
参数定义域
[[nodiscard]] std::pair<double, double> domain() const { return {0.0, 1.0}; }
返回: 固定为 [0, 1]
控制点访问
[[nodiscard]] const std::vector<Point3D>& control_points() const { return cp_; }
返回: 控制点向量的只读引用
在 t 处将曲线一分为二
[[nodiscard]] std::pair<BezierCurve, BezierCurve> split(double t) const
| 参数 | 说明 |
|---|---|
t |
分割参数,范围 [0, 1] |
返回: 左段 + 右段两条 Bézier 曲线
使用 de Casteljau 分割算法,分割点为三角阵的对角线
升阶操作
[[nodiscard]] BezierCurve degree_elevate(int times = 1) const
| 参数 | 说明 |
|---|---|
times |
升阶次数,≥ 1 |
返回: 升阶后的 Bézier 曲线(控制点数增加 times,形状不变)
通过反复应用公式 P_i' = i/(n+1) P_{i-1} + (1 - i/(n+1)) P_i
参见: split
bezier_surface.h
Bézier 张量积曲面
构造 Bézier 曲面
BezierSurface(std::vector<std::vector<Point3D>> control_grid)
| 参数 | 说明 |
|---|---|
control_grid |
控制点网格,grid[i][j] 对应 u 方向第 i 个、v 方向第 j 个控制点 |
grid 必须矩整(所有行等长);grid.size() = degree_u+1, grid[0].size() = degree_v+1
求曲面点 S(u,v)
[[nodiscard]] Point3D evaluate(double u, double v) const
| 参数 | 说明 |
|---|---|
u |
u 参数,范围 [0, 1] |
v |
v 参数,范围 [0, 1] |
返回: 曲面上对应 (u,v) 的 3D 坐标
张量积求值:先按 v 方向对每行做 de Casteljau,再沿 u 方向对结果做一次
u 方向偏导数 ∂S/∂u
[[nodiscard]] Vector3D derivative_u(double u, double v) const
| 参数 | 说明 |
|---|---|
u |
u 参数 |
v |
v 参数 |
返回: u 方向切向量
通过降阶 Bézier 曲线计算:对 v 求值后沿 u 求导
v 方向偏导数 ∂S/∂v
[[nodiscard]] Vector3D derivative_v(double u, double v) const
| 参数 | 说明 |
|---|---|
u |
u 参数 |
v |
v 参数 |
返回: v 方向切向量
单位法向量 N(u,v) = (∂S/∂u × ∂S/∂v) / |…|
[[nodiscard]] Vector3D normal(double u, double v) const
| 参数 | 说明 |
|---|---|
u |
u 参数 |
v |
v 参数 |
返回: 归一化法向量(指向曲面的特选侧)
当两个偏导数平行时返回零向量(奇异点)
u 向阶次
[[nodiscard]] int degree_u() const { return static_cast<int>(cp_.size()) - 1; }
返回: u 方向阶次(控制点行数 - 1)
v 向阶次
[[nodiscard]] int degree_v() const { return static_cast<int>(cp_[0].size()) - 1; }
返回: v 方向阶次(控制点列数 - 1)
一维 de Casteljau 求值(内部辅助)
[[nodiscard]] Point3D de_casteljau(double t, const std::vector<Point3D>& pts) const
| 参数 | 说明 |
|---|---|
t |
参数 |
pts |
一维控制点序列 |
返回: 求值结果
bspline_curve.h
B 样条曲线(非有理、均匀/非均匀节点)
构造 B 样条曲线
BSplineCurve(std::vector<Point3D> control_points,
| 参数 | 说明 |
|---|---|
control_points |
n+1 个控制点 |
knots |
节点向量,必须为非递减序列 |
degree |
阶次 p |
节点数量 = 控制点数 + 阶次 + 1;clamped 端点多重度为 p+1
在参数 t 处求值曲线点
[[nodiscard]] Point3D evaluate(double t) const
| 参数 | 说明 |
|---|---|
t |
参数值,必须在 domain() 范围内 |
返回: 曲线上对应 t 的点坐标
使用 de Boor(Cox-de Boor)递推算法
在参数 t 处求导数
[[nodiscard]] Vector3D derivative(double t, int order = 1) const
| 参数 | 说明 |
|---|---|
t |
参数值 |
order |
导数阶数,1 = 一切向量 |
返回: 导数向量
B 样条导数公式:
曲线阶次
[[nodiscard]] int degree() const { return degree_; }
返回: 阶次 p
参数定义域
[[nodiscard]] std::pair<double, double> domain() const
返回: 有效参数范围 [knots[p], knots[n+1]]
控制点访问
[[nodiscard]] const std::vector<Point3D>& control_points() const { return cp_; }
返回: 控制点数组只读引用
节点向量访问
[[nodiscard]] const std::vector<double>& knots() const { return knots_; }
返回: 节点向量只读引用
查找 t 所在的节点区间
[[nodiscard]] int find_span(double t) const
| 参数 | 说明 |
|---|---|
t |
参数值 |
返回: 节点区间索引 i 满足 knots[i] ≤ t < knots[i+1]
使用二分查找,O(log n);求值和基函数的前置步骤
在 t 处求非零基函数值
[[nodiscard]] std::vector<double> basis_functions(double t, int span = -1) const
| 参数 | 说明 |
|---|---|
t |
参数值 |
span |
节点区间索引,-1 表示自动查找 |
返回: N_{span-p}(t), ..., N_{span}(t) 共 p+1 个值
仅返回 p+1 个非零基函数;用于端点求值及插值
参见: find_span
在 t 处求非零基函数的一阶导数
[[nodiscard]] std::vector<double> basis_derivatives(double t, int span = -1) const
| 参数 | 说明 |
|---|---|
t |
参数值 |
span |
节点区间索引,-1 表示自动查找 |
返回: dN_{span-p}/du, ..., dN_{span}/du 共 p+1 个值
B 样条基函数导数递推:
参见: basis_functions
bspline_surface.h
B 样条张量积曲面(非有理)
构造 B 样条曲面
BSplineSurface(std::vector<std::vector<Point3D>> control_grid,
| 参数 | 说明 |
|---|---|
control_grid |
(nu+1)×(nv+1) 控制点网格 |
knots_u |
u 向节点向量,长度 = nu + pu + 1 |
knots_v |
v 向节点向量,长度 = nv + pv + 1 |
degree_u |
u 向阶次 pu |
degree_v |
v 向阶次 pv |
求曲面点 S(u,v)
[[nodiscard]] Point3D evaluate(double u, double v) const
| 参数 | 说明 |
|---|---|
u |
u 参数 |
v |
v 参数 |
返回: 曲面上的 3D 点
张量积分解:先行后列(或先列后行)做两次 B 样条求值
u 向偏导数 ∂S/∂u
[[nodiscard]] Vector3D derivative_u(double u, double v) const
| 参数 | 说明 |
|---|---|
u |
u 参数 |
v |
v 参数 |
返回: u 向切向量
v 向偏导数 ∂S/∂v
[[nodiscard]] Vector3D derivative_v(double u, double v) const
| 参数 | 说明 |
|---|---|
u |
u 参数 |
v |
v 参数 |
返回: v 向切向量
单位法向量
[[nodiscard]] Vector3D normal(double u, double v) const
| 参数 | 说明 |
|---|---|
u |
u 参数 |
v |
v 参数 |
返回: N(u,v) = (∂S/∂u × ∂S/∂v) / |…|
u 向阶次
[[nodiscard]] int degree_u() const { return degree_u_; }
返回: pu
v 向阶次
[[nodiscard]] int degree_v() const { return degree_v_; }
返回: pv
u 向节点向量
[[nodiscard]] const std::vector<double>& knots_u() const { return knots_u_; }
返回: 只读引用
v 向节点向量
[[nodiscard]] const std::vector<double>& knots_v() const { return knots_v_; }
返回: 只读引用
nurbs_curve.h
NURBS 曲线(Non-Uniform Rational B-Spline)
构造 NURBS 曲线
NurbsCurve(std::vector<Point3D> control_points, std::vector<double> knots,
| 参数 | 说明 |
|---|---|
control_points |
控制点序列 |
knots |
节点向量 |
weights |
权重序列,必须与 control_points 等长,各分量 > 0 |
degree |
阶次 p |
所有权重必须 > 0 以保证分母不为零(非退化)
在参数 t 处求值
[[nodiscard]] Point3D evaluate(double t) const
| 参数 | 说明 |
|---|---|
t |
参数值 |
返回: 曲线上对应 t 的点坐标
内部将 (w·P, w) 提升为齐次坐标的 B 样条,求值后投影回 3D
在参数 t 处求导数
[[nodiscard]] Vector3D derivative(double t, int order = 1) const
| 参数 | 说明 |
|---|---|
t |
参数值 |
order |
导数阶数 |
返回: 导数向量
有理导数公式:
曲线阶次
[[nodiscard]] int degree() const { return degree_; }
返回: p
参数定义域
[[nodiscard]] std::pair<double, double> domain() const
返回: [knots[degree], knots[n+1]]
控制点访问
[[nodiscard]] const std::vector<Point3D>& control_points() const { return cp_; }
返回: 只读引用
权重访问
[[nodiscard]] const std::vector<double>& weights() const { return weights_; }
返回: 只读引用
节点向量访问
[[nodiscard]] const std::vector<double>& knots() const { return knots_; }
返回: 只读引用
nurbs_operations.h
NURBS 曲面等距偏移
[[nodiscard]] NurbsSurface offset_surface(const NurbsSurface& surf, double distance)
| 参数 | 说明 |
|---|---|
surf |
输入 NURBS 曲面 |
distance |
偏移距离(正值 = 沿法向外,负值 = 向内) |
返回: 偏移后的 NURBS 曲面(近似,阶次与原曲面相同)
这是几何近似,非精确偏移。对于大变曲率曲面,增大控制点数量
偏移可能导致自交(distance 超过曲面局部曲率半径时)
参见: trim_surface blend_surfaces
NURBS 曲面参数域裁剪
[[nodiscard]] NurbsSurface trim_surface(const NurbsSurface& surf,
| 参数 | 说明 |
|---|---|
surf |
输入曲面 |
u_min,u_max |
裁剪后的 u 参数范围(必须在原 domain 内) |
v_min,v_max |
裁剪后的 v 参数范围(必须在原 domain 内) |
返回: 裁剪后的 NURBS 曲面
裁剪是"软裁剪"——几何不变,仅改变参数化。如需"硬裁剪"
两 NURBS 曲面沿边界边的过渡面
[[nodiscard]] NurbsSurface blend_surfaces(const NurbsSurface& surf_a,
| 参数 | 说明 |
|---|---|
surf_a |
第一个曲面 |
surf_b |
第二个曲面 |
edge_a |
surf_a 的边界边索引(0=u_min, 1=u_max, 2=v_min, 3=v_max) |
edge_b |
surf_b 的边界边索引(0=u_min, 1=u_max, 2=v_min, 3=v_max) |
blend_radius |
过渡半径 |
返回: 过渡 NURBS 曲面(在偏移边界曲线间的直纹面)
过渡面与原始曲面在边界处为 C⁰ 连续(非切线连续)
参见: ruled_surface
两 NURBS 曲线间的直纹面
[[nodiscard]] NurbsSurface ruled_surface(const NurbsCurve& curve_a,
| 参数 | 说明 |
|---|---|
curve_a |
第一条曲线(v=0 边界) |
curve_b |
第二条曲线(v=1 边界) |
返回: 直纹 NURBS 曲面
两条曲线需有兼容的阶次和节点结构(内部执行升阶和节点精化)
参见: coons_patch blend_surfaces
由四条边界曲线创建 Coons 曲面
[[nodiscard]] NurbsSurface coons_patch(const NurbsCurve& curve_u0,
| 参数 | 说明 |
|---|---|
curve_u0 |
v=0 处边界(沿 u 方向) |
curve_u1 |
v=1 处边界(沿 u 方向) |
curve_v0 |
u=0 处边界(沿 v 方向) |
curve_v1 |
u=1 处边界(沿 v 方向) |
返回: Coons 曲面
仅保证边界插值,不保证内部形状与设计意图一致
参见: ruled_surface
沿方向向量拉伸 NURBS 曲线为曲面
[[nodiscard]] NurbsSurface extrude_curve(const NurbsCurve& curve,
| 参数 | 说明 |
|---|---|
curve |
截面曲线 |
direction |
拉伸方向(内部归一化) |
length |
拉伸长度 |
返回: 拉伸 NURBS 曲面
提取 NURBS 曲面的等参边界曲线
[[nodiscard]] NurbsCurve extract_boundary_curve(const NurbsSurface& surf, int edge)
| 参数 | 说明 |
|---|---|
surf |
输入曲面 |
edge |
边界索引:0=u_min, 1=u_max, 2=v_min, 3=v_max |
返回: 指定边界上的 NURBS 曲线
边界曲线继承原曲面该方向的阶次和节点向量
nurbs_surface.h
NURBS 张量积曲面
构造 NURBS 曲面
NurbsSurface(std::vector<std::vector<Point3D>> control_grid,
| 参数 | 说明 |
|---|---|
control_grid |
控制点网格 |
knots_u |
u 向节点向量 |
knots_v |
v 向节点向量 |
weights |
权重网格,维度与 control_grid 一致,所有值 > 0 |
degree_u |
u 向阶次 |
degree_v |
v 向阶次 |
求曲面点 S(u,v)
[[nodiscard]] Point3D evaluate(double u, double v) const
| 参数 | 说明 |
|---|---|
u |
u 参数 |
v |
v 参数 |
返回: 曲面上对应 (u,v) 的 3D 点
u 向偏导数
[[nodiscard]] Vector3D derivative_u(double u, double v) const
| 参数 | 说明 |
|---|---|
u |
u 参数 |
v |
v 参数 |
返回: ∂S/∂u
v 向偏导数
[[nodiscard]] Vector3D derivative_v(double u, double v) const
| 参数 | 说明 |
|---|---|
u |
u 参数 |
v |
v 参数 |
返回: ∂S/∂v
单位法向量
[[nodiscard]] Vector3D normal(double u, double v) const
| 参数 | 说明 |
|---|---|
u |
u 参数 |
v |
v 参数 |
返回: N(u,v) = normalize(∂S/∂u × ∂S/∂v)
u 向阶次
[[nodiscard]] int degree_u() const { return degree_u_; }
返回: pu
v 向阶次
[[nodiscard]] int degree_v() const { return degree_v_; }
返回: pv
控制点数量
[[nodiscard]] std::array<int, 2> num_control_points() const {
返回: {nu+1, nv+1},即网格的行数和列数
u 向节点向量
[[nodiscard]] const std::vector<double>& knots_u() const { return knots_u_; }
返回: 只读引用
v 向节点向量
[[nodiscard]] const std::vector<double>& knots_v() const { return knots_v_; }
返回: 只读引用
控制点网格访问
[[nodiscard]] const std::vector<std::vector<Point3D>>& control_points() const { return cp_; }
返回: 只读引用
权重网格访问
[[nodiscard]] const std::vector<std::vector<double>>& weights() const { return weights_; }
返回: 只读引用
由两条 NURBS 曲线创建直纹面
static NurbsSurface ruled(const NurbsCurve& c1, const NurbsCurve& c2)
| 参数 | 说明 |
|---|---|
c1 |
起始曲线(v=0 边界) |
c2 |
终止曲线(v=1 边界) |
返回: 直纹 NURBS 曲面
两条曲线需具有兼容的阶次和节点结构(内部做升阶和节点精化对齐)
参见: blend_surfaces ruled_surface
由截面曲线旋转生成旋转曲面
static NurbsSurface revolve(const NurbsCurve& profile, const Point3D& axis_origin,
| 参数 | 说明 |
|---|---|
profile |
截面 NURBS 曲线 |
axis_origin |
旋转轴上一点 |
axis_dir |
旋转轴方向 |
angle_rad |
旋转角度(弧度),≤ 2π |
返回: 旋转 NURBS 曲面
使用 NURBS 表示圆弧的权重方案;完整旋转生成闭曲面
将 NURBS 曲面三角化
[[nodiscard]] std::pair<std::vector<Point3D>, std::vector<std::array<int,3>>>
| 参数 | 说明 |
|---|---|
res_u |
u 方向采样分辨率 |
res_v |
v 方向采样分辨率 |
返回: {顶点数组, 三角形索引数组},每个三角形为 {i0,i1,i2}
生成 res_u×res_v 均匀网格,每个单元格拆为两个三角形
参见: tessellate
tessellation.h
均匀参数化曲面三角化
std::pair<std::vector<Point3D>, std::vector<std::array<int, 3>>>
| 参数 | 说明 |
|---|---|
eval |
曲面求值函数 eval(u,v) -> Point3D,参数 (u,v) ∈ [0,1]×[0,1] |
res_u |
u 方向子分段数(≥ 1) |
res_v |
v 方向子分段数(≥ 1) |
返回: {顶点数组, 三角形索引数组},三角形为 {i0,i1,i2}
总顶点数 = (res_u+1)×(res_v+1),三角形数 = 2×res_u×res_v
参见: adaptive_tessellate
自适应曲面三角化
std::pair<std::vector<Point3D>, std::vector<std::array<int, 3>>>
| 参数 | 说明 |
|---|---|
eval |
曲面求值函数 eval(u,v) -> Point3D |
normal_fn |
单位法向函数 normal_fn(u,v) -> Vector3D |
min_res |
初始每向子分段数(≥ 1),默认 2 |
max_depth |
最大递归深度,限制总面数,默认 6 |
angle_threshold_deg |
法向角度偏差阈值(度),默认 5.0 |
返回: {顶点数组, 三角形索引数组}
最终面数上限约为 2·min_res²·4^max_depth(实际远小于此上限)
参见: tessellate
网格处理 (vde::mesh)
alpha_shapes.h
Alpha Shapes 点云表面重建
TetrahedronMesh alpha_shapes(const std::vector<Point3D>& points, double alpha)
| 参数 | 说明 |
|---|---|
points |
输入 3D 点云 |
alpha |
α 半径阈值,通常取平均点间距的 1~3 倍 |
返回: TetrahedronMesh 保留的四面体网格
参见: alpha_shapes_surface delaunay_3d
将 Alpha Shapes 四面体网格的表面提取为三角形网格
std::pair<std::vector<Point3D>, std::vector<std::array<int,3>>>
| 参数 | 说明 |
|---|---|
tet_mesh |
Alpha Shapes 输出的四面体网格 |
返回: {顶点数组, 三角形索引数组}
表面三角形法向指向四面体外部(右手定则)
参见: alpha_shapes
cdt_2d.h
约束 Delaunay 三角化(CDT)
DelaunayResult constrained_delaunay_2d(
| 参数 | 说明 |
|---|---|
points |
输入 2D 点集 |
constraints |
约束边列表,每项为 {起点索引, 终点索引} |
返回: DelaunayResult 含约束边的三角化结果
约束边不能相交(否则行为未定义);自相交约束需先分割交点
参见: delaunay_2d
delaunay_2d.h
2D Delaunay 三角化结果
struct DelaunayResult {
2D Delaunay 三角化(Bowyer-Watson 增量算法)
DelaunayResult delaunay_2d(const std::vector<Point2D>& points)
| 参数 | 说明 |
|---|---|
points |
输入 2D 点集(至少 3 个不共线点) |
返回: DelaunayResult 三角化结果
时间复杂度:平均 O(n log n),最坏 O(n²)
参见: constrained_delaunay_2d
delaunay_3d.h
四面体网格结构
struct TetrahedronMesh {
3D Delaunay 四面体化(Bowyer-Watson 增量算法)
TetrahedronMesh delaunay_3d(const std::vector<Point3D>& points)
| 参数 | 说明 |
|---|---|
points |
输入 3D 点集(至少 4 个不共面点) |
返回: TetrahedronMesh 四面体网格
时间复杂度与 2D 类似:平均 O(n log n),最坏 O(n²)
输出包括内部和边界四面体;通过 alpha_shapes 可提取表面
参见: alpha_shapes
geodesic.h
热方法(Heat Method)计算测地距离
std::vector<double> geodesic_distance(const HalfedgeMesh& mesh,
| 参数 | 说明 |
|---|---|
mesh |
输入三角网格 |
sources |
源顶点索引列表(距离为 0 的顶点) |
t |
时间步长,< 0 时自动设为平均边长平方 |
返回: 每顶点到最近源点的测地距离
要求网格为连通流形;时间步长 t 越小精度越高但数值越不稳定
halfedge_mesh.h
半边数据结构元素
struct Halfedge {
面元素
struct Face {
半边数据结构三角网格
清空所有数据
void clear()
添加顶点
int add_vertex(const Point3D& p)
| 参数 | 说明 |
|---|---|
p |
3D 坐标 |
返回: 新顶点的索引(0-based)
添加面
int add_face(const std::vector<int>& vertex_indices)
| 参数 | 说明 |
|---|---|
vertex_indices |
按逆时针顺序排列的顶点索引(至少 3 个) |
返回: 新面的索引,失败返回 -1
自动创建/查找半边并设置对侧关系;面法向遵循右手定则
从三角形列表批量构建半边形网格
void build_from_triangles(const std::vector<Point3D>& verts,
| 参数 | 说明 |
|---|---|
verts |
顶点位置数组 |
tris |
三角形索引数组,每个 {i0,i1,i2} |
等价于反复调用 add_vertex + add_face,但内部做批处理优化
顶点数量
[[nodiscard]] size_t num_vertices() const { return vertices_.size(); }
返回: vertices_ 大小
面数量
[[nodiscard]] size_t num_faces() const { return faces_.size(); }
返回: faces_ 大小
边数量
[[nodiscard]] size_t num_edges() const { return halfedges_.size() / 2; }
返回: halfedges_.size() / 2
访问顶点
[[nodiscard]] const Point3D& vertex(size_t idx) const { return vertices_[idx]; }
| 参数 | 说明 |
|---|---|
idx |
顶点索引,0 ≤ idx < num_vertices() |
返回: 顶点坐标只读引用
访问面
[[nodiscard]] const Face& face(size_t idx) const { return faces_[idx]; }
| 参数 | 说明 |
|---|---|
idx |
面索引 |
返回: Face 只读引用
访问半边
[[nodiscard]] const Halfedge& halfedge(size_t idx) const { return halfedges_[idx]; }
| 参数 | 说明 |
|---|---|
idx |
半边索引 |
返回: Halfedge 只读引用
更新顶点位置
void set_vertex(size_t idx, const Point3D& p) { vertices_[idx] = p; normals_dirty_ = true; }
| 参数 | 说明 |
|---|---|
idx |
顶点索引 |
p |
新坐标 |
标记法向缓存为脏,下次查询时重新计算
获取面的所有顶点索引(按环绕顺序)
[[nodiscard]] std::vector<int> face_vertices(int fi) const
| 参数 | 说明 |
|---|---|
fi |
面索引 |
返回: 顶点索引序列
获取顶点的邻面索引环
[[nodiscard]] std::vector<int> vertex_faces(int vi) const
| 参数 | 说明 |
|---|---|
vi |
顶点索引 |
返回: 所有以 vi 为顶点的面索引
是否为边界半边
[[nodiscard]] bool is_boundary_edge(int hei) const { return halfedges_[hei].face_index < 0; }
| 参数 | 说明 |
|---|---|
hei |
半边索引 |
返回: 没有所属面时为 true
是否为边界顶点
[[nodiscard]] bool is_boundary_vertex(int vi) const
| 参数 | 说明 |
|---|---|
vi |
顶点索引 |
返回: 邻接任何边界半边时为 true
面法向(几何法向,非归一化?由实现决定)
[[nodiscard]] Vector3D face_normal(int fi) const
| 参数 | 说明 |
|---|---|
fi |
面索引 |
返回: (v1-v0)×(v2-v0) 归一化结果
顶点法向(邻面法向的面积加权平均)
[[nodiscard]] Vector3D vertex_normal(int vi) const
| 参数 | 说明 |
|---|---|
vi |
顶点索引 |
返回: 归一化顶点法向
重新计算所有面法向和顶点法向
void update_normals()
修改顶点位置后自动标记脏位,调用此方法触发重新计算
网格包围盒
[[nodiscard]] AABB3D bounds() const
返回: AABB3D 轴对齐包围盒
面迭代器范围(支持 for-range)
顶点单邻环迭代器
获取所有面范围(range-based for 支持)
[[nodiscard]] FaceRange faces_range() const
返回: FaceRange 对象
获取顶点的 1-ring 邻域迭代器
[[nodiscard]] VertexOneRing vertex_one_ring(int vi) const
| 参数 | 说明 |
|---|---|
vi |
顶点索引 |
返回: VertexOneRing 对象
查找或创建半边 (v0→v1)
int find_or_create_edge(int v0, int v1)
| 参数 | 说明 |
|---|---|
v0 |
起点顶点索引 |
v1 |
终点顶点索引 |
返回: 半边索引
marching_cubes.h
Marching Cubes 输出网格
struct MCMesh {
Marching Cubes 等值面提取
MCMesh marching_cubes(const std::function<double(double,double,double)>& f,
| 参数 | 说明 |
|---|---|
f |
标量场函数 f(x,y,z) → double |
iso_level |
等值面值(默认 0) |
bmin |
包围盒最小角 |
bmax |
包围盒最大角 |
resolution |
每轴采样分辨率(≥ 1),总网格 = resolution³ 个立方体 |
返回: MCMesh 三角形网格
使用经典的 256 查表法(Lorensen & Cline 1987)
参见: sdf_sphere sdf_box
SDF 球体函数
inline double sdf_sphere(double x, double y, double z, double cx, double cy, double cz, double r) {
| 参数 | 说明 |
|---|---|
x,y,z |
采样点坐标 |
cx,cy,cz |
球心坐标 |
r |
半径 |
返回: 有符号距离:内部 < 0,表面 = 0,外部 > 0
SDF 立方体函数(轴对齐,中心在原点)
inline double sdf_box(double x, double y, double z, double hx, double hy, double hz) {
| 参数 | 说明 |
|---|---|
x,y,z |
采样点坐标 |
hx,hy,hz |
半边长 |
返回: 有符号距离
SDF 平滑并集(Smooth Union)
| 参数 | 说明 |
|---|---|
d1,d2 |
两个 SDF 值 |
k |
平滑宽度(> 0),值越大过渡越平滑 |
返回: 混合后的 SDF 值
SDF 平滑差集(Smooth Subtraction)
inline double sdf_smooth_subtraction(double d1, double d2, double k) {
| 参数 | 说明 |
|---|---|
d1,d2 |
两个 SDF 值 |
k |
平滑宽度(> 0) |
返回: 混合后的 SDF 值
mesh_boolean.h
布尔运算类型(CSG 组合)
enum class BooleanOp {
三角网格布尔运算
HalfedgeMesh mesh_boolean(const HalfedgeMesh& a, const HalfedgeMesh& b, BooleanOp op)
| 参数 | 说明 |
|---|---|
a |
第一个三角网格(必须为封闭流形) |
b |
第二个三角网格(必须为封闭流形) |
op |
布尔运算类型 |
返回: 结果三角网格
要求输入网格为封闭流形(watertight),否则分类不可靠
mesh_curvature.h
离散曲率计算结果
struct CurvatureResult {
离散曲率计算(Cotan 公式,Meyer et al. 2003)
CurvatureResult compute_curvature(const HalfedgeMesh& mesh)
| 参数 | 说明 |
|---|---|
mesh |
输入三角网格 |
返回: CurvatureResult 每顶点曲率
要求网格为流形;边界顶点曲率使用近似公式
mesh_parameterize.h
Tutte 参数化(调和参数化)
[[nodiscard]] std::vector<Point2D> tutte_parameterization(const HalfedgeMesh& mesh)
| 参数 | 说明 |
|---|---|
mesh |
输入三角网格(需含边界) |
返回: 每顶点 UV 坐标(Point2D),顺序与 mesh 顶点一致
网格必须有边界(开网格);闭曲面需先切割为拓扑圆盘
参见: lscm_parameterization
LSCM(Least Squares Conformal Maps)参数化
[[nodiscard]] std::vector<Point2D> lscm_parameterization(const HalfedgeMesh& mesh)
| 参数 | 说明 |
|---|---|
mesh |
输入三角网格 |
返回: 每顶点 UV 坐标(Point2D)
简化实现,不包含完整 Lévy 论文中所有的退化处理
参见: tutte_parameterization
mesh_quality.h
三角网格质量指标
struct MeshQuality {
评估三角网格质量
MeshQuality evaluate_mesh_quality(const HalfedgeMesh& mesh)
| 参数 | 说明 |
|---|---|
mesh |
输入三角网格 |
返回: MeshQuality 质量指标汇总
四面体网格质量指标
struct TetQuality {
评估三角网格作为四面体边界的质量
TetQuality evaluate_tet_quality(const HalfedgeMesh& mesh)
| 参数 | 说明 |
|---|---|
mesh |
封闭三角网格(volume boundary) |
返回: TetQuality 四面体质量指标
这不是真正的四面体网格质量评估——仅用于表面网格的代理指标
单元类型枚举
enum class ElementType {
通用单元质量指标
struct ElemQuality {
按单元类型分派的网格质量评估
ElemQuality evaluate_element_quality(const HalfedgeMesh& mesh, ElementType type)
| 参数 | 说明 |
|---|---|
mesh |
输入网格 |
type |
单元类型 |
返回: ElemQuality 质量指标
目前仅 Tri 和 Tet 完整实现;Quad / Hex 返回 stub(全零)
详细质量报告
struct QualityReport {
生成三角网格的完整质量报告
QualityReport mesh_quality_report(const HalfedgeMesh& mesh)
| 参数 | 说明 |
|---|---|
mesh |
输入三角网格 |
返回: QualityReport 完整质量报告
生成四面体网格的完整质量报告
QualityReport mesh_quality_report_tet(const HalfedgeMesh& mesh)
| 参数 | 说明 |
|---|---|
mesh |
封闭三角网格 |
返回: QualityReport 完整质量报告
三角形归一化 Jacobian
double tri_scaled_jacobian(const Point3D& a, const Point3D& b, const Point3D& c)
| 参数 | 说明 |
|---|---|
a,b,c |
三角形三个顶点 |
返回: 归一化 Jacobian [-1, 1]
四面体归一化 Jacobian
double tet_scaled_jacobian(const Point3D& a, const Point3D& b,
| 参数 | 说明 |
|---|---|
a,b,c,d |
四面体四个顶点 |
返回: 归一化 Jacobian [0, 1]
mesh_repair.h
网格修复选项
struct RepairOptions {
自动网格修复
HalfedgeMesh repair_mesh(const HalfedgeMesh& mesh, const RepairOptions& opts = {})
| 参数 | 说明 |
|---|---|
mesh |
输入网格(可能有缺陷) |
opts |
修复选项(默认全部启用) |
返回: 修复后的网格
修复为启发式算法,不保证 100% 成功;孔洞过大或非流形边可能仍有残留问题
mesh_simplify.h
网格简化选项
struct SimplifyOptions {
QEM(Quadric Error Metrics)网格简化
HalfedgeMesh simplify_mesh(const HalfedgeMesh& mesh, const SimplifyOptions& opts = {})
| 参数 | 说明 |
|---|---|
mesh |
输入三角网格 |
opts |
简化选项 |
返回: 简化后的网格
preserve_boundary 模式下,边界边通过惩罚项(大代价)被保护
mesh_smooth.h
网格光顺方法
enum class SmoothMethod {
网格光顺参数
struct SmoothOptions {
网格光顺(通用分发器)
HalfedgeMesh smooth_mesh(const HalfedgeMesh& mesh, const SmoothOptions& opts = {})
| 参数 | 说明 |
|---|---|
mesh |
输入三角网格 |
opts |
光顺选项 |
返回: 光顺后的网格(顶点位置更新,拓扑不变)
标准拉普拉斯光顺
HalfedgeMesh smooth_laplacian(const HalfedgeMesh& mesh, int iterations, double lambda)
| 参数 | 说明 |
|---|---|
mesh |
输入网格 |
iterations |
迭代次数 |
lambda |
步长系数 (0, 1] |
返回: 光顺后的网格
迭代过多会导致网格坍塌;对于体积关键的应用优先选 Taubin 或 HC
参见: smooth_taubin smooth_hc_laplacian
Taubin λ|μ 光顺(体积保持)
HalfedgeMesh smooth_taubin(const HalfedgeMesh& mesh, int iterations, double lambda, double mu)
| 参数 | 说明 |
|---|---|
mesh |
输入网格 |
iterations |
完整 λ/μ 循环次数 |
lambda |
正步系数 (0, 1] |
mu |
负步系数,需满足 mu < 0 且 |
返回: 光顺后的网格
典型值:λ = 0.5, μ = -0.53;|mu| 过大可能导致不稳定振荡
HC 拉普拉斯光顺(Humphrey's Classes)
HalfedgeMesh smooth_hc_laplacian(const HalfedgeMesh& mesh, const SmoothOptions& opts = {})
| 参数 | 说明 |
|---|---|
mesh |
输入网格 |
opts |
光顺选项(使用 hc_alpha 和 hc_beta 字段) |
返回: 光顺后的网格
双边网格滤波
HalfedgeMesh smooth_bilateral(const HalfedgeMesh& mesh, const SmoothOptions& opts = {})
| 参数 | 说明 |
|---|---|
mesh |
输入网格 |
opts |
光顺选项(使用 bilateral_ 前缀字段) |
返回: 光顺后的网格
空间索引 (vde::spatial)
bvh.h
包围盒层次结构 (Bounding Volume Hierarchy)
BVH 构建分裂策略
enum class BVHSplitStrategy {
< 按最长轴中点分裂
Equal, /**< 按数量均等分裂 */
< 按数量均等分裂
SAH /**< Surface Area Heuristic — 最小化射线击中概率期望 */
< Surface Area Heuristic — 最小化射线击中概率期望
}
BVH 构建选项
struct BVHBuildOptions {
< 分裂策略
int leaf_size = 4; /**< 叶节点最大图元数 */
< 叶节点最大图元数
int max_depth = 64; /**< 树的最大深度 */
< 树的最大深度
}
包围盒层次结构 — 三角形网格加速结构
参见: SpatialIndex, Octree, KDTree, RTree
构造 BVH 并指定构建选项
explicit BVH(const BVHBuildOptions& opts = {}) : opts_(opts) {}
| 参数 | 说明 |
|---|---|
opts |
构建选项(分裂策略、叶节点大小、最大深度) |
清除已有数据并重建 BVH
void build(const std::vector<Triangle3D>& tris) override
| 参数 | 说明 |
|---|---|
tris |
三角形数组 |
插入单个三角形
void insert(const Triangle3D& tri) override
| 参数 | 说明 |
|---|---|
tri |
要插入的三角形 |
删除三角形
bool remove(const Triangle3D& tri) override
| 参数 | 说明 |
|---|---|
tri |
要删除的三角形 |
返回: 删除成功返回 true
AABB 范围查询
std::vector<Triangle3D> query_range(const AABB3D& range) const override
| 参数 | 说明 |
|---|---|
range |
查询包围盒 |
返回: 与 range 相交的三角形列表
K 近邻查询
std::vector<Triangle3D> query_knn(const Point3D& point, size_t k) const override
| 参数 | 说明 |
|---|---|
point |
查询点 |
k |
返回数量 |
返回: 最近的 k 个三角形
射线查询:返回所有命中的三角形
std::vector<Triangle3D> query_ray(const Ray3Dd& ray) const override
| 参数 | 说明 |
|---|---|
ray |
查询射线 |
返回: 按命中顺序排列的三角形列表
清空 BVH 树和所有三角形
void clear() override
三角形数量
size_t size() const override { return primitives_.size(); }
返回: 当前索引的三角形总数
射线最近命中查询结果
struct HitResult {
< 沿射线的参数 t
Triangle3D tri; /**< 命中的三角形 */
< 命中的三角形
Point3D point; /**< 命中点的世界坐标 = origin + t * dir */
< 命中点的世界坐标 = origin + t * dir
}
射线最近命中查询
std::optional<HitResult> query_ray_nearest(const Ray3Dd& ray) const
| 参数 | 说明 |
|---|---|
ray |
查询射线 |
返回: 最近命中结果(若无命中则返回空)
比 query_ray() 更高效,仅返回最近命中
BVH 节点
struct Node {
< 节点的包围盒(所有子节点/图元的并集)
int left = -1; /**< 左子节点索引,叶节点为 -1 */
< 左子节点索引,叶节点为 -1
int right = -1; /**< 右子节点索引,叶节点为 -1 */
< 右子节点索引,叶节点为 -1
int first_prim = 0; /**< 叶节点第一个图元的索引 */
< 叶节点第一个图元的索引
int prim_count = 0; /**< 叶节点图元数量 */
< 叶节点图元数量
/** @brief 判断是否为叶节点 */
判断是否为叶节点
bool leaf() const { return left < 0; }
< 节点数组(根节点为 nodes_[0])
std::vector<Triangle3D> primitives_; /**< 图元数组 */
< 图元数组
BVHBuildOptions opts_; /**< 构建选项 */
< 构建选项
/**
递归构建 BVH 子树
void build_recursive(int node, int first, int count, int depth)
| 参数 | 说明 |
|---|---|
node |
当前节点索引 |
first |
图元范围的起始索引 |
count |
图元数量 |
depth |
当前递归深度 |
计算 SAH 分裂代价
double sah_cost(int n_left, int n_right, const AABB3D& left, const AABB3D& right) const
| 参数 | 说明 |
|---|---|
n_left |
左子树图元数 |
n_right |
右子树图元数 |
left |
左子树包围盒 |
right |
右子树包围盒 |
返回: SAH 代价估值
kd_tree.h
k-d 树 (K-Dimensional Tree) 空间划分结构
k-d 树空间索引
template <typename T>
k-d 树在维度约 2~6 时效率最佳。三维场景中,
参见: SpatialIndex, BVH, Octree
批量构建 k-d 树
void build(const std::vector<T>& items) override
| 参数 | 说明 |
|---|---|
items |
待索引的对象数组 |
插入单个对象
void insert(const T& item) override
| 参数 | 说明 |
|---|---|
item |
待插入的空间对象 |
删除对象
bool remove(const T& item) override
| 参数 | 说明 |
|---|---|
item |
待删除的空间对象 |
返回: 删除成功返回 true
范围查询
std::vector<T> query_range(const AABB3D& range) const override
| 参数 | 说明 |
|---|---|
range |
查询包围盒 |
返回: 与 range 相交的对象列表
K 近邻查询
std::vector<T> query_knn(const Point3D& point, size_t k) const override
| 参数 | 说明 |
|---|---|
point |
查询点 |
k |
返回数量 |
返回: 最近的 k 个对象
射线查询
std::vector<T> query_ray(const Ray3Dd& ray) const override
| 参数 | 说明 |
|---|---|
ray |
查询射线 |
返回: 与射线相交的对象列表
清空 k-d 树
void clear() override
对象数量
size_t size() const override { return items_.size(); }
返回: 当前索引的对象总数
k-d 树节点
struct Node {
< 节点包围盒
int item_idx = -1; /**< 叶节点对应的对象索引(-1 表示内部节点) */
< 叶节点对应的对象索引(-1 表示内部节点)
int split_axis = 0; /**< 分裂轴:0=x, 1=y, 2=z */
< 分裂轴:0=x, 1=y, 2=z
int left = -1; /**< 左子节点索引 */
< 左子节点索引
int right = -1; /**< 右子节点索引 */
< 右子节点索引
}
< 对象数组
std::vector<Node> nodes_; /**< 节点数组 */
< 节点数组
int root_ = -1; /**< 根节点索引 */
< 根节点索引
/**
获取对象代表位置(用于空间排序)
static Point3D get_position(const T& item)
| 参数 | 说明 |
|---|---|
item |
空间对象 |
返回: 对象的三维代表点
获取对象的轴对齐包围盒
static AABB3D get_aabb(const T& item)
| 参数 | 说明 |
|---|---|
item |
空间对象 |
返回: 包围盒
判断对象是否与射线相交
static bool ray_hits_item(const T& item, const Ray3Dd& ray)
| 参数 | 说明 |
|---|---|
item |
空间对象 |
ray |
查询射线 |
返回: 相交返回 true
递归构建 k-d 树
int build_recursive(int start, int end)
| 参数 | 说明 |
|---|---|
start |
items_ 中当前范围起始索引 |
end |
items_ 中当前范围结束索引 |
返回: 新节点的索引
递归范围查询
void query_range_recursive(int node_idx, const AABB3D& range,
| 参数 | 说明 |
|---|---|
node_idx |
当前节点索引 |
range |
查询包围盒 |
result |
累积结果 |
递归射线查询
void query_ray_recursive(int node_idx, const Ray3Dd& ray,
| 参数 | 说明 |
|---|---|
node_idx |
当前节点索引 |
ray |
查询射线 |
result |
累积结果 |
octree.h
八叉树 (Octree) 空间划分结构
八叉树空间索引
template <typename T>
适用于体积数据、粒子系统、空间哈希等场景。
参见: SpatialIndex, BVH, KDTree
构造八叉树
explicit Octree(int max_depth = 8, int max_items = 16)
| 参数 | 说明 |
|---|---|
max_depth |
最大递归深度(默认 8,对应 256³ 分辨率) |
max_items |
节点剖分前可容纳的最大对象数(默认 16) |
批量构建八叉树
void build(const std::vector<T>& items) override
| 参数 | 说明 |
|---|---|
items |
待索引的对象数组 |
增量插入对象
void insert(const T& item) override
| 参数 | 说明 |
|---|---|
item |
待插入的空间对象 |
删除对象
bool remove(const T& item) override
| 参数 | 说明 |
|---|---|
item |
待删除的空间对象 |
返回: 删除成功返回 true;对象不存在返回 false
范围查询
std::vector<T> query_range(const AABB3D& range) const override
| 参数 | 说明 |
|---|---|
range |
查询包围盒 |
返回: 与 range 相交的对象列表
K 近邻查询
std::vector<T> query_knn(const Point3D& point, size_t k) const override
| 参数 | 说明 |
|---|---|
point |
查询点 |
k |
返回数量 |
返回: 最近的 k 个对象
射线查询
std::vector<T> query_ray(const Ray3Dd& ray) const override
| 参数 | 说明 |
|---|---|
ray |
查询射线 |
返回: 按命中顺序排列的相交对象列表
清空八叉树
void clear() override
当前索引中的对象数量
size_t size() const override
返回: 对象总数
递归插入对象到指定节点
void insert_recursive(int node_idx, const T& item, int depth)
| 参数 | 说明 |
|---|---|
node_idx |
目标节点索引 |
item |
待插入的对象 |
depth |
当前递归深度 |
递归剖分节点
void subdivide_recursive(int node_idx, int depth)
| 参数 | 说明 |
|---|---|
node_idx |
当前节点索引 |
depth |
当前深度 |
递归范围查询
void query_range_recursive(int node_idx, const AABB3D& range,
| 参数 | 说明 |
|---|---|
node_idx |
当前节点索引 |
range |
查询包围盒 |
result |
累积结果 |
递归射线查询
void query_ray_recursive(int node_idx, const Ray3Dd& ray,
| 参数 | 说明 |
|---|---|
node_idx |
当前节点索引 |
ray |
查询射线 |
result |
累积结果 |
获取对象空间位置(用于剖分分配)
static Point3D get_position(const T& item)
| 参数 | 说明 |
|---|---|
item |
空间对象 |
返回: 对象的代表点
< 八叉树内部数据
int max_depth_; /**< 最大递归深度 */
< 最大递归深度
int max_items_; /**< 节点剖分阈值 */
< 节点剖分阈值
}
r_tree.h
R 树 (R-Tree) 动态空间索引
R 树节点
template <typename T>
< 节点包围盒(子节点/对象 MBR 的并集)
bool is_leaf = true; /**< 是否为叶节点 */
< 是否为叶节点
std::vector<size_t> children; /**< 内部节点:子节点索引列表 */
< 内部节点:子节点索引列表
std::vector<size_t> item_indices; /**< 叶节点:对象索引列表 */
< 叶节点:对象索引列表
size_t parent = static_cast<size_t>(-1); /**< 父节点索引 */
< 父节点索引
}
R 树动态空间索引
template <typename T>
R 树在动态场景(如编辑中的几何体)中比 BVH 更合适。
参见: SpatialIndex, BVH, RStarTree
批量构建 R 树
void build(const std::vector<T>& items) override
| 参数 | 说明 |
|---|---|
items |
待索引的对象数组 |
增量插入对象
void insert(const T& item) override
| 参数 | 说明 |
|---|---|
item |
待插入的空间对象 |
删除对象
bool remove(const T& item) override
| 参数 | 说明 |
|---|---|
item |
待删除的空间对象 |
返回: 删除成功返回 true
范围查询
std::vector<T> query_range(const AABB3D& range) const override
| 参数 | 说明 |
|---|---|
range |
查询包围盒 |
返回: 与 range 相交的对象列表
K 近邻查询
std::vector<T> query_knn(const Point3D& point, size_t k) const override
| 参数 | 说明 |
|---|---|
point |
查询点 |
k |
返回数量 |
返回: 最近的 k 个对象
射线查询
std::vector<T> query_ray(const Ray3Dd& ray) const override
| 参数 | 说明 |
|---|---|
ray |
查询射线 |
返回: 与射线相交的对象列表
清空 R 树
void clear() override
对象数量
size_t size() const override { return count_; }
返回: 当前索引的对象总数
R 树节点总数
size_t node_count() const { return nodes_.size(); }
返回: 内部节点 + 叶节点数量
递归范围查询
void query_range_recursive(size_t node_idx, const AABB3D& range,
| 参数 | 说明 |
|---|---|
node_idx |
当前节点索引 |
range |
查询包围盒 |
result |
累积结果 |
< 对象数组
std::vector<AABB3D> item_bounds_; /**< 对象包围盒数组 */
< 对象包围盒数组
std::vector<RTreeNode<T>> nodes_; /**< R 树节点数组 */
< R 树节点数组
size_t root_idx_ = 0; /**< 根节点索引 */
< 根节点索引
size_t count_ = 0; /**< 对象计数 */
< 对象计数
}
spatial_index.h
空间索引抽象基类
空间索引抽象基类
template <typename T>
本类为纯虚接口,不可直接实例化
批量构建索引
virtual void build(const std::vector<T>& items) = 0
| 参数 | 说明 |
|---|---|
items |
待索引的对象数组 |
插入单个对象
virtual void insert(const T& item) = 0
| 参数 | 说明 |
|---|---|
item |
待插入的空间对象 |
删除单个对象
virtual bool remove(const T& item) = 0
| 参数 | 说明 |
|---|---|
item |
待删除的空间对象 |
返回: true 删除成功;false 对象不存在
范围查询:返回与 AABB 相交的所有对象
virtual std::vector<T> query_range(const AABB3D& range) const = 0
| 参数 | 说明 |
|---|---|
range |
查询的轴对齐包围盒 |
返回: 与 range 相交的对象列表
K 近邻查询:返回距 point 最近的 k 个对象
virtual std::vector<T> query_knn(const Point3D& point, size_t k) const = 0
| 参数 | 说明 |
|---|---|
point |
查询点 |
k |
需要返回的对象数量 |
返回: 按距离升序排列的 k 个最近对象
射线查询:返回与射线相交的所有对象
virtual std::vector<T> query_ray(const Ray3Dd& ray) const = 0
| 参数 | 说明 |
|---|---|
ray |
查询射线 |
返回: 按命中距离升序排列的相交对象列表
清空索引中所有数据
virtual void clear() = 0
当前索引中的对象数量
virtual size_t size() const = 0
返回: 对象计数
布尔运算 (vde::boolean)
boolean_2d.h
二维多边形布尔运算
布尔运算类型
enum class BooleanOp {
< 并集 A ∪ B
Intersection, /**< 交集 A ∩ B */
< 交集 A ∩ B
Difference, /**< 差集 A − B */
< 差集 A − B
SymDiff /**< 对称差 (A − B) ∪ (B − A) */
< 对称差 (A − B) ∪ (B − A)
}
二维多边形布尔运算
std::vector<Polygon2D> boolean_2d(const Polygon2D& a, const Polygon2D& b, BooleanOp op)
| 参数 | 说明 |
|---|---|
a |
第一个多边形 |
b |
第二个多边形 |
op |
布尔操作类型 |
返回: 结果多边形列表(可能有多个分离的组件)
当前版本优化了凸多边形路径。对于带孔洞或自交的
参见: BooleanOp, mesh_boolean, polygon_offset
boolean_mesh.h
三维网格布尔运算
网格并集 A ∪ B
HalfedgeMesh mesh_union(const HalfedgeMesh& a, const HalfedgeMesh& b)
| 参数 | 说明 |
|---|---|
a |
网格 A |
b |
网格 B |
返回: A ∪ B 的合并网格
参见: mesh_intersection, mesh_difference, is_point_inside_mesh
网格交集 A ∩ B
HalfedgeMesh mesh_intersection(const HalfedgeMesh& a, const HalfedgeMesh& b)
| 参数 | 说明 |
|---|---|
a |
网格 A |
b |
网格 B |
返回: A ∩ B 的交集网格
结果体积为两网格公共区域
参见: mesh_union, mesh_difference
网格差集 A − B
HalfedgeMesh mesh_difference(const HalfedgeMesh& a, const HalfedgeMesh& b)
| 参数 | 说明 |
|---|---|
a |
网格 A |
b |
网格 B |
返回: A − B 的差集网格
结果中来自 B 的面片会被翻转法线以保持内-外一致性
参见: mesh_union, mesh_intersection, mesh_sym_diff
网格对称差 (A − B) ∪ (B − A)
HalfedgeMesh mesh_sym_diff(const HalfedgeMesh& a, const HalfedgeMesh& b)
| 参数 | 说明 |
|---|---|
a |
网格 A |
b |
网格 B |
返回: 对称差网格
参见: mesh_difference, mesh_union
用网格 B 裁剪网格 A
HalfedgeMesh clip_mesh(const HalfedgeMesh& a, const HalfedgeMesh& b,
| 参数 | 说明 |
|---|---|
a |
待裁剪网格 |
b |
裁剪体网格 |
invert_b |
若为 true,将 B 的内外判定取反(裁剪外部) |
返回: 裁剪后的网格(仅包含 A 的面片)
参见: mesh_difference, is_point_inside_mesh
翻转网格所有面片的法线方向
HalfedgeMesh invert_mesh(const HalfedgeMesh& m)
| 参数 | 说明 |
|---|---|
m |
原始网格 |
返回: 法线翻转后的网格
参见: mesh_difference
合并两个网格
HalfedgeMesh merge_meshes(const HalfedgeMesh& a, const HalfedgeMesh& b)
| 参数 | 说明 |
|---|---|
a |
网格 A |
b |
网格 B |
返回: 包含 A 和 B 全部顶点和面片的合并网格
不处理重叠区域;仅做纯几何拼接
参见: mesh_union(做布尔合并)
网格布尔运算统一接口
HalfedgeMesh mesh_boolean(const HalfedgeMesh& a, const HalfedgeMesh& b, BooleanOp op)
| 参数 | 说明 |
|---|---|
a |
网格 A |
b |
网格 B |
op |
布尔操作类型 |
返回: 结果网格
参见: BooleanOp, mesh_union, mesh_intersection, mesh_difference, mesh_sym_diff
判断三维点是否在封闭网格内部
bool is_point_inside_mesh(const core::Point3D& p, const HalfedgeMesh& mesh)
| 参数 | 说明 |
|---|---|
p |
待判定点 |
mesh |
封闭网格 |
返回: 点在网格内部返回 true
网格必须是封闭(水密)的,否则结果不可靠。
参见: clip_mesh, mesh_difference
polygon_offset.h
多边形等距偏移 (Polygon Offset / Inset)
多边形等距偏移
std::vector<Polygon2D> polygon_offset(const Polygon2D& poly, double distance)
| 参数 | 说明 |
|---|---|
poly |
原始多边形 |
distance |
偏移距离(正=外扩,负=内缩) |
返回: 偏移后的多边形列表(内缩或自交可能产生多个碎片)
使用直骨架近似而非精确圆弧偏移,转角处为斜角连接。
参见: boolean_2d
碰撞检测 (vde::collision)
gjk.h
GJK (Gilbert–Johnson–Keerthi) 碰撞检测算法
支撑函数类型
using SupportFunc = std::function<Point3D(const Vector3D&)>
GJK 完整检测结果
struct GJKResult {
< 两凸体是否相交
double distance; /**< 最近距离(不相交时 >0,相交时为 0) */
< 最近距离(不相交时 >0,相交时为 0)
Point3D point_a; /**< 形状 A 上的最近点 */
< 形状 A 上的最近点
Point3D point_b; /**< 形状 B 上的最近点 */
< 形状 B 上的最近点
}
GJK 相交检测(仅判断是否碰撞)
bool gjk_intersect(const SupportFunc& shape_a, const SupportFunc& shape_b)
| 参数 | 说明 |
|---|---|
shape_a |
形状 A 的支撑函数 |
shape_b |
形状 B 的支撑函数 |
返回: 相交返回 true
参见: gjk_distance, gjk_full, SupportFunc
GJK 最近距离查询
double gjk_distance(const SupportFunc& shape_a, const SupportFunc& shape_b)
| 参数 | 说明 |
|---|---|
shape_a |
形状 A 的支撑函数 |
shape_b |
形状 B 的支撑函数 |
返回: 最近距离(相交时返回 0),始终 ≥ 0
参见: gjk_intersect, gjk_full
GJK 完整检测:碰撞状态、距离、最近点对
GJKResult gjk_full(const SupportFunc& shape_a, const SupportFunc& shape_b)
| 参数 | 说明 |
|---|---|
shape_a |
形状 A 的支撑函数 |
shape_b |
形状 B 的支撑函数 |
返回: GJKResult 包含碰撞状态、距离、最近点对
对于连续碰撞检测 (CCD) 或需要分离向量的场景,
参见: gjk_intersect, gjk_distance
ray_intersect.h
射线求交工具集
射线-三角形求交结果
struct RayTriResult {
< 沿射线的参数:hit_point = origin + t * dir
double u, v; /**< 三角形重心坐标:hit_point = (1−u−v)*v0 + u*v1 + v*v2 */
< 三角形重心坐标:hit_point = (1−u−v)v0 + uv1 + v*v2
Point3D point; /**< 命中点的世界坐标 */
< 命中点的世界坐标
}
射线-三角形求交(Möller-Trumbore 算法)
std::optional<RayTriResult> ray_triangle_intersect(
| 参数 | 说明 |
|---|---|
origin |
射线起点 |
dir |
射线方向(需归一化以获得正确 t 值) |
tri |
三角形 |
返回: 命中返回 RayTriResult;未命中返回空
参见: ray_mesh_intersect
射线-三角形求交(Ray3Dd 重载)
inline std::optional<RayTriResult> ray_triangle_intersect(
| 参数 | 说明 |
|---|---|
ray |
射线 |
tri |
三角形 |
返回: 命中返回 RayTriResult;未命中返回空
参见: ray_triangle_intersect(origin, dir, tri)
射线-AABB 求交(slab 方法)
bool ray_aabb_intersect(const Ray3Dd& ray, const AABB3D& box,
| 参数 | 说明 |
|---|---|
ray |
射线 |
box |
轴对齐包围盒 |
tmin_out |
[输出] 进入包围盒的参数 t |
tmax_out |
[输出] 离开包围盒的参数 t |
返回: 命中返回 true
常用于 BVH 遍历节点的快速 rejection test
参见: ray_triangle_intersect
射线-球体求交结果
struct RaySphereResult {
< 命中参数(通常取较小的 t)
Point3D point; /**< 命中点世界坐标 */
< 命中点世界坐标
}
射线-球体求交(解析法)
std::optional<RaySphereResult> ray_sphere_intersect(
| 参数 | 说明 |
|---|---|
origin |
射线起点 |
dir |
射线方向 |
center |
球心 |
radius |
球半径 |
返回: 命中返回 RaySphereResult(最近交点);未命中返回空
参见: ray_sphere_intersect(ray, center, radius)
射线-球体求交(Ray3Dd 重载)
inline std::optional<RaySphereResult> ray_sphere_intersect(
| 参数 | 说明 |
|---|---|
ray |
射线 |
center |
球心 |
radius |
球半径 |
返回: 命中返回 RaySphereResult;未命中返回空
射线-平面求交
std::optional<double> ray_plane_intersect(
| 参数 | 说明 |
|---|---|
origin |
射线起点 |
dir |
射线方向 |
plane_point |
平面上一点 |
plane_normal |
平面法线(需归一化以获得正确 t) |
返回: 命中返回参数 t;未命中(平行或反向)返回空
射线-平面求交(Ray3Dd 重载)
inline std::optional<double> ray_plane_intersect(
| 参数 | 说明 |
|---|---|
ray |
射线 |
plane_point |
平面上一点 |
plane_normal |
平面法线 |
返回: 命中返回参数 t;未命中返回空
射线-网格求交(暴力遍历)
std::optional<RayTriResult> ray_mesh_intersect(
| 参数 | 说明 |
|---|---|
origin |
射线起点 |
dir |
射线方向 |
triangles |
三角形列表 |
返回: 最近命中结果;无命中返回空
对于大型网格建议配合 BVH 使用:
参见: ray_tri_intersect.h, query_ray_nearest (BVH)
射线-网格求交(Ray3Dd 重载)
inline std::optional<RayTriResult> ray_mesh_intersect(
| 参数 | 说明 |
|---|---|
ray |
射线 |
triangles |
三角形列表 |
返回: 最近命中结果;无命中返回空
sat.h
SAT (Separating Axis Theorem) 碰撞检测
SAT 凸多面体相交检测
bool sat_intersect(const std::vector<Point3D>& verts_a,
| 参数 | 说明 |
|---|---|
verts_a |
多面体 A 的顶点数组 |
faces_a |
多面体 A 的面索引数组(每个面为 {v0, v1, v2}) |
verts_b |
多面体 B 的顶点数组 |
faces_b |
多面体 B 的面索引数组 |
返回: 相交返回 true
适用于任意凸多面体。对于胶囊/球等光滑形状,GJK 更合适。
参见: gjk_intersect, tri_tri_intersect
tri_intersect.h
三角形-三角形 / 三角形-AABB 相交检测
三角形-三角形相交检测(布尔测试)
bool tri_tri_intersect(const Triangle3D& t1, const Triangle3D& t2)
| 参数 | 说明 |
|---|---|
t1 |
三角形 1 |
t2 |
三角形 2 |
返回: 相交返回 true
参见: tri_tri_intersect_detailed, sat_intersect
三角形-三角形相交线段
struct TriTriIntersection {
< 是否相交
Point3D p0; /**< 交点段起点 */
< 交点段起点
Point3D p1; /**< 交点段终点 */
< 交点段终点
}
三角形-三角形详细相交检测
TriTriIntersection tri_tri_intersect_detailed(const Triangle3D& t1,
| 参数 | 说明 |
|---|---|
t1 |
三角形 1 |
t2 |
三角形 2 |
返回: TriTriIntersection:相交标志 + 交点段端点
共面情况交集段可能退化为单点(p0 == p1)
参见: tri_tri_intersect
三角形-AABB 快速相交测试
bool tri_aabb_overlap(const Triangle3D& tri, const AABB3D& box)
| 参数 | 说明 |
|---|---|
tri |
三角形 |
box |
轴对齐包围盒 |
返回: 相交返回 true
AABB 碰撞比三角剖分后的三角-三角检测更高效,
参见: tri_tri_intersect, ray_aabb_intersect
B-Rep建模 (vde::brep)
assembly.h
装配体节点
struct AssemblyNode {
装配体
struct Assembly {
brep.h
边界表示(B-Rep)核心数据结构
边曲线类型枚举
enum class CurveType { Line, Circle, Bezier, BSpline, Nurbs }
拓扑顶点
struct TopoVertex {
拓扑边
struct TopoEdge {
拓扑环(Loop)
struct TopoLoop {
拓扑面
struct TopoFace {
拓扑壳
struct TopoShell {
拓扑体
struct TopoBody {
B-Rep 模型
参见: brep_validate.h 验证, modeling.h 高层建模 API, brep_boolean.h 布尔运算
添加顶点
int add_vertex(const Point3D& p)
| 参数 | 说明 |
|---|---|
p |
顶点坐标 |
返回: 新顶点的 ID
添加直线边
int add_edge(int v0, int v1)
| 参数 | 说明 |
|---|---|
v0 |
起点顶点 ID |
v1 |
终点顶点 ID |
返回: 新边的 ID
添加曲线边
int add_edge(int v0, int v1, const curves::NurbsCurve& curve)
| 参数 | 说明 |
|---|---|
v0 |
起点顶点 ID |
v1 |
终点顶点 ID |
curve |
边的几何曲线 |
返回: 新边的 ID
添加环
int add_loop(const std::vector<int>& edges, bool outer = true)
| 参数 | 说明 |
|---|---|
edges |
环中边的 ID 序列(顺序连接) |
outer |
true = 外环, false = 内环 |
返回: 新环的 ID
添加面
int add_face(int surface_id, const std::vector<int>& loops)
| 参数 | 说明 |
|---|---|
surface_id |
关联曲面 ID |
loops |
环 ID 列表 |
返回: 新面的 ID
添加壳
int add_shell(const std::vector<int>& faces, bool closed = true)
| 参数 | 说明 |
|---|---|
faces |
面 ID 列表 |
closed |
是否为封闭壳 |
返回: 新壳的 ID
添加体
int add_body(const std::vector<int>& shells, const std::string& name = "")
| 参数 | 说明 |
|---|---|
shells |
壳 ID 列表 |
name |
体名称 |
返回: 新体的 ID
添加 NURBS 曲面
int add_surface(const curves::NurbsSurface& surf)
| 参数 | 说明 |
|---|---|
surf |
NURBS 曲面定义 |
返回: 新曲面的 ID
顶点数量
[[nodiscard]] size_t num_vertices() const { return vertices_.size(); }
边数量
[[nodiscard]] size_t num_edges() const { return edges_.size(); }
面数量
[[nodiscard]] size_t num_faces() const { return faces_.size(); }
体数量
[[nodiscard]] size_t num_bodies() const { return bodies_.size(); }
曲面数量
[[nodiscard]] size_t num_surfaces() const { return surfaces_.size(); }
按数组索引访问顶点
[[nodiscard]] const TopoVertex& vertex(int id) const { return vertices_[id]; }
按唯一 ID 访问顶点(适用于边数据中的 ID 引用)
[[nodiscard]] const TopoVertex& vertex_by_id(int id) const
按数组索引访问边
[[nodiscard]] const TopoEdge& edge(int id) const { return edges_[id]; }
按数组索引访问面
[[nodiscard]] const TopoFace& face(int id) const { return faces_[id]; }
按数组索引访问曲面
[[nodiscard]] const curves::NurbsSurface& surface(int id) const { return surfaces_[id]; }
按唯一 ID 访问环
[[nodiscard]] const TopoLoop& loop_by_id(int id) const
获取所有环的只读引用
[[nodiscard]] const std::vector<TopoLoop>& all_loops() const { return loops_; }
计算模型的轴对齐包围盒
[[nodiscard]] core::AABB3D bounds() const
返回: 包围盒(AABB)
检查模型有效性(快速版本)
[[nodiscard]] bool is_valid() const
返回: true 如果模型通过基本检查
参见: validate() 完整验证(水密性、方向一致性等)
将 B-Rep 模型 tessellate 为三角网格
[[nodiscard]] mesh::HalfedgeMesh to_mesh(double deflection = 0.01) const
| 参数 | 说明 |
|---|---|
deflection |
弦高误差(控制 tessellation 精度,默认 0.01) |
返回: HalfedgeMesh 三角网格
deflection 越小网格越精细,但三角形数量显著增加。
获取面的所有边
[[nodiscard]] std::vector<int> face_edges(int face_id) const
| 参数 | 说明 |
|---|---|
face_id |
面 ID |
返回: 边 ID 列表(去重)
获取边的所有相邻面
[[nodiscard]] std::vector<int> edge_faces(int edge_id) const
| 参数 | 说明 |
|---|---|
edge_id |
边 ID |
返回: 相邻面 ID 列表
获取顶点的所有相邻边
[[nodiscard]] std::vector<int> vertex_edges(int vertex_id) const
| 参数 | 说明 |
|---|---|
vertex_id |
顶点 ID |
返回: 相邻边 ID 列表
brep_boolean.h
B-Rep 级别的布尔运算
B-Rep 布尔并集: A ∪ B
[[nodiscard]] BrepModel brep_union(const BrepModel& a, const BrepModel& b)
| 参数 | 说明 |
|---|---|
a |
第一个 B-Rep 实体 |
b |
第二个 B-Rep 实体 |
返回: 新的 B-Rep 实体(a ∪ b)
参见: brep_intersection 交集, brep_difference 差集
B-Rep 布尔交集: A ∩ B
[[nodiscard]] BrepModel brep_intersection(const BrepModel& a, const BrepModel& b)
| 参数 | 说明 |
|---|---|
a |
第一个 B-Rep 实体 |
b |
第二个 B-Rep 实体 |
返回: 新的 B-Rep 实体(a ∩ b)
参见: brep_union 并集, brep_difference 差集
B-Rep 布尔差集: A \ B
[[nodiscard]] BrepModel brep_difference(const BrepModel& a, const BrepModel& b)
| 参数 | 说明 |
|---|---|
a |
被减实体 A |
b |
减去实体 B |
返回: 新的 B-Rep 实体(a \ b)
参见: brep_union 并集, brep_intersection 交集
brep_validate.h
B-Rep 模型综合验证
B-Rep 模型的综合验证结果
struct ValidationResult {
是否通过所有必要检查
bool valid = true
错误信息列表(导致 valid = false)
std::vector<std::string> errors
警告信息列表(不影响 valid)
std::vector<std::string> warnings
水密性比率:恰好有 2 个相邻面的边的比例(1.0 = 完美水密)
double watertightness = 1.0
无自交比率:不与其他面内部相交的面对比例(1.0 = 无自交)
double self_intersection_free = 1.0
最短边的长度(用于检测退化边)
double min_edge_length = std::numeric_limits<double>::max()
最长边的长度(用于检测超长边)
double max_edge_length = 0.0
非流形边数(相邻面 ≠ 2 的边)
size_t non_manifold_edges = 0
悬挂边数(无相邻面的边)
size_t dangling_edges = 0
方向不一致的面数
size_t inconsistent_orientations = 0
总边数
size_t total_edges = 0
总面数
size_t total_faces = 0
对 BrepModel 执行综合验证
[[nodiscard]] ValidationResult validate(const BrepModel& body)
| 参数 | 说明 |
|---|---|
body |
待验证的 B-Rep 模型 |
返回: ValidationResult 包含所有检查结果的详细报告
自交检测是最昂贵的检查项(O(n²) 面对数),
参见: BrepModel::is_valid() 快速有效性检查(无详细报告)
iges_export.h
IGES 文件导出(版本 5.3)
将 B-Rep 体导出为 IGES 格式字符串(版本 5.3)
[[nodiscard]] std::string export_iges(const std::vector<BrepModel>& bodies)
| 参数 | 说明 |
|---|---|
bodies |
B-Rep 体列表 |
返回: IGES 5.3 格式字符串
参见: export_iges_file 直接写入文件, export_step STEP 格式导出
将 B-Rep 体导出为 IGES 文件
void export_iges_file(const std::string& filepath, const std::vector<BrepModel>& bodies)
| 参数 | 说明 |
|---|---|
filepath |
输出文件路径(建议扩展名 .igs 或 .iges) |
bodies |
B-Rep 体列表 |
参见: export_iges 获取字符串输出
iges_import.h
IGES 文件导入(ANSI Y14.26M)
IGES 导入错误码
enum class IgesError {
从文件导入 IGES
[[nodiscard]] std::vector<BrepModel> import_iges(const std::string& filepath)
| 参数 | 说明 |
|---|---|
filepath |
.igs 或 .iges 文件路径 |
返回: B-Rep 体列表
IGES 格式较为宽松,不同 CAD 系统的实现差异很大。
参见: import_iges_from_string 从字符串导入, iges_last_error 获取错误码
从字符串导入 IGES(用于测试)
[[nodiscard]] std::vector<BrepModel> import_iges_from_string(const std::string& data)
| 参数 | 说明 |
|---|---|
data |
IGES 文件完整内容(字符串形式) |
返回: B-Rep 体列表
参见: import_iges 从文件导入
获取最近一次 IGES 导入的错误码
[[nodiscard]] IgesError iges_last_error()
返回: IgesError 枚举值
参见: iges_last_error_message 获取可读描述
获取最近一次 IGES 导入的可读错误描述
[[nodiscard]] const std::string& iges_last_error_message()
返回: 错误描述字符串
参见: iges_last_error 获取枚举错误码
modeling.h
高层 B-Rep 建模 API
沿方向挤出平面轮廓
[[nodiscard]] BrepModel extrude(const curves::NurbsCurve& profile, const Vector3D& dir)
| 参数 | 说明 |
|---|---|
profile |
轮廓曲线(必须位于一个平面内) |
dir |
挤出方向向量(其长度决定挤出距离) |
返回: 挤出后的 B-Rep 实体
参见: revolve 旋转扫掠, sweep 沿任意路径扫掠
绕轴旋转平面轮廓
[[nodiscard]] BrepModel revolve(const curves::NurbsCurve& profile,
| 参数 | 说明 |
|---|---|
profile |
轮廓曲线(通常位于轴的半平面中) |
axis_origin |
旋转轴上的一个点 |
axis_dir |
旋转轴方向(单位向量) |
angle_rad |
旋转角度(弧度,默认 2π = 完整的旋转体) |
返回: 旋转后的 B-Rep 实体
参见: extrude 线性挤出, make_sphere 直接创建球体
沿任意路径扫掠轮廓
[[nodiscard]] BrepModel sweep(const curves::NurbsCurve& profile,
| 参数 | 说明 |
|---|---|
profile |
截面轮廓(需位于路径起点的垂直平面内) |
path |
扫掠路径曲线 |
返回: 扫掠后的 B-Rep 实体
路径曲率过大处可能出现自交,需要控制路径的光滑性。
参见: extrude 直线挤出, revolve 旋转扫掠
在两个或多个轮廓曲线之间放样
[[nodiscard]] BrepModel loft(const std::vector<curves::NurbsCurve>& profiles)
| 参数 | 说明 |
|---|---|
profiles |
轮廓曲线列表(至少 2 条) |
返回: 放样后的 B-Rep 实体
参见: extrude 单轮廓挤出
创建立方体
[[nodiscard]] BrepModel make_box(double w, double h, double d)
| 参数 | 说明 |
|---|---|
w |
宽度(X 方向),必须 > 0 |
h |
高度(Y 方向),必须 > 0 |
d |
深度(Z 方向),必须 > 0 |
返回: 实心立方体 B-Rep
参见: make_cylinder 圆柱体, make_sphere 球体
创建圆柱体
[[nodiscard]] BrepModel make_cylinder(double radius, double height, int segments = 32)
| 参数 | 说明 |
|---|---|
radius |
截面半径,必须 > 0 |
height |
总高度,沿 Y 轴从 -h/2 到 +h/2 |
segments |
截面分段数(边数,默认 32) |
返回: 实心圆柱体 B-Rep
segments 越大圆柱越光滑,但面和边数增加。
参见: make_box 立方体, make_sphere 球体
创建球体
[[nodiscard]] BrepModel make_sphere(double radius, int segments_u = 32, int segments_v = 16)
| 参数 | 说明 |
|---|---|
radius |
球半径,必须 > 0 |
segments_u |
经度方向分段数(默认 32) |
segments_v |
纬度方向分段数(默认 16) |
返回: 实心球体 B-Rep
参见: make_cylinder 圆柱体
对边做圆角处理
[[nodiscard]] BrepModel fillet(const BrepModel& body, int edge_id, double radius)
| 参数 | 说明 |
|---|---|
body |
输入实体 |
edge_id |
要倒圆的边 ID |
radius |
圆角半径,必须 > 0 |
返回: 圆角后的新实体
圆角半径不能超过相邻面的最小宽度,否则会产生自交。
只支持恒定半径圆角。变半径圆角尚未实现。
参见: chamfer 倒角, shell 抽壳
对边做倒角
[[nodiscard]] BrepModel chamfer(const BrepModel& body, int edge_id, double distance)
| 参数 | 说明 |
|---|---|
body |
输入实体 |
edge_id |
要倒角的边 ID |
distance |
倒角距离(从原边沿两个面各偏移的距离) |
返回: 倒角后的新实体
参见: fillet 圆角
抽壳(挖空实体)
[[nodiscard]] BrepModel shell(const BrepModel& body, int face_id, double thickness)
| 参数 | 说明 |
|---|---|
body |
输入实心实体 |
face_id |
要移除的面 ID(形成开口),-1 表示封闭壳(不开口) |
thickness |
壁厚(正值 = 向外偏移,负值 = 向内偏移) |
返回: 抽壳后的新实体
壁厚不应超过实体最小尺寸的一半。
当 face_id = -1 时,结果是一个封闭的壳(中空但没有开口)。
参见: fillet 圆角
step_export.h
STEP 文件导出(ISO 10303-214)
将 B-Rep 体导出为 STEP AP214 字符串
[[nodiscard]] std::string export_step(const std::vector<BrepModel>& bodies)
| 参数 | 说明 |
|---|---|
bodies |
B-Rep 体列表(每个体对应一个 PRODUCT) |
返回: STEP AP214 格式字符串
输出包含所有必要的 ISO 10303-21 头部信息。
参见: export_step_file 直接写入文件, export_iges IGES 格式导出
将 B-Rep 体导出为 STEP 文件
void export_step_file(const std::string& filepath, const std::vector<BrepModel>& bodies)
| 参数 | 说明 |
|---|---|
filepath |
输出文件路径(建议扩展名 .step 或 .stp) |
bodies |
B-Rep 体列表 |
参见: export_step 获取字符串输出
step_import.h
STEP 文件导入(ISO 10303)
STEP 导入错误码
enum class StepError {
从文件导入 STEP(AP203/AP214)
[[nodiscard]] std::vector<BrepModel> import_step(const std::string& filepath)
| 参数 | 说明 |
|---|---|
filepath |
.step 或 .stp 文件路径 |
返回: B-Rep 体列表(每个文件中的 PRODUCT 一个)
大型 STEP 文件(> 100 MB)可能需要数秒到数十秒进行解析。
参见: import_step_from_string 从内存字符串导入(测试用), step_last_error 获取错误码
从字符串导入 STEP(用于测试和嵌入式场景)
[[nodiscard]] std::vector<BrepModel> import_step_from_string(const std::string& step_data)
| 参数 | 说明 |
|---|---|
step_data |
完整的 STEP 文件内容(字符串形式) |
返回: B-Rep 体列表
参见: import_step 从文件导入
获取最近一次 STEP 导入的错误码
[[nodiscard]] StepError step_last_error()
返回: StepError 枚举值
参见: step_last_error_message 获取可读的错误描述
获取最近一次 STEP 导入的可读错误描述
[[nodiscard]] const std::string& step_last_error_message()
返回: 错误描述字符串(如 "Missing entity reference #42")
参见: step_last_error 获取枚举错误码
SDF隐式建模 (vde::sdf)
sdf_gradient.h
SDF 梯度计算(数值微分、解析梯度、链式法则)
SDF 的空间梯度(中心差分近似)
[[nodiscard]] inline Vector3D gradient(
| 参数 | 说明 |
|---|---|
f |
SDF 函数(接受 Point3D 参数) |
p |
求值点 |
h |
差分步长(默认 1e-6) |
返回: 梯度向量 ∇f(p)
步长太小会导致舍入误差主导,太大导致截断误差主导。
对于含不连续性的 SDF(如 sharp CSG),有限差分可能在边界产生错误梯度。
参见: evaluate_with_gradient 一次性获取值和梯度
前向模梯度结果: SDF 值 + 梯度
struct GradResult {
同时计算 SDF 值和梯度的便捷函数
[[nodiscard]] inline GradResult evaluate_with_gradient(
| 参数 | 说明 |
|---|---|
f |
SDF 函数 |
p |
求值点 |
h |
差分步长 |
返回: value + grad 结构
参见: gradient 仅计算梯度
球体 SDF 对半径的参数梯度 ∂f/∂r
[[nodiscard]] inline double sphere_radius_gradient(const Point3D& p, double radius, double h = 1e-6)
| 参数 | 说明 |
|---|---|
p |
采样点 |
radius |
球体半径 |
h |
差分步长(默认 1e-6) |
返回: ∂f/∂radius
对于球体,解析梯度为 -1(球面上),但此函数提供与实现无关的数值验证。
参见: sphere_param_grad 封装版本
长方体 SDF 对各轴半尺寸的参数梯度 ∂f/∂extent[i]
[[nodiscard]] inline double box_extent_gradient(const Point3D& p, const Point3D& extents,
| 参数 | 说明 |
|---|---|
p |
采样点 |
extents |
半边长 |
axis |
轴索引: 0=x, 1=y, 2=z |
h |
差分步长 |
返回: ∂f/∂extent[axis]
参见: box_param_grad 封装版本
圆环 SDF 对主半径的参数梯度 ∂f/∂major_r
[[nodiscard]] inline double torus_major_gradient(const Point3D& p, double major_r, double minor_r,
| 参数 | 说明 |
|---|---|
p |
采样点 |
major_r |
主半径 |
minor_r |
副半径 |
h |
差分步长 |
返回: 参数梯度
圆环 SDF 对副半径的参数梯度 ∂f/∂minor_r
[[nodiscard]] inline double torus_minor_gradient(const Point3D& p, double major_r, double minor_r,
返回: 参数梯度
圆柱 SDF 对高度的参数梯度 ∂f/∂height
[[nodiscard]] inline double cylinder_height_gradient(const Point3D& p, double radius, double height,
| 参数 | 说明 |
|---|---|
p |
采样点 |
radius |
圆柱半径 |
height |
圆柱高度 |
h |
差分步长 |
返回: 参数梯度
圆柱 SDF 对半径的参数梯度 ∂f/∂radius
[[nodiscard]] inline double cylinder_radius_gradient(const Point3D& p, double radius, double height,
返回: 参数梯度
球体 SDF 的解析梯度
[[nodiscard]] inline Vector3D sphere_gradient_analytic(const Point3D& p, double /*radius*/)
| 参数 | 说明 |
|---|---|
p |
采样点 |
radius |
球半径(当前未使用,保留以保持接口一致) |
返回: 解析梯度(单位向量)
在表面上 (|p| = radius),梯度即为外法向量。
长方体 SDF 的解析梯度
[[nodiscard]] inline Vector3D box_gradient_analytic(const Point3D& p, const Point3D& half_extents)
| 参数 | 说明 |
|---|---|
p |
采样点 |
half_extents |
半边长 |
返回: 解析梯度
圆环 SDF 的解析梯度
[[nodiscard]] inline Vector3D torus_gradient_analytic(const Point3D& p, double major_r, double minor_r)
| 参数 | 说明 |
|---|---|
p |
采样点 |
major_r |
主半径 |
minor_r |
副半径 |
返回: 解析梯度
无限圆柱(沿 Y 轴)的解析梯度
[[nodiscard]] inline Vector3D cylinder_gradient_analytic(const Point3D& p, double /*radius*/)
| 参数 | 说明 |
|---|---|
p |
采样点 |
radius |
圆柱半径(未使用,保留接口一致) |
返回: 解析梯度
平面的解析梯度
[[nodiscard]] inline Vector3D plane_gradient_analytic(const Vector3D& normal)
| 参数 | 说明 |
|---|---|
normal |
单位法向量 |
返回: 梯度(等于 normal)
这是最简单的解析梯度,因为平面 SDF 是线性的。
胶囊体 SDF 的解析梯度
[[nodiscard]] inline Vector3D capsule_gradient_analytic(const Point3D& p,
| 参数 | 说明 |
|---|---|
p |
采样点 |
a |
线段起点 |
b |
线段终点 |
radius |
扫掠球半径 |
返回: 解析梯度
并集操作后的梯度传递
[[nodiscard]] inline Vector3D chain_union(const Vector3D& grad_a, const Vector3D& grad_b,
| 参数 | 说明 |
|---|---|
grad_a |
子对象 A 的梯度 |
grad_b |
子对象 B 的梯度 |
d1 |
A 的 SDF 值 |
d2 |
B 的 SDF 值 |
返回: 合并后的梯度
参见: chain_smooth_union 避免不连续的平滑版本
交集操作后的梯度传递
[[nodiscard]] inline Vector3D chain_intersection(const Vector3D& grad_a, const Vector3D& grad_b,
返回: 合并后的梯度
差集操作后的梯度传递
[[nodiscard]] inline Vector3D chain_difference(const Vector3D& grad_a, const Vector3D& grad_b,
| 参数 | 说明 |
|---|---|
grad_a |
子对象 A 的梯度 |
grad_b |
子对象 B 的梯度 |
d1 |
f_A |
d2 |
f_B |
返回: 合并后的梯度
平滑并集操作的梯度传递(含完整链式法则)
[[nodiscard]] inline Vector3D chain_smooth_union(const Vector3D& grad_a, const Vector3D& grad_b,
| 参数 | 说明 |
|---|---|
grad_a |
子对象 A 的梯度 |
grad_b |
子对象 B 的梯度 |
d1 |
f_A |
d2 |
f_B |
k |
混合参数 |
返回: 平滑合并后的梯度
参见: op_smooth_union 对应的平滑并集 SDF 操作, chain_union 硬切换版本
平移变换后的梯度传递(梯度不变)
[[nodiscard]] inline GradResult chain_translate(const GradResult& child_result, const Point3D& /*offset*/)
| 参数 | 说明 |
|---|---|
child_result |
变换空间中的子对象求值结果 |
offset |
平移量(仅接口保留) |
返回: 相同梯度
绕 Y 轴旋转后的梯度传递
[[nodiscard]] inline GradResult chain_rotate(const GradResult& child_result, double angle_rad)
| 参数 | 说明 |
|---|---|
child_result |
旋转后坐标系中的子对象求值 |
angle_rad |
旋转角度 |
返回: 世界坐标系的梯度
参见: op_rotate 对应的域变形操作
非均匀缩放后的梯度传递
[[nodiscard]] inline GradResult chain_scale(const GradResult& child_result, const Point3D& factors)
| 参数 | 说明 |
|---|---|
child_result |
缩放后坐标系中的子对象求值 |
factors |
缩放因子 |
返回: 世界坐标系的梯度
缩放后梯度不再是单位长度,除非是均匀缩放。
扭曲变换后的梯度传递(含完整雅可比)
[[nodiscard]] inline GradResult chain_twist(const GradResult& child_result,
| 参数 | 说明 |
|---|---|
child_result |
扭曲空间中的子对象求值 |
amount |
单位高度的旋转量 |
p |
原始采样点 |
返回: 世界坐标系的梯度
参见: op_twist 对应的域变形操作, chain_rotate 不含 Y 依赖的简化旋转梯度传递
周期重复后的梯度传递(梯度不变)
[[nodiscard]] inline GradResult chain_repeat(const GradResult& child_result,
| 参数 | 说明 |
|---|---|
child_result |
中心晶格内的子对象求值 |
cell |
晶格尺寸(仅接口保留) |
p |
原始采样点(仅接口保留) |
返回: 相同梯度
参数梯度结构体
struct ParamGrad {
参见: sphere_param_grad, box_param_grad, cylinder_param_grad
球体所有参数的梯度(当前仅 radius 有意义)
[[nodiscard]] inline ParamGrad sphere_param_grad(const Point3D& p, double radius, double h = 1e-6)
| 参数 | 说明 |
|---|---|
p |
采样点 |
radius |
球体半径 |
h |
差分步长 |
返回: 参数梯度(仅 d_radius 非零)
参见: sphere_radius_gradient 底层数值差分
长方体所有参数的梯度
[[nodiscard]] inline ParamGrad box_param_grad(const Point3D& p, const Point3D& half_extents,
| 参数 | 说明 |
|---|---|
p |
采样点 |
half_extents |
半边长 |
h |
差分步长 |
返回: 参数梯度(d_extents 分量填充)
参见: box_extent_gradient 底层数值差分
圆柱所有参数的梯度
[[nodiscard]] inline ParamGrad cylinder_param_grad(const Point3D& p, double radius, double height,
| 参数 | 说明 |
|---|---|
p |
采样点 |
radius |
圆柱半径 |
height |
圆柱高度 |
h |
差分步长 |
返回: 参数梯度(d_radius, d_height 填充)
sdf_operations.h
SDF 布尔运算、修饰算子与域变形
布尔并集: A ∪ B
[[nodiscard]] inline double op_union(double d1, double d2) {
| 参数 | 说明 |
|---|---|
d1 |
第一个对象的 SDF 值 |
d2 |
第二个对象的 SDF 值 |
返回: 并集的 SDF 值
参见: op_smooth_union 带平滑过渡的并集, op_intersection 交集
布尔交集: A ∩ B
[[nodiscard]] inline double op_intersection(double d1, double d2) {
| 参数 | 说明 |
|---|---|
d1 |
第一个对象的 SDF 值 |
d2 |
第二个对象的 SDF 值 |
返回: 交集的 SDF 值
参见: op_smooth_intersection 带平滑过渡的交集
布尔差集: A \ B
[[nodiscard]] inline double op_difference(double d1, double d2) {
| 参数 | 说明 |
|---|---|
d1 |
被减对象 A 的 SDF 值 |
d2 |
减去对象 B 的 SDF 值 |
返回: 差集的 SDF 值
参见: op_smooth_difference 带平滑过渡的差集
平滑并集(带混合过渡)
[[nodiscard]] inline double op_smooth_union(double d1, double d2, double k) {
| 参数 | 说明 |
|---|---|
d1 |
第一个对象的 SDF 值 |
d2 |
第二个对象的 SDF 值 |
k |
混合强度参数(> 0 时平滑过渡;≤ 0 时退化为普通并集) |
返回: 平滑混合后的 SDF 值
多项式混合是函数 f(x)=x 在 [0,k] 区间的平滑近似。在 d1=d2 处,f 向下偏移 k/4。
参见: op_union 无平滑的标准并集, op_smooth_intersection 平滑交集, op_smooth_difference 平滑差集
平滑交集(带混合过渡)
[[nodiscard]] inline double op_smooth_intersection(double d1, double d2, double k) {
| 参数 | 说明 |
|---|---|
d1 |
第一个对象的 SDF 值 |
d2 |
第二个对象的 SDF 值 |
k |
混合强度参数 |
返回: 平滑混合后的 SDF 值
参见: op_intersection 无平滑的标准交集, op_smooth_union 平滑并集
平滑差集(带混合过渡)
[[nodiscard]] inline double op_smooth_difference(double d1, double d2, double k) {
| 参数 | 说明 |
|---|---|
d1 |
被减对象 A 的 SDF 值 |
d2 |
减去对象 B 的 SDF 值 |
k |
混合强度参数 |
返回: 平滑混合后的 SDF 值
参见: op_difference 无平滑的标准差集, op_smooth_union 平滑并集
圆角偏移: 将等值面向外扩展 r 单位
[[nodiscard]] inline double op_round(double d, double r) {
| 参数 | 说明 |
|---|---|
d |
SDF 值 |
r |
偏移距离(正值 = 膨胀,负值 = 收缩) |
返回: 偏移后的 SDF 值
参见: op_onion 壳层修饰, round_box 特例化的圆角立方体
洋葱皮/壳层修饰: 取绝对值后减去厚度
[[nodiscard]] inline double op_onion(double d, double thickness) {
| 参数 | 说明 |
|---|---|
d |
SDF 值 |
thickness |
壳层半厚度,必须 > 0 |
返回: 壳层的 SDF 值
参见: op_round 圆角偏移
无限重复(周期复制)
[[nodiscard]] inline Point3D op_repeat(const Point3D& p, const Point3D& cell) {
| 参数 | 说明 |
|---|---|
p |
原始采样点 |
cell |
晶格尺寸 (cx, cy, cz),各分量必须 > 0 才生效 |
返回: 映射到中心晶格内的点
边界处 SDF 可能不连续,需要确保各晶格间映射是连续的。
镜像对称(X=0 平面),可选偏移
[[nodiscard]] inline Point3D op_mirror_x(const Point3D& p, double offset = 0.0) {
| 参数 | 说明 |
|---|---|
p |
原始采样点 |
offset |
镜像平面沿 X 轴的偏移量(默认 0 = X=0 平面) |
返回: 映射到镜像半空间的点
参见: op_mirror_y YZ 平面镜像, op_mirror_z XY 平面镜像
镜像对称(Y=0 平面)
[[nodiscard]] inline Point3D op_mirror_y(const Point3D& p) {
| 参数 | 说明 |
|---|---|
p |
原始采样点 |
返回: 映射到上半空间的点
镜像对称(Z=0 平面)
[[nodiscard]] inline Point3D op_mirror_z(const Point3D& p) {
| 参数 | 说明 |
|---|---|
p |
原始采样点 |
返回: 映射到前半空间的点
空间平移(逆变换)
[[nodiscard]] inline Point3D op_translate(const Point3D& p, const Point3D& offset) {
| 参数 | 说明 |
|---|---|
p |
原始采样点 |
offset |
平移量(对象正向移动的方向) |
返回: 逆平移后的采样点
参见: op_rotate 旋转变换, op_scale 缩放变换
绕 Y 轴旋转(逆变换)
[[nodiscard]] inline Point3D op_rotate(const Point3D& p, double angle_rad) {
| 参数 | 说明 |
|---|---|
p |
原始采样点 |
angle_rad |
旋转角度(弧度),正值 = 逆时针(从上往下看) |
返回: 逆旋转后的采样点
参见: op_twist 绕 Y 轴的扭曲变换, op_bend 弯曲变换
非均匀缩放(逆变换)
[[nodiscard]] inline Point3D op_scale(const Point3D& p, const Point3D& s) {
| 参数 | 说明 |
|---|---|
p |
原始采样点 |
s |
各轴缩放因子 (sx, sy, sz),均必须 ≠ 0 |
返回: 缩放后的采样点
参见: op_translate 平移(等距变换), op_rotate 旋转(等距变换)
绕 Y 轴的扭曲变换
[[nodiscard]] inline Point3D op_twist(const Point3D& p, double amount) {
| 参数 | 说明 |
|---|---|
p |
原始采样点 |
amount |
单位高度上的旋转量(弧度/单位长度) |
返回: 扭曲后的采样点
参见: op_rotate 恒定角度旋转, op_bend 弯曲变换
弯曲变换(绕 Z 轴弯曲 XZ 平面)
[[nodiscard]] inline Point3D op_bend(const Point3D& p, double k) {
| 参数 | 说明 |
|---|---|
p |
原始采样点 |
k |
弯曲曲率参数(k 越大弯曲越剧烈) |
返回: 弯曲后的采样点
参见: op_cheap_bend 简化版弯曲(仅绕 X 轴), op_twist 扭曲变换
拉伸/压扁域变形(消除拉伸方向上的内部体积)
[[nodiscard]] inline Point3D op_elongate(const Point3D& p, const Point3D& h) {
| 参数 | 说明 |
|---|---|
p |
原始采样点 |
h |
各轴的拉伸阈值 (hx, hy, hz),均 ≥ 0 |
返回: 变形后的采样点
参见: op_repeat 周期重复
简化弯曲变换(绕 X 轴弯曲 YZ 平面)
[[nodiscard]] inline Point3D op_cheap_bend(const Point3D& p, double k) {
| 参数 | 说明 |
|---|---|
p |
原始采样点 |
k |
弯曲曲率参数 |
返回: 弯曲后的采样点
使用场景:不需要精确物理弯曲,仅需视觉效果时优先用此函数以节省计算。
参见: op_bend 完整弯曲变换
正弦波位移扰动
[[nodiscard]] inline double op_displace(double d, const Point3D& p,
| 参数 | 说明 |
|---|---|
d |
原始 SDF 值 |
p |
采样点(用于扰动计算) |
amplitude |
扰动幅值 |
frequency |
空间频率 |
返回: 扰动后的 SDF 值
sdf_optimize.h
基于梯度的 SDF 形状优化
优化结果
struct OptimizeResult {
损失函数类型
using LossFn = std::function<double(const std::function<double(const Point3D&)>&)>
参见: fit_to_point_cloud 使用该类型的内置实现
将参数化形状拟合到目标点云
[[nodiscard]] OptimizeResult fit_to_point_cloud(
| 参数 | 说明 |
|---|---|
initial |
初始形状(sphere, box, cylinder 等),其参数将被优化 |
target_points |
目标点云(表面采样点) |
learning_rate |
梯度下降步长(默认 0.01) |
max_iterations |
最大迭代次数(默认 100) |
返回: 优化结果(含优化后的形状和收敛信息)
损失函数为 L = mean(|sdf(p_i)|),即点到表面的平均绝对距离。
initial 的共享子节点不会被复制——返回的 optimize_shape 共享未修改的子树。
参见: fit_surface_to_points 类似但仅最小化 |sdf| 而非有符号距离, fit_to_sdf 拟合到另一个 SDF
将形状表面移动到目标采样点
[[nodiscard]] OptimizeResult fit_surface_to_points(
| 参数 | 说明 |
|---|---|
initial |
初始形状 |
surface_points |
目标表面点 |
learning_rate |
学习率 |
max_iterations |
最大迭代次数 |
返回: 优化结果
参见: fit_to_point_cloud 更通用的点云拟合(可包含内部/外部点)
拟合一个 SDF 形状以匹配另一个目标 SDF
[[nodiscard]] OptimizeResult fit_to_sdf(
| 参数 | 说明 |
|---|---|
source |
被优化的参数化形状 |
target_sdf |
目标 SDF 函数 |
bmin |
采样网格最小角点 |
bmax |
采样网格最大角点 |
grid_resolution |
采样网格分辨率(默认 16) |
learning_rate |
学习率 |
max_iterations |
最大迭代次数 |
返回: 优化结果
参见: fit_to_point_cloud 拟合到点云
通过平移解决两个形状之间的穿透
[[nodiscard]] bool resolve_collision(
| 参数 | 说明 |
|---|---|
shape_a |
形状 A(原地修改) |
shape_b |
形状 B(原地修改) |
step_size |
每次迭代的平移步长(默认 0.1) |
max_iterations |
最大迭代次数(默认 50) |
返回: true 如果碰撞被成功解决;false 如果在迭代次数内未能解决
参见: penetration_depth 估算穿透深度
估算两个形状之间的最小穿透距离
[[nodiscard]] double penetration_depth(
| 参数 | 说明 |
|---|---|
shape_a |
形状 A |
shape_b |
形状 B |
bmin |
公共包围盒最小角点 |
bmax |
公共包围盒最大角点 |
samples |
蒙地卡罗采样数(默认 1000) |
返回: 最大穿透深度(负值表示不重叠时的最小间距)
参见: resolve_collision 解决穿透
计算形状表面上点的可及性分数
[[nodiscard]] double accessibility(
| 参数 | 说明 |
|---|---|
shape |
SDF 形状 |
p |
表面点(应满足 |
direction |
接近方向 |
hemisphere_samples |
半球采样光线数量(默认 64) |
返回: 可及性分数 [0, 1]
采样数越多越精确,但线性增加计算量。
参见: find_accessible_point 找到最大可及性的表面点
找到给定接近方向下具有最大可及性的表面点
[[nodiscard]] Point3D find_accessible_point(
| 参数 | 说明 |
|---|---|
shape |
SDF 形状 |
approach_dir |
接近方向(如工具接近方向) |
bmin |
搜索包围盒最小角点 |
bmax |
搜索包围盒最大角点 |
grid_res |
搜索网格分辨率(默认 32) |
返回: 最大可及性的表面点
参见: accessibility 单点可及性计算
检测形状在给定方向上的反射对称性
[[nodiscard]] double symmetry_score(
| 参数 | 说明 |
|---|---|
shape |
SDF 形状 |
bmin |
包围盒最小角点 |
bmax |
包围盒最大角点 |
plane_normal |
反射平面的法向量 |
plane_offset |
反射平面的偏移量(沿法向量方向,默认 0) |
samples |
采样点对数(默认 1000) |
返回: 对称性分数 [0, 1](0 = 完全不对称,1 = 完美对称)
参见: find_symmetry_plane 自动寻找最佳对称平面
对称检测结果
struct SymmetryResult {
自动找到形状的最佳反射对称平面
[[nodiscard]] SymmetryResult find_symmetry_plane(
| 参数 | 说明 |
|---|---|
shape |
SDF 形状 |
bmin |
包围盒最小角点 |
bmax |
包围盒最大角点 |
samples |
每个候选方向的采样数(默认 1000) |
返回: 最佳对称平面及其分数
参见: symmetry_score 给定方向的对称性检测
通过蒙地卡罗法估算隐式形状的体积
[[nodiscard]] double estimate_volume(
| 参数 | 说明 |
|---|---|
shape |
SDF 形状 |
bmin |
采样包围盒最小角点 |
bmax |
采样包围盒最大角点 |
samples |
蒙地卡罗采样数(默认 10000) |
返回: 近似体积
精度与 √samples 成正比。10000 采样 ≈ 1% 相对误差。
包围盒应尽可能紧致以减小方差。
参见: center_of_mass 蒙地卡罗质心估算
通过蒙地卡罗法估算形状的质心
[[nodiscard]] Point3D center_of_mass(
| 参数 | 说明 |
|---|---|
shape |
SDF 形状 |
bmin |
采样包围盒最小角点 |
bmax |
采样包围盒最大角点 |
samples |
蒙地卡罗采样数(默认 10000) |
返回: 近似质心坐标
参见: estimate_volume 体积估算
SDF 树中可变参数的引用
struct ParamRef {
从叶节点收集所有可变数值参数
[[nodiscard]] std::vector<ParamRef> collect_params(SdfNodePtr& root)
| 参数 | 说明 |
|---|---|
root |
SDF 树根节点(可写引用,因为参数将被原地修改) |
返回: 可变参数引用列表
参见: numerical_gradient 计算损失对参数的数值梯度
计算标量损失对收集到的参数的数值梯度
[[nodiscard]] std::vector<double> numerical_gradient(
| 参数 | 说明 |
|---|---|
params |
collect_params() 返回的参数引用列表 |
loss_fn |
损失函数(无参数的可调用对象) |
eps |
差分步长(默认 1e-6) |
返回: 梯度向量 grad_loss,grad_loss[i] = ∂loss / ∂params[i].value
参见: collect_params 收集参数, GradientDescent 梯度下降优化器
固定学习率的简单梯度下降优化器
构造优化器
explicit GradientDescent(double lr) : lr_(lr) {}
| 参数 | 说明 |
|---|---|
lr |
学习率(步长因子) |
执行单步梯度下降
double step(std::vector<double>& params,
| 参数 | 说明 |
|---|---|
params |
参数向量(原地修改) |
grad_fn |
梯度计算函数,签名为 |
返回: 当前损失值
设置学习率
void set_learning_rate(double lr) { lr_ = lr; }
获取学习率
[[nodiscard]] double learning_rate() const { return lr_; }
获取当前迭代次数
[[nodiscard]] int iteration() const { return iteration_; }
sdf_primitives.h
有符号距离函数(SDF)基础图元
所有图元假设未施加变换——坐标系原点即图元中心/基点。
球体的 SDF
[[nodiscard]] inline double sphere(const Point3D& p, double radius) {
| 参数 | 说明 |
|---|---|
p |
采样点(三维坐标) |
radius |
球半径,必须 > 0 |
返回: 有符号距离
球位于原点。如需其他位置,使用 op_translate 对采样点做反向平移。
参见: ellipsoid 各轴半径不同的椭球, cylinder 沿 Y 轴的圆柱
轴对齐立方体的 SDF
[[nodiscard]] inline double box(const Point3D& p, const Point3D& half_extents) {
| 参数 | 说明 |
|---|---|
p |
采样点 |
half_extents |
半边长 (hx, hy, hz),均必须 ≥ 0 |
返回: 有符号距离
参见: round_box 带圆角的盒子, wedge 对角切割的半盒子
圆角立方体的 SDF
[[nodiscard]] inline double round_box(const Point3D& p, const Point3D& half_extents, double r) {
| 参数 | 说明 |
|---|---|
p |
采样点 |
half_extents |
半边长 (hx, hy, hz) |
r |
圆角半径,必须 < min(half_extents) 否则整体形态改变 |
返回: 有符号距离
参见: box 无圆角的长方体, op_round 对任意 SDF 做圆角偏移
圆环面的 SDF
[[nodiscard]] inline double torus(const Point3D& p, double major_radius, double minor_radius) {
| 参数 | 说明 |
|---|---|
p |
采样点 |
major_radius |
主半径(环的半径),必须 > 0 |
minor_radius |
副半径(管的粗细),必须 > 0 |
返回: 有符号距离
参见: link 双环连接体(两个并行圆环的组合)
胶囊体的 SDF
[[nodiscard]] inline double capsule(const Point3D& p, const Point3D& a, const Point3D& b, double radius) {
| 参数 | 说明 |
|---|---|
p |
采样点 |
a |
线段起点 |
b |
线段终点 |
radius |
扫掠球半径,必须 > 0 |
返回: 有符号距离
参见: cylinder 两端平头的圆柱(非球形端盖)
带平端盖的圆柱体 SDF
[[nodiscard]] inline double cylinder(const Point3D& p, double radius, double height) {
| 参数 | 说明 |
|---|---|
p |
采样点 |
radius |
圆柱截面半径,必须 > 0 |
height |
圆柱总高度(从 -h/2 到 +h/2),必须 > 0 |
返回: 有符号距离
参见: capsule 两端球形端盖的圆柱, infinite_cylinder 无限长圆柱, cone 圆锥台
平面的 SDF
[[nodiscard]] inline double plane(const Point3D& p, const Vector3D& normal, double offset) {
| 参数 | 说明 |
|---|---|
p |
采样点 |
normal |
单位法向量(必须已归一化) |
offset |
沿法向量正方向的偏移量 |
返回: 有符号距离
参见: wedge 两个平面+盒子的组合(对角切割)
椭球体的 SDF(有界梯度近似)
[[nodiscard]] inline double ellipsoid(const Point3D& p, const Point3D& radii) {
| 参数 | 说明 |
|---|---|
p |
采样点 |
radii |
半轴长 (rx, ry, rz),均必须 > 0 |
返回: 有符号距离(近似)
当三个半径相等时退化为球体,此时使用 sphere() 更精确高效。
当点到原点距离远大于最大半径时,近似精度下降。
参见: sphere 精确球体(rx=ry=rz 时的特例)
正六棱柱的 SDF
[[nodiscard]] inline double hex_prism(const Point3D& p, double radius, double height) {
| 参数 | 说明 |
|---|---|
p |
采样点 |
radius |
六边形外接圆半径(中心到顶点),必须 > 0 |
height |
挤出总高度(±h/2 沿 Y 轴),必须 > 0 |
返回: 有符号距离
参见: extrusion_bounded 通用 bounded extrusion 算子
无限长圆柱的 SDF
[[nodiscard]] inline double infinite_cylinder(const Point3D& p, const Vector3D& axis, double radius) {
| 参数 | 说明 |
|---|---|
p |
采样点 |
axis |
圆柱轴线方向(必须归一化, |
radius |
截面半径,必须 > 0 |
返回: 有符号距离
参见: cylinder 有限长圆柱(带平端盖)
楔形体的 SDF
[[nodiscard]] inline double wedge(const Point3D& p, double w, double h, double d) {
| 参数 | 说明 |
|---|---|
p |
采样点 |
w |
宽度(X 方向) |
h |
高度(Y 方向) |
d |
深度(Z 方向) |
返回: 有符号距离
参见: box 完整立方体, plane 独立平面 SDF
二维 SDF 沿 Z 轴的无限挤出
[[nodiscard]] inline double extrusion(const Point3D& /*p*/, double sdf_2d) {
| 参数 | 说明 |
|---|---|
p |
三维采样点(仅 x,y 分量被隐式使用——通过 sdf_2d 参数间接) |
sdf_2d |
预计算的二维 SDF 值(在 (p.x, p.y) 处求值) |
返回: 三维有符号距离(等于 sdf_2d)
p 参数仅保持接口一致,实际不影响结果。
对于有限长度的挤出,使用 extrusion_bounded()。
参见: extrusion_bounded 有限长度的挤出, revolution 二维轮廓绕 Y 轴旋转
二维 SDF 的有限长度挤出
[[nodiscard]] inline double extrusion_bounded(const Point3D& p, double sdf_2d, double half_height) {
| 参数 | 说明 |
|---|---|
p |
三维采样点 |
sdf_2d |
预计算的二维 SDF 值(在 (p.x, p.y) 处求值) |
half_height |
挤出半高度(Z 方向),必须 ≥ 0 |
返回: 有符号距离
参见: extrusion 无限挤出, hex_prism 六棱柱(特例化 bounded extrusion 实现)
二维轮廓绕 Y 轴的旋转体 SDF
[[nodiscard]] inline double revolution(const Point3D& /*p*/, double sdf_2d, double /*offset*/) {
| 参数 | 说明 |
|---|---|
p |
三维采样点(接口保留,不直接使用) |
sdf_2d |
预计算的二维 SDF(在 (√(pₓ²+p𝓏²)-offset, p.y) 处求值) |
offset |
径向偏移量(从 Y 轴的起点距离) |
返回: 有符号距离
参见: torus 圆环(revolution 的特例:截面为圆)
圆锥台的 SDF(非内联实现)
[[nodiscard]] double cone(const Point3D& p, double angle_rad, double height)
| 参数 | 说明 |
|---|---|
p |
采样点 |
angle_rad |
半锥角(弧度),决定底面半径 |
height |
锥体总高度,必须 > 0 |
返回: 有符号距离
参见: cylinder 半锥角为 0 时的退化情况, infinite_cone 无限圆锥
三角棱柱的 SDF(非内联实现)
[[nodiscard]] double triangular_prism(const Point3D& p, const Point3D& a, const Point3D& b,
| 参数 | 说明 |
|---|---|
p |
采样点 |
a |
三角形顶点 A(XY 平面内) |
b |
三角形顶点 B(XY 平面内) |
c |
三角形顶点 C(XY 平面内) |
height |
挤出总高度(沿 Z 轴),必须 > 0 |
返回: 有符号距离
参见: wedge 直角三角形楔形体
双环链接体的 SDF(非内联实现)
[[nodiscard]] double link(const Point3D& p, double length, double major_r, double minor_r)
| 参数 | 说明 |
|---|---|
p |
采样点 |
length |
两个环心沿 X 轴的距离 |
major_r |
每个环的主半径(环的半径) |
minor_r |
每个环的管半径(截面的粗细) |
返回: 有符号距离
参见: torus 单个圆环
无限圆锥的 SDF(非内联实现)
[[nodiscard]] double infinite_cone(const Point3D& p, const Point3D& apex,
| 参数 | 说明 |
|---|---|
p |
采样点 |
apex |
锥顶位置 |
axis |
锥轴方向(必须归一化),锥体沿此方向扩展 |
angle_rad |
半锥角(弧度) |
返回: 有符号距离
参见: cone 有限高圆锥台
sdf_to_mesh.h
SDF 到三角网格的转换
将 SDF 表达式树转换为三角网格
[[nodiscard]] mesh::MCMesh sdf_to_mesh(const SdfNodePtr& root,
| 参数 | 说明 |
|---|---|
root |
SDF 表达式树的根节点 |
resolution |
每轴的网格分辨率(例如 64 表示 64³ 体素网格) |
iso_level |
等值面水平(0.0 = 隐式表面) |
返回: 包含顶点和三角形索引的 MCMesh
分辨率推荐为 2 的幂(32, 64, 128, 256)以获得最佳缓存性能。
对于大尺寸但细节少的几何体,使用较低的 resolution 即可获得光滑结果。
参见: sdf_to_mesh_lambda Lambda 版本的 SDF 转网格(Python 友好), estimate_bbox 包围盒估算
将 Lambda SDF 函数转换为三角网格
[[nodiscard]] mesh::MCMesh sdf_to_mesh_lambda(
| 参数 | 说明 |
|---|---|
f |
SDF 函数,签名为 double(double x, double y, double z) → 有符号距离 |
bmin |
采样包围盒最小角点 |
bmax |
采样包围盒最大角点 |
resolution |
每轴分辨率 |
iso_level |
等值面水平(默认 0.0) |
返回: MCMesh 三角网格
参见: sdf_to_mesh 基于 SDF 树的网格转换
sdf_torch.h
SDF 批量求值与梯度计算(CPU 后端)
在批处理模式下求值 SDF
void evaluate_batch(const SdfNodePtr& root,
| 参数 | 说明 |
|---|---|
root |
SDF 表达式树根节点 |
points |
点数组,length = 3·n,x,y,z 交替存储 |
n |
点数 |
distances |
输出数组,length = n,写入有符号距离值 |
参见: evaluate 单点求值, gradient_batch 批量梯度计算
在批处理模式下求值 SDF 的空间梯度
void gradient_batch(const SdfNodePtr& root,
| 参数 | 说明 |
|---|---|
root |
SDF 表达式树根节点 |
points |
点数组,length = 3·n |
n |
点数 |
gradients |
输出数组,length = 3·n,x,y,z 梯度分量交替存储 |
参见: evaluate_batch 批量距离求值, evaluate_with_gradient_batch 同时获取距离和梯度(减少重复采样)
一次遍历同时求值 SDF 值和梯度
void evaluate_with_gradient_batch(const SdfNodePtr& root,
| 参数 | 说明 |
|---|---|
root |
SDF 表达式树根节点 |
points |
点数组,length = 3·n |
n |
点数 |
distances |
输出距离数组,length = n |
gradients |
输出梯度数组,length = 3·n |
对于大量点的场景(n > 1000),推荐使用本函数以获得 ~2× 速度提升。
参见: evaluate_batch 仅求距离, gradient_batch 仅求梯度
sdf_tree.h
SDF 表达式树结构
CSG 树的所有节点类型
enum class SdfOp : uint8_t {
参见: SdfParams 对应的参数结构
SDF 节点参数联合体
struct SdfParams {
SDF 表达式树节点
树是不可变的——节点创建后 op 和子节点关系不变,但 params 可被外部修改以支持参数优化。
创建球体节点
static SdfNodePtr sphere(double r)
创建轴对齐长方体节点
static SdfNodePtr box(const Point3D& half_extents)
创建圆角长方体节点
static SdfNodePtr round_box(const Point3D& half_extents, double r)
创建圆柱体节点
static SdfNodePtr cylinder(double r, double h)
创建圆环体节点
static SdfNodePtr torus(double major_r, double minor_r)
创建胶囊体节点
static SdfNodePtr capsule(const Point3D& a, const Point3D& b, double r)
创建圆锥台节点
static SdfNodePtr cone(double angle_rad, double h)
创建平面节点
static SdfNodePtr plane(const Vector3D& normal, double offset)
创建椭球体节点
static SdfNodePtr ellipsoid(const Point3D& radii)
创建三角棱柱节点
static SdfNodePtr triangular_prism(double h)
创建六棱柱节点
static SdfNodePtr hex_prism(double h)
创建双环链接节点
static SdfNodePtr link(double r, double length, double thickness)
创建楔形体节点
static SdfNodePtr wedge(const Point3D& extents)
创建并集节点: A ∪ B
static SdfNodePtr op_union(SdfNodePtr a, SdfNodePtr b)
创建交集节点: A ∩ B
static SdfNodePtr op_intersection(SdfNodePtr a, SdfNodePtr b)
创建差集节点: A \ B
static SdfNodePtr op_difference(SdfNodePtr a, SdfNodePtr b)
创建平滑并集节点
static SdfNodePtr smooth_union(SdfNodePtr a, SdfNodePtr b, double k)
创建平滑交集节点
static SdfNodePtr smooth_intersection(SdfNodePtr a, SdfNodePtr b, double k)
创建平滑差集节点
static SdfNodePtr smooth_difference(SdfNodePtr a, SdfNodePtr b, double k)
创建圆角偏移节点
static SdfNodePtr round(SdfNodePtr child, double r)
创建壳层修饰节点
static SdfNodePtr onion(SdfNodePtr child, double thickness)
创建周期重复节点
static SdfNodePtr repeat(SdfNodePtr child, const Point3D& cell)
创建 X 镜像节点
static SdfNodePtr mirror_x(SdfNodePtr child)
创建 Y 镜像节点
static SdfNodePtr mirror_y(SdfNodePtr child)
创建 Z 镜像节点
static SdfNodePtr mirror_z(SdfNodePtr child)
创建平移节点
static SdfNodePtr translate(SdfNodePtr child, const Point3D& offset)
创建旋转节点(绕 Y 轴)
static SdfNodePtr rotate(SdfNodePtr child, double angle_rad)
创建缩放节点
static SdfNodePtr scale(SdfNodePtr child, const Point3D& factors)
创建扭曲节点
static SdfNodePtr twist(SdfNodePtr child, double amount)
创建弯曲节点
static SdfNodePtr bend(SdfNodePtr child, double amount)
创建拉伸节点
static SdfNodePtr elongate(SdfNodePtr child, const Point3D& h)
创建简化弯曲节点
static SdfNodePtr cheap_bend(SdfNodePtr child, double amount)
创建位移扰动节点
static SdfNodePtr displace(SdfNodePtr child, double amplitude, double frequency)
前序遍历所有节点
template <typename Fn>
前序遍历(const 版本)
template <typename Fn>
参见: visit(Fn&&)
构造 SDF 节点
explicit SdfNode(SdfOp o) : op(o) {}
| 参数 | 说明 |
|---|---|
o |
操作类型 |
在空间点 p 处求值 SDF 树
[[nodiscard]] double evaluate(const SdfNodePtr& root, const Point3D& p)
| 参数 | 说明 |
|---|---|
root |
SDF 表达式树的根节点 |
p |
世界空间中的采样点 |
返回: 有符号距离(负 = 内部,零 = 表面,正 = 外部)
参见: estimate_bounds 估计树的包围盒
估算 SDF 树的包围半尺寸
[[nodiscard]] Point3D estimate_bounds(const SdfNodePtr& root, double margin = 1.0)
| 参数 | 说明 |
|---|---|
root |
SDF 树的根节点 |
margin |
额外安全边距(默认 1.0) |
返回: 包围半边长 (hx, hy, hz)
变形节点(旋转/弯曲/扭曲等)会使包围盒放大,以保守估计覆盖变形后区域。
参见: estimate_bbox 完整 AABB 结果
SDF 树的包围盒(AABB)
struct SdfBBox {
估算 SDF 树的完整轴对齐包围盒
[[nodiscard]] SdfBBox estimate_bbox(const SdfNodePtr& root, double margin = 1.0)
| 参数 | 说明 |
|---|---|
root |
SDF 树的根节点 |
margin |
额外安全边距 |
返回: AABB 包围盒
草图约束 (vde::sketch)
constraint_solver.h
草图点元素
struct SketchPoint {
草图线段元素
struct SketchLine {
草图圆元素
struct SketchCircle {
约束类型枚举
enum class ConstraintType {
约束实例
struct Constraint {
求解器返回结果
struct SolverResult {
二维几何约束求解器
添加自由点
int add_point(double x, double y, bool fixed = false)
| 参数 | 说明 |
|---|---|
x |
X 坐标 |
y |
Y 坐标 |
fixed |
是否固定(true 则排除变量) |
返回: 点 ID
添加线段
int add_line(int p0, int p1)
| 参数 | 说明 |
|---|---|
p0 |
起点 ID |
p1 |
终点 ID |
返回: 线段 ID
添加圆
int add_circle(int center, double radius)
| 参数 | 说明 |
|---|---|
center |
圆心点 ID |
radius |
半径 |
返回: 圆 ID
添加约束
void add_constraint(ConstraintType type, const std::vector<int>& elements, double val = 0.0)
| 参数 | 说明 |
|---|---|
type |
约束类型 |
elements |
约束涉及的元素 ID 列表 |
val |
约束值(距离、角度等),默认 0 |
不同类型 elements 的语义:
标记点为固定(硬约束)
void fix_point(int pid) {
| 参数 | 说明 |
|---|---|
pid |
点 ID |
固定点不参与变量优化,从自由度中排除
执行约束求解
[[nodiscard]] SolverResult solve(int max_iter = 100, double tol = 1e-8)
| 参数 | 说明 |
|---|---|
max_iter |
最大 Gauss-Newton 迭代次数,默认 100 |
tol |
收敛容差(梯度范数 < tol 时停止),默认 1e-8 |
返回: SolverResult 求解结果
收敛判断:||J^T r|| < tol
欠约束时(DOF > 0)解不唯一;过约束时(DOF < 0)为最小二乘解
计算自由度
[[nodiscard]] int degrees_of_freedom() const
返回: DOF = 2·N_free - Σ(约束方程数)
DOF < 0 时系统过约束,求解器仍然工作但解非精确满足所有约束
当前点集访问
[[nodiscard]] const std::vector<SketchPoint>& points() const { return points_; }
返回: SketchPoint 数组只读引用
查询点坐标
[[nodiscard]] Point2D get_point(int id) const
| 参数 | 说明 |
|---|---|
id |
点 ID |
返回: Point2D 当前坐标
将求解器变量向量同步回 points_(用于 Jacobian 数值计算)
void sync_from_vars(const double* vars, int nv)
| 参数 | 说明 |
|---|---|
vars |
变量数组(长度为 2·N_free) |
nv |
变量数 |
评估单个约束的残差值
double eval_constraint(const Constraint& c) const
| 参数 | 说明 |
|---|---|
c |
约束 |
返回: 残差(方程 → 0 表示约束满足)
计算单个约束的方程数
int count_equations(const Constraint& c) const
| 参数 | 说明 |
|---|---|
c |
约束 |
返回: Coincident/Fixed → 2,其余 → 1
填充 Jacobian 矩阵中对应约束 ci 的行
void fill_jacobian_rows(const Constraint& c, int ci,
| 参数 | 说明 |
|---|---|
c |
约束 |
ci |
约束索引 |
row_map |
方程行映射 |
J_data |
Jacobian 矩阵数据(行优先) |
nv |
变量数 |
stride |
行跨度 |
C API (vde::capi)
vde_capi.h
ViewDesignEngine C API — 跨语言边界接口
extern "C" {
参见: vde.h C++ 等价接口
引擎上下文句柄 — 管理错误状态和内部资源
typedef struct VdeContext* VdeHandle
三角网格句柄 — 顶点+面集合
typedef struct VdeMesh* VdeMeshHandle
参数曲线句柄 — NURBS 曲线
typedef struct VdeCurve* VdeCurveHandle
约束求解器句柄 — 二维草图约束
typedef struct VdeSolver* VdeSolverHandle
B-Rep 实体句柄 — 边界表示模型
typedef struct VdeBody* VdeBodyHandle
创建 ViewDesignEngine 上下文
VdeHandle vde_create(void)
返回: 新的引擎句柄,不需要时通过 vde_destroy() 释放
参见: vde_destroy 释放上下文
销毁引擎上下文
void vde_destroy(VdeHandle ctx)
| 参数 | 说明 |
|---|---|
ctx |
引擎上下文句柄 |
参见: vde_create
获取引擎版本字符串
const char* vde_version(void)
返回: 语义版本号字符串(如 "0.5.0"),静态生命周期,无需释放
获取最后一次操作的错误描述
const char* vde_last_error(VdeHandle ctx)
| 参数 | 说明 |
|---|---|
ctx |
引擎上下文句柄 |
返回: 错误描述字符串(上下文的内部缓冲区,静态生命周期)
每次新的失败操作会覆盖此描述。成功操作不会清除它。
从文件加载三角网格
VdeMeshHandle vde_load_mesh(VdeHandle ctx, const char* path)
| 参数 | 说明 |
|---|---|
ctx |
引擎上下文句柄 |
path |
文件路径(UTF-8 编码) |
返回: 网格句柄,失败时返回 NULL(通过 vde_last_error() 获取原因)
参见: vde_mesh_free 释放网格, vde_save_mesh 保存网格
将三角网格保存为文件
int vde_save_mesh(VdeHandle ctx, VdeMeshHandle mesh, const char* path, const char* format)
| 参数 | 说明 |
|---|---|
ctx |
引擎上下文句柄 |
mesh |
网格句柄 |
path |
输出文件路径 |
format |
输出格式(当前仅 "obj" 有效) |
返回: 成功返回 1,失败返回 0
参见: vde_load_mesh 加载网格
获取网格的顶点数量
size_t vde_mesh_num_vertices(VdeMeshHandle mesh)
| 参数 | 说明 |
|---|---|
mesh |
网格句柄(必须有效且非 NULL) |
返回: 顶点数
参见: vde_mesh_num_faces 面数
获取网格的三角面数量
size_t vde_mesh_num_faces(VdeMeshHandle mesh)
| 参数 | 说明 |
|---|---|
mesh |
网格句柄 |
返回: 面数
参见: vde_mesh_num_vertices 顶点数
获取指定索引的顶点坐标
void vde_mesh_get_vertex(VdeMeshHandle mesh, size_t idx,
| 参数 | 说明 |
|---|---|
mesh |
网格句柄 |
idx |
顶点索引 [0, num_vertices) |
out_x |
[out] 顶点 X 坐标 |
out_y |
[out] 顶点 Y 坐标 |
out_z |
[out] 顶点 Z 坐标 |
获取网格的轴对齐包围盒
void vde_mesh_get_bounds(VdeMeshHandle mesh,
| 参数 | 说明 |
|---|---|
mesh |
网格句柄 |
out_min_x |
[out] 最小 X 坐标 |
out_min_y |
[out] 最小 Y 坐标 |
out_min_z |
[out] 最小 Z 坐标 |
out_max_x |
[out] 最大 X 坐标 |
out_max_y |
[out] 最大 Y 坐标 |
out_max_z |
[out] 最大 Z 坐标 |
释放网格句柄及其资源
void vde_mesh_free(VdeMeshHandle mesh)
| 参数 | 说明 |
|---|---|
mesh |
网格句柄 |
网格简化
VdeMeshHandle vde_mesh_simplify(VdeHandle ctx, VdeMeshHandle mesh, double target_ratio)
| 参数 | 说明 |
|---|---|
ctx |
引擎上下文句柄 |
mesh |
输入网格句柄(不修改输入) |
target_ratio |
目标简化比率 [0, 1](0 = 不变,1 = 最大简化) |
返回: 简化后的新网格句柄
参见: vde_mesh_smooth 网格平滑
网格平滑(Laplacian 或 Taubin 平滑)
VdeMeshHandle vde_mesh_smooth(VdeHandle ctx, VdeMeshHandle mesh, int iterations)
| 参数 | 说明 |
|---|---|
ctx |
引擎上下文句柄 |
mesh |
输入网格句柄 |
iterations |
平滑迭代次数 |
返回: 平滑后的新网格句柄
参见: vde_mesh_simplify 网格简化
网格布尔运算
VdeMeshHandle vde_mesh_boolean(VdeHandle ctx, VdeMeshHandle a, VdeMeshHandle b, int operation)
| 参数 | 说明 |
|---|---|
ctx |
引擎上下文句柄 |
a |
网格 A |
b |
网格 B |
operation |
布尔操作类型: 0 = 并集, 1 = 交集, 2 = 差集 (A \ B) |
返回: 布尔结果的新网格句柄
创建 Bézier 曲线
VdeCurveHandle vde_curve_create_bezier(VdeHandle ctx, const double* control_points,
| 参数 | 说明 |
|---|---|
ctx |
引擎上下文句柄 |
control_points |
控制点数组,每 3 个 double 表示一个三维点 (x,y,z) |
num_points |
控制点数量(次数 = num_points - 1) |
dim |
维度(固定为 3) |
返回: 曲线句柄
参见: vde_curve_evaluate 求值, vde_curve_free 释放
在参数 t 处求值曲线
void vde_curve_evaluate(VdeCurveHandle curve, double t,
| 参数 | 说明 |
|---|---|
curve |
曲线句柄 |
t |
参数值 [0, 1] |
out_x |
[out] 曲线上点的 X 坐标 |
out_y |
[out] 曲线上点的 Y 坐标 |
out_z |
[out] 曲线上点的 Z 坐标 |
获取曲线的次数
int vde_curve_degree(VdeCurveHandle curve)
| 参数 | 说明 |
|---|---|
curve |
曲线句柄 |
返回: 曲线次数
释放曲线句柄
void vde_curve_free(VdeCurveHandle curve)
| 参数 | 说明 |
|---|---|
curve |
曲线句柄 |
两球体碰撞检测(GJK 算法)
int vde_collision_gjk_spheres(VdeHandle ctx,
| 参数 | 说明 |
|---|---|
ctx |
引擎上下文句柄 |
cx1, |
cy1, cz1 第一个球体的球心坐标 |
r1 |
第一个球体的半径 |
cx2, |
cy2, cz2 第二个球体的球心坐标 |
r2 |
第二个球体的半径 |
返回: 碰撞返回 1,不碰撞返回 0
参见: vde_collision_ray_mesh 射线-网格相交
射线与网格的最近交点查询
int vde_collision_ray_mesh(VdeHandle ctx, VdeMeshHandle mesh,
| 参数 | 说明 |
|---|---|
ctx |
引擎上下文句柄 |
mesh |
目标网格句柄 |
ox, |
oy, oz 射线起点 |
dx, |
dy, dz 射线方向(无需归一化) |
out_t |
[out] 交点参数 t(沿射线的距离) |
out_x, |
out_y, out_z [out] 交点坐标 |
返回: 命中返回 1,未命中返回 0
参见: vde_collision_gjk_spheres GJK 球体碰撞
创建二维约束求解器
VdeSolverHandle vde_solver_create(void)
返回: 求解器句柄
参见: vde_solver_free 释放
向求解器添加点
int vde_solver_add_point(VdeSolverHandle solver, double x, double y, int fixed)
| 参数 | 说明 |
|---|---|
solver |
求解器句柄 |
x |
初始 X 坐标 |
y |
初始 Y 坐标 |
fixed |
固定点标记(1 = 固定不移动) |
返回: 点的 ID(用于后续约束引用)
参见: vde_solver_add_line 添加线段
向求解器添加线段(由两个点定义)
int vde_solver_add_line(VdeSolverHandle solver, int p0, int p1)
| 参数 | 说明 |
|---|---|
solver |
求解器句柄 |
p0 |
起点 ID |
p1 |
终点 ID |
返回: 线段的 ID
参见: vde_solver_add_point 添加点, vde_solver_add_horizontal 添加水平约束, vde_solver_add_vertical 添加垂直约束
添加距离约束(两点之间)
void vde_solver_add_distance_constraint(VdeSolverHandle solver, int p0, int p1, double d)
| 参数 | 说明 |
|---|---|
solver |
求解器句柄 |
p0 |
第一个点的 ID |
p1 |
第二个点的 ID |
d |
目标距离(必须 > 0) |
参见: vde_solver_add_horizontal 水平约束
添加水平约束(线段水平)
void vde_solver_add_horizontal(VdeSolverHandle solver, int line_id)
| 参数 | 说明 |
|---|---|
solver |
求解器句柄 |
line_id |
线段 ID |
参见: vde_solver_add_vertical 垂直约束, vde_solver_add_line 添加线段
添加垂直约束(线段垂直)
void vde_solver_add_vertical(VdeSolverHandle solver, int line_id)
| 参数 | 说明 |
|---|---|
solver |
求解器句柄 |
line_id |
线段 ID |
参见: vde_solver_add_horizontal 水平约束
求解约束系统
int vde_solver_solve(VdeSolverHandle solver, int max_iter, double tol)
| 参数 | 说明 |
|---|---|
solver |
求解器句柄 |
max_iter |
最大迭代次数 |
tol |
收敛容差 |
返回: 收敛返回 1,未收敛返回 0
参见: vde_solver_get_point 获取求解后的点坐标
获取求解后的点坐标
void vde_solver_get_point(VdeSolverHandle solver, int idx, double* out_x, double* out_y)
| 参数 | 说明 |
|---|---|
solver |
求解器句柄 |
idx |
点 ID |
out_x |
[out] 求解后 X 坐标 |
out_y |
[out] 求解后 Y 坐标 |
释放求解器句柄
void vde_solver_free(VdeSolverHandle solver)
| 参数 | 说明 |
|---|---|
solver |
求解器句柄 |
创建实心立方体 B-Rep
VdeBodyHandle vde_body_create_box(VdeHandle ctx, double w, double h, double d)
| 参数 | 说明 |
|---|---|
ctx |
引擎上下文句柄 |
w |
宽度(X 方向),> 0 |
h |
高度(Y 方向),> 0 |
d |
深度(Z 方向),> 0 |
返回: B-Rep 实体句柄
参见: vde_body_create_cylinder 圆柱体, vde_body_create_sphere 球体
创建实心圆柱体 B-Rep
VdeBodyHandle vde_body_create_cylinder(VdeHandle ctx, double r, double h, int segs)
| 参数 | 说明 |
|---|---|
ctx |
引擎上下文句柄 |
r |
截面半径,> 0 |
h |
总高度(从 -h/2 到 +h/2) |
segs |
截面分段数(边数) |
返回: B-Rep 实体句柄
参见: vde_body_create_box 立方体
创建球体 B-Rep
VdeBodyHandle vde_body_create_sphere(VdeHandle ctx, double r, int su, int sv)
| 参数 | 说明 |
|---|---|
ctx |
引擎上下文句柄 |
r |
球半径,> 0 |
su |
经度方向分段数 |
sv |
纬度方向分段数 |
返回: B-Rep 实体句柄
将 B-Rep 实体转换为三角网格
VdeMeshHandle vde_body_to_mesh(VdeHandle ctx, VdeBodyHandle body, double deflection)
| 参数 | 说明 |
|---|---|
ctx |
引擎上下文句柄 |
body |
B-Rep 实体句柄 |
deflection |
弦高误差(越小 = 越精细,推荐 0.01) |
返回: 三角网格句柄
参见: vde_body_free 释放 B-Rep 实体
释放 B-Rep 实体句柄
void vde_body_free(VdeBodyHandle body)
| 参数 | 说明 |
|---|---|
body |
B-Rep 实体句柄 |
将网格序列化为二进制字节流
size_t vde_serialize_mesh(VdeHandle ctx, VdeMeshHandle mesh, uint8_t** out_data)
| 参数 | 说明 |
|---|---|
ctx |
引擎上下文句柄 |
mesh |
网格句柄 |
out_data |
[out] 指向序列化字节数组的指针 |
返回: 字节数
输出的缓冲区由库管理,调用方不得直接 free/delete。
参见: vde_deserialize_mesh 反序列化, vde_free_buffer 释放序列化缓冲区
从二进制字节流反序列化为网格
VdeMeshHandle vde_deserialize_mesh(VdeHandle ctx, const uint8_t* data, size_t len)
| 参数 | 说明 |
|---|---|
ctx |
引擎上下文句柄 |
data |
序列化数据缓冲区 |
len |
数据长度(字节数) |
返回: 反序列化后的网格句柄
参见: vde_serialize_mesh 序列化
释放由 vde_serialize_mesh 分配的缓冲区
void vde_free_buffer(uint8_t* ptr)
| 参数 | 说明 |
|---|---|
ptr |
由 vde_serialize_mesh 返回的缓冲区指针 |