#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& 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); /** * @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); /** * @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); // ═══════════════════════════════════════════════ // 编辑操作 // ═══════════════════════════════════════════════ /** * @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); } // namespace vde::brep