aeb29ab87c
VDE-019 (Fixed): make_box/make_cylinder/make_sphere 添加 Point3D center 参数 VDE-020 (Fixed): 新增 make_cone(r1,r2,height) 和 make_torus(rMajor,rMinor) 基本体 VDE-022 (Partially Fixed): 添加 get_edge_index_by_position / get_face_index_by_position / fillet_by_position / chamfer_by_position VDE-026 (Fixed): Triangle3D 添加 int id 字段,BVH::build() 自动赋值索引,HitResult 添加 tri_index VDE-021/023/024/025 (Acknowledged): mesh→NURBS 转换等复杂几何算法,需求已记录 反馈来自 ViewDesign feat/viewdesign-engine 分支
403 lines
13 KiB
C++
403 lines
13 KiB
C++
#pragma once
|
||
/**
|
||
* @file modeling.h
|
||
* @brief 高层 B-Rep 建模 API
|
||
*
|
||
* 提供 B-Rep 实体的创建和编辑操作,类比于 CAD 系统的特征建模功能。
|
||
*
|
||
* ## 功能概览
|
||
*
|
||
* | 类别 | 操作 |
|
||
* |----------------|---------------------------------------------|
|
||
* | 基本体 | make_box, make_cylinder, make_sphere |
|
||
* | 扫掠特征 | extrude, revolve, sweep, loft |
|
||
* | 编辑操作 | fillet, chamfer, shell |
|
||
*
|
||
* ## 使用模式
|
||
*
|
||
* 每个函数返回一个新的 BrepModel(值语义),适合链式构建:
|
||
*
|
||
* @code{.cpp}
|
||
* auto body = make_box(10, 5, 3);
|
||
* // 或者更复杂的构建:
|
||
* auto profile = NURBS 曲线;
|
||
* auto swept = extrude(profile, Vector3D(0, 0, 10));
|
||
* auto rounded = fillet(swept, 0, 2.0);
|
||
* @endcode
|
||
*
|
||
* @ingroup brep
|
||
*/
|
||
#include "vde/core/point.h"
|
||
#include "vde/brep/brep.h"
|
||
|
||
namespace vde::brep {
|
||
using core::Point3D;
|
||
using core::Vector3D;
|
||
using core::AABB3D;
|
||
|
||
// ═══════════════════════════════════════════════
|
||
// 扫掠特征
|
||
// ═══════════════════════════════════════════════
|
||
|
||
/**
|
||
* @brief 沿方向挤出平面轮廓
|
||
*
|
||
* 将平面曲线沿给定方向扫掠,生成柱状实体。
|
||
*
|
||
* **算法:** 曲线的每个点沿方向向量平移,两端加盖平面形成封闭实体。
|
||
*
|
||
* @param profile 轮廓曲线(必须位于一个平面内)
|
||
* @param dir 挤出方向向量(其长度决定挤出距离)
|
||
* @return 挤出后的 B-Rep 实体
|
||
*
|
||
* @pre profile 必须是平面曲线(存在于某个平面内)且闭合
|
||
*
|
||
* @code{.cpp}
|
||
* // 沿 Z 轴挤出 5 个单位
|
||
* auto circle = NurbsCurve::create_circle(Point3D(0,0,0), 2.0);
|
||
* auto cylinder = extrude(circle, Vector3D(0, 0, 5));
|
||
* @endcode
|
||
*
|
||
* @see revolve 旋转扫掠
|
||
* @see sweep 沿任意路径扫掠
|
||
*/
|
||
[[nodiscard]] BrepModel extrude(const curves::NurbsCurve& profile, const Vector3D& dir);
|
||
|
||
/**
|
||
* @brief 绕轴旋转平面轮廓
|
||
*
|
||
* 将轮廓绕给定轴旋转,生成旋转体(如轮子、瓶子等)。
|
||
*
|
||
* @param profile 轮廓曲线(通常位于轴的半平面中)
|
||
* @param axis_origin 旋转轴上的一个点
|
||
* @param axis_dir 旋转轴方向(单位向量)
|
||
* @param angle_rad 旋转角度(弧度,默认 2π = 完整的旋转体)
|
||
* @return 旋转后的 B-Rep 实体
|
||
*
|
||
* @pre profile 必须在轴的同一侧(不应跨越轴线)
|
||
*
|
||
* @code{.cpp}
|
||
* // 绕 Y 轴旋转半圆,生成球体的一半
|
||
* NurbsCurve semicircle = 在 XZ 平面中的半圆弧;
|
||
* auto half_sphere = revolve(semicircle, Point3D(0,0,0),
|
||
* Vector3D(0,1,0), M_PI);
|
||
* @endcode
|
||
*
|
||
* @see extrude 线性挤出
|
||
* @see make_sphere 直接创建球体
|
||
*/
|
||
[[nodiscard]] BrepModel revolve(const curves::NurbsCurve& profile,
|
||
const Point3D& axis_origin,
|
||
const Vector3D& axis_dir,
|
||
double angle_rad = 2.0 * M_PI);
|
||
|
||
/**
|
||
* @brief 沿任意路径扫掠轮廓
|
||
*
|
||
* 轮廓沿一条空间路径曲线运动,生成管道或异形截面杆。
|
||
*
|
||
* @param profile 截面轮廓(需位于路径起点的垂直平面内)
|
||
* @param path 扫掠路径曲线
|
||
* @return 扫掠后的 B-Rep 实体
|
||
*
|
||
* @note 路径曲率过大处可能出现自交,需要控制路径的光滑性。
|
||
*
|
||
* @code{.cpp"}
|
||
* auto circle = NurbsCurve::create_circle(Point3D(0,0,0), 0.5);
|
||
* auto helix = NurbsCurve::create_helix(// ...);
|
||
* auto pipe = sweep(circle, helix);
|
||
* @endcode
|
||
*
|
||
* @see extrude 直线挤出
|
||
* @see revolve 旋转扫掠
|
||
*/
|
||
[[nodiscard]] BrepModel sweep(const curves::NurbsCurve& profile,
|
||
const curves::NurbsCurve& path);
|
||
|
||
/**
|
||
* @brief 在两个或多个轮廓曲线之间放样
|
||
*
|
||
* 通过线性或平滑插值连接多个平行或非平行轮廓,
|
||
* 生成过渡实体。
|
||
*
|
||
* @param profiles 轮廓曲线列表(至少 2 条)
|
||
* @return 放样后的 B-Rep 实体
|
||
*
|
||
* @pre profiles.size() ≥ 2
|
||
* @pre 所有轮廓应是平面曲线(逐一)
|
||
*
|
||
* @code{.cpp}
|
||
* auto profile_a = NurbsCurve::create_circle(Point3D(0,0,0), 5.0);
|
||
* auto profile_b = NurbsCurve::create_circle(Point3D(0,0,10), 2.0);
|
||
* auto cone = loft({profile_a, profile_b});
|
||
* @endcode
|
||
*
|
||
* @see extrude 单轮廓挤出
|
||
*/
|
||
[[nodiscard]] BrepModel loft(const std::vector<curves::NurbsCurve>& profiles);
|
||
|
||
// ═══════════════════════════════════════════════
|
||
// 基本体
|
||
// ═══════════════════════════════════════════════
|
||
|
||
/**
|
||
* @brief 创建立方体
|
||
*
|
||
* 以原点为中心、轴对齐的立方体。
|
||
*
|
||
* @param w 宽度(X 方向),必须 > 0
|
||
* @param h 高度(Y 方向),必须 > 0
|
||
* @param d 深度(Z 方向),必须 > 0
|
||
* @return 实心立方体 B-Rep
|
||
*
|
||
* @code{.cpp}
|
||
* auto box = make_box(10, 5, 3); // 10×5×3 的盒子
|
||
* @endcode
|
||
*
|
||
* @see make_cylinder 圆柱体
|
||
* @see make_sphere 球体
|
||
*/
|
||
[[nodiscard]] BrepModel make_box(double w, double h, double d,
|
||
const Point3D& center = Point3D(0, 0, 0));
|
||
|
||
/**
|
||
* @brief 创建圆柱体
|
||
*
|
||
* 沿 Y 轴、以原点为中心的圆柱体。
|
||
*
|
||
* @param radius 截面半径,必须 > 0
|
||
* @param height 总高度,沿 Y 轴从 -h/2 到 +h/2
|
||
* @param segments 截面分段数(边数,默认 32)
|
||
* @return 实心圆柱体 B-Rep
|
||
*
|
||
* @note segments 越大圆柱越光滑,但面和边数增加。
|
||
*
|
||
* @code{.cpp}
|
||
* auto cyl = make_cylinder(2.0, 10.0, 64); // 高精度圆柱
|
||
* @endcode
|
||
*
|
||
* @see make_box 立方体
|
||
* @see make_sphere 球体
|
||
*/
|
||
[[nodiscard]] BrepModel make_cylinder(double radius, double height, int segments = 32,
|
||
const Point3D& center = Point3D(0, 0, 0));
|
||
|
||
/**
|
||
* @brief 创建球体
|
||
*
|
||
* 以原点为中心的球体。
|
||
*
|
||
* @param radius 球半径,必须 > 0
|
||
* @param segments_u 经度方向分段数(默认 32)
|
||
* @param segments_v 纬度方向分段数(默认 16)
|
||
* @return 实心球体 B-Rep
|
||
*
|
||
* @code{.cpp}
|
||
* auto sphere = make_sphere(5.0, 32, 32);
|
||
* @endcode
|
||
*
|
||
* @see make_cylinder 圆柱体
|
||
*/
|
||
[[nodiscard]] BrepModel make_sphere(double radius, int segments_u = 32, int segments_v = 16,
|
||
const Point3D& center = Point3D(0, 0, 0));
|
||
|
||
/**
|
||
* @brief 创建圆锥/圆台
|
||
*
|
||
* 沿 Y 轴、以给定位置为中心的圆锥或圆台。
|
||
*
|
||
* @param r1 底部半径,必须 ≥ 0
|
||
* @param r2 顶部半径,必须 ≥ 0(r2=0 时为圆锥)
|
||
* @param height 总高度,沿 Y 轴从 -h/2 到 +h/2
|
||
* @param segments 截面分段数(边数,默认 32)
|
||
* @param center 几何中心位置(默认原点)
|
||
* @return 实心圆台/圆锥 B-Rep
|
||
*
|
||
* @code{.cpp}
|
||
* auto cone = make_cone(3.0, 1.0, 8.0); // 底部半径 3,顶部半径 1
|
||
* auto pointy = make_cone(2.0, 0.0, 5.0); // 圆锥(顶部半径 0)
|
||
* @endcode
|
||
*
|
||
* @see make_cylinder 圆柱体
|
||
*/
|
||
[[nodiscard]] BrepModel make_cone(double r1, double r2, double height, int segments = 32,
|
||
const Point3D& center = Point3D(0, 0, 0));
|
||
|
||
/**
|
||
* @brief 创建圆环体
|
||
*
|
||
* 以给定位置为中心的圆环体(torus)。
|
||
*
|
||
* @param rMajor 中心环半径(从圆环中心到管中心的距离)
|
||
* @param rMinor 管半径
|
||
* @param segments_u 绕中心环的分段数(默认 32)
|
||
* @param segments_v 绕管截面的分段数(默认 16)
|
||
* @param center 几何中心位置(默认原点)
|
||
* @return 实心圆环体 B-Rep
|
||
*
|
||
* @pre rMajor > rMinor > 0
|
||
*
|
||
* @code{.cpp}
|
||
* auto torus = make_torus(5.0, 1.0, 64, 32);
|
||
* @endcode
|
||
*/
|
||
[[nodiscard]] BrepModel make_torus(double rMajor, double rMinor,
|
||
int segments_u = 32, int segments_v = 16,
|
||
const Point3D& center = Point3D(0, 0, 0));
|
||
|
||
// ═══════════════════════════════════════════════
|
||
// 编辑操作
|
||
// ═══════════════════════════════════════════════
|
||
|
||
/**
|
||
* @brief 对边做圆角处理
|
||
*
|
||
* 在指定的边上施加恒定半径的圆角(倒圆)。
|
||
* 适用于凹边和凸边。
|
||
*
|
||
* @param body 输入实体
|
||
* @param edge_id 要倒圆的边 ID
|
||
* @param radius 圆角半径,必须 > 0
|
||
* @return 圆角后的新实体
|
||
*
|
||
* @note 圆角半径不能超过相邻面的最小宽度,否则会产生自交。
|
||
*
|
||
* @code{.cpp}
|
||
* auto box = make_box(10, 5, 3);
|
||
* auto rounded = fillet(box, 0, 2.0); // 对边 0 做半径 2 的圆角
|
||
* @endcode
|
||
*
|
||
* @see fillet_variable 变半径圆角
|
||
* @see chamfer 倒角
|
||
* @see shell 抽壳
|
||
*/
|
||
[[nodiscard]] BrepModel fillet(const BrepModel& body, int edge_id, double radius);
|
||
|
||
/**
|
||
* @brief 变半径圆角
|
||
*
|
||
* 沿边的参数方向在 r_start 和 r_end 之间线性插值半径,
|
||
* 生成平滑过渡的圆角曲面。
|
||
*
|
||
* @param body 输入实体
|
||
* @param edge_id 要倒圆的边 ID
|
||
* @param r_start 边起点处的圆角半径
|
||
* @param r_end 边终点处的圆角半径
|
||
* @param samples 沿边的横截面采样数(默认 8)
|
||
* @return 变半径圆角后的新实体
|
||
*
|
||
* @pre r_start ≥ 0, r_end ≥ 0,且至少一个 > 0
|
||
* @note samples 越大截面过渡越光滑,但面和边数增加。
|
||
*
|
||
* @code{.cpp}
|
||
* auto box = make_box(10, 5, 3);
|
||
* auto result = fillet_variable(box, 0, 0.5, 2.0, 12);
|
||
* // 边 0 从 0.5 到 2.0 逐渐变化的圆角
|
||
* @endcode
|
||
*
|
||
* @see fillet 恒定半径圆角
|
||
*/
|
||
[[nodiscard]] BrepModel fillet_variable(const BrepModel& body, int edge_id,
|
||
double r_start, double r_end, int samples = 8);
|
||
|
||
/**
|
||
* @brief 对边做倒角
|
||
*
|
||
* 将尖锐边替换为 45° 斜面。
|
||
*
|
||
* @param body 输入实体
|
||
* @param edge_id 要倒角的边 ID
|
||
* @param distance 倒角距离(从原边沿两个面各偏移的距离)
|
||
* @return 倒角后的新实体
|
||
*
|
||
* @pre distance > 0
|
||
*
|
||
* @see fillet 圆角
|
||
*/
|
||
[[nodiscard]] BrepModel chamfer(const BrepModel& body, int edge_id, double distance);
|
||
|
||
/**
|
||
* @brief 抽壳(挖空实体)
|
||
*
|
||
* 将实体变为等厚度的壳,去除指定面形成开口。
|
||
*
|
||
* @param body 输入实心实体
|
||
* @param face_id 要移除的面 ID(形成开口),-1 表示封闭壳(不开口)
|
||
* @param thickness 壁厚(正值 = 向外偏移,负值 = 向内偏移)
|
||
* @return 抽壳后的新实体
|
||
*
|
||
* @note 壁厚不应超过实体最小尺寸的一半。
|
||
* @note 当 face_id = -1 时,结果是一个封闭的壳(中空但没有开口)。
|
||
*
|
||
* @code{.cpp"}
|
||
* auto box = make_box(10, 5, 3);
|
||
* auto shelled = shell(box, 0, 0.5); // 移除面 0,壁厚 0.5
|
||
* @endcode
|
||
*
|
||
* @see fillet 圆角
|
||
*/
|
||
[[nodiscard]] BrepModel shell(const BrepModel& body, int face_id, double thickness);
|
||
|
||
// ═══════════════════════════════════════════════
|
||
// 拓扑查询(基于几何位置)
|
||
// ═══════════════════════════════════════════════
|
||
|
||
/**
|
||
* @brief 根据几何位置查找最近的 edge ID
|
||
*
|
||
* 遍历所有边,返回其端点中点距离给定点最近的边的 ID。
|
||
* 用于 mesh→BrepModel 转换后重新定位拓扑元素。
|
||
*
|
||
* @param body 输入实体
|
||
* @param nearPoint 参考点(通常为 mesh edge 中点)
|
||
* @return 最近的边 ID,若 body 无边则返回 -1
|
||
*
|
||
* @see get_face_index_by_position
|
||
*/
|
||
[[nodiscard]] int get_edge_index_by_position(const BrepModel& body, const Point3D& nearPoint);
|
||
|
||
/**
|
||
* @brief 根据几何位置查找最近的 face ID
|
||
*
|
||
* 遍历所有面,返回其边界盒中心距离给定点最近的面 ID。
|
||
* 用于 mesh→BrepModel 转换后重新定位拓扑元素。
|
||
*
|
||
* @param body 输入实体
|
||
* @param nearPoint 参考点(通常为 mesh face 中心)
|
||
* @return 最近的面 ID,若 body 无面则返回 -1
|
||
*
|
||
* @see get_edge_index_by_position
|
||
*/
|
||
[[nodiscard]] int get_face_index_by_position(const BrepModel& body, const Point3D& nearPoint);
|
||
|
||
/**
|
||
* @brief 基于几何位置对边做圆角(VDE-022 方案二)
|
||
*
|
||
* 自动查找距离 nearPoint 最近的边并对其倒圆角。
|
||
* 适用于 mesh→BrepModel 转换后的场景(edge ID 已发生变化)。
|
||
*
|
||
* @param body 输入实体
|
||
* @param nearPoint 参考点(靠近目标边的任意点)
|
||
* @param radius 圆角半径
|
||
* @return 圆角后的实体(若未找到边则返回原实体)
|
||
*
|
||
* @see fillet 基于 ID 的圆角
|
||
*/
|
||
[[nodiscard]] BrepModel fillet_by_position(const BrepModel& body,
|
||
const Point3D& nearPoint, double radius);
|
||
|
||
/**
|
||
* @brief 基于几何位置对边做倒角(VDE-022 方案二)
|
||
*
|
||
* @param body 输入实体
|
||
* @param nearPoint 参考点
|
||
* @param distance 倒角距离
|
||
* @return 倒角后的实体
|
||
*
|
||
* @see chamfer 基于 ID 的倒角
|
||
*/
|
||
[[nodiscard]] BrepModel chamfer_by_position(const BrepModel& body,
|
||
const Point3D& nearPoint, double distance);
|
||
|
||
} // namespace vde::brep
|