feat(v5-M3): large assembly LOD + constraint solver + CAM strategies + direct modeling
M3.1 — 大装配 LOD + 约束求解器 (Agent #0): - assembly_lod.h/.cpp: 3-level LOD (Full/Simplified/BBox), view-distance auto-switch - constraint_solver.h/.cpp: ConstraintGraph, DOF analysis, Newton-Raphson solver - 7 constraint types, over-constraint detection, incremental solve - 59 tests (22 LOD + 37 constraint) M3.2 — 完整 CAM 策略 (Agent #1): - cam_strategies.h/.cpp: roughing(Z-layer), finishing(parallel/spiral), drilling(G81/G83/G84) - Tool/ToolLibrary, PostProcessor (Fanuc/Siemens/Heidenhain) - material_removal_simulation with volume stats - 27 tests, 26/27 passing M3.3 — 直接建模 (Agent #2): - direct_modeling.h/.cpp: tweak_face, move_face, replace_face, push_pull, offset_face - Auto neighbor-face extension for watertightness - DirectModelingResult with diagnostics - 23 tests with validate() verification 12 files, ~5400 lines, 109 tests
This commit is contained in:
@@ -0,0 +1,267 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file assembly_lod.h
|
||||
* @brief 大装配 LOD(细节层次)系统
|
||||
*
|
||||
* 为装配体节点提供三级 LOD 支持,基于视距自动切换。
|
||||
* 集成 InstanceCache 实现几何共享,减少大装配的内存占用。
|
||||
*
|
||||
* LOD 级别:
|
||||
* - Full: 完整 B-Rep(精确几何)
|
||||
* - Simplified: QEM 简化网格(快速渲染)
|
||||
* - BoundingBox: AABB 包围盒(远距离/不可见)
|
||||
*
|
||||
* @ingroup brep
|
||||
*/
|
||||
|
||||
#include "vde/brep/assembly.h"
|
||||
#include "vde/brep/large_assembly.h"
|
||||
#include "vde/core/aabb.h"
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
namespace vde::brep {
|
||||
|
||||
/// 将局部空间 AABB 变换到世界空间
|
||||
[[nodiscard]] core::AABB3D compute_transformed_bounds(
|
||||
const core::AABB3D& local_bb, const Transform3D& tf);
|
||||
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// LODLevel
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
/// 细节层次枚举
|
||||
enum class LODLevel {
|
||||
Full, ///< 完整 B-Rep 模型(精确几何)
|
||||
Simplified, ///< QEM 简化后的三角网格
|
||||
BoundingBox ///< 仅 AABB 包围盒(远距离/剔除测试)
|
||||
};
|
||||
|
||||
/// LOD 级别转可读字符串
|
||||
[[nodiscard]] inline const char* to_string(LODLevel level) {
|
||||
switch (level) {
|
||||
case LODLevel::Full: return "Full";
|
||||
case LODLevel::Simplified: return "Simplified";
|
||||
case LODLevel::BoundingBox: return "BoundingBox";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// LODNode — per-node LOD state
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
/// 每个装配节点的 LOD 状态
|
||||
struct LODNode {
|
||||
AssemblyNode* node = nullptr; ///< 对应的装配节点
|
||||
core::AABB3D world_bounds; ///< 世界空间包围盒(缓存)
|
||||
LODLevel current_level = LODLevel::Full; ///< 当前 LOD 级别
|
||||
bool manual_override = false; ///< 是否手动设置了级别
|
||||
};
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// LODConfig
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
/// LOD 系统配置参数
|
||||
struct LODConfig {
|
||||
double near_plane = 50.0; ///< 近距离阈值:距离 < near_plane → Full
|
||||
double far_plane = 500.0; ///< 远距离阈值:距离 > far_plane → BoundingBox
|
||||
double screen_size_threshold = 0.02; ///< 屏幕空间尺寸比阈值
|
||||
int simplify_num_levels = 3; ///< QEM 简化级别数
|
||||
bool enable_auto_lod = true; ///< 是否启用自动 LOD 切换
|
||||
};
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// AssemblyLOD
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* @brief 大装配 LOD 管理器
|
||||
*
|
||||
* 管理装配体所有节点的 LOD 级别。支持:
|
||||
* - 自动视距驱动 LOD 选择
|
||||
* - 手动设置节点 LOD 级别
|
||||
* - 按 LOD 级别遍历装配体
|
||||
* - 集成 InstanceCache 共享几何
|
||||
*
|
||||
* @code{.cpp}
|
||||
* Assembly assy("robot");
|
||||
* // ... 添加零件 ...
|
||||
* AssemblyLOD lod(assy);
|
||||
* lod.set_config(LODConfig{ .near_plane = 100, .far_plane = 1000 });
|
||||
*
|
||||
* // 自动选择 LOD
|
||||
* lod.compute_lod(camera_distance, screen_size);
|
||||
*
|
||||
* // 按 LOD 遍历
|
||||
* lod.traverse_assembly([&](const LODNode& n) {
|
||||
* switch (n.current_level) {
|
||||
* case LODLevel::Full: render_brep(n); break;
|
||||
* case LODLevel::Simplified: render_simplified(n); break;
|
||||
* case LODLevel::BoundingBox: render_bbox(n); break;
|
||||
* }
|
||||
* });
|
||||
* @endcode
|
||||
*
|
||||
* @ingroup brep
|
||||
*/
|
||||
class AssemblyLOD {
|
||||
public:
|
||||
/**
|
||||
* @brief 从装配体构建 LOD 管理器
|
||||
*
|
||||
* 收集所有零件节点,预计算世界空间 AABB,
|
||||
* 通过 InstanceCache 注册可共享的几何。
|
||||
*
|
||||
* @param assembly 装配体引用
|
||||
*/
|
||||
explicit AssemblyLOD(Assembly& assembly);
|
||||
|
||||
/// 获取配置
|
||||
[[nodiscard]] const LODConfig& config() const { return config_; }
|
||||
|
||||
/// 设置配置
|
||||
void set_config(const LODConfig& cfg);
|
||||
|
||||
/**
|
||||
* @brief 获取所有 LOD 节点(扁平化列表)
|
||||
* @return LODNode 列表引用
|
||||
*/
|
||||
[[nodiscard]] const std::vector<LODNode>& nodes() const { return nodes_; }
|
||||
|
||||
/**
|
||||
* @brief 根据视距和屏幕尺寸自动选择 LOD 级别
|
||||
*
|
||||
* 选择规则:
|
||||
* - distance > far_plane → BoundingBox
|
||||
* - distance < near_plane → Full
|
||||
* - near_plane ≤ distance ≤ far_plane → Simplified
|
||||
*
|
||||
* @param camera_distance 相机到装配体中心的距离
|
||||
* @param screen_size 屏幕空间尺寸比(节点投影 / 屏幕尺寸)
|
||||
*/
|
||||
void compute_lod(double camera_distance, double screen_size);
|
||||
|
||||
/**
|
||||
* @brief 自动计算单个节点的 LOD 级别
|
||||
*
|
||||
* @param node LOD 节点(含预计算的 world_bounds)
|
||||
* @param camera_distance 相机到装配体中心的距离
|
||||
* @param screen_size 屏幕空间尺寸比
|
||||
* @return 推荐的 LOD 级别
|
||||
*/
|
||||
[[nodiscard]] LODLevel compute_lod_for_node(
|
||||
const LODNode& node,
|
||||
double camera_distance,
|
||||
double screen_size) const;
|
||||
|
||||
/**
|
||||
* @brief 手动设置某节点的 LOD 级别
|
||||
*
|
||||
* 手动设置后,该节点将忽略自动 LOD 选择直到调用 clear_manual_override()。
|
||||
*
|
||||
* @param node LOD 节点(通过 nodes() 获取)
|
||||
* @param level 要设置的 LOD 级别
|
||||
*/
|
||||
void set_lod_level(LODNode& node, LODLevel level);
|
||||
|
||||
/**
|
||||
* @brief 清除手动 LOD 设置
|
||||
*
|
||||
* @param node 要清除手动覆盖的节点
|
||||
*/
|
||||
void clear_manual_override(LODNode& node);
|
||||
|
||||
/// 清除所有节点的手动 LOD 设置
|
||||
void clear_all_manual_overrides();
|
||||
|
||||
/**
|
||||
* @brief 按 LOD 级别遍历装配体
|
||||
*
|
||||
* 对每个零件节点调用 visitor,传入其 LODNode 状态。
|
||||
*
|
||||
* @param visitor 回调函数:void(const LODNode&)
|
||||
*/
|
||||
template <typename Visitor>
|
||||
void traverse_assembly(Visitor&& visitor) const {
|
||||
for (const auto& node : nodes_) {
|
||||
visitor(node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 按 LOD 遍历(带装配层级上下文)
|
||||
*
|
||||
* 遍历装配体树,对每个零件节点调用 visitor。
|
||||
* 传入 LODNode、父变换矩阵、深度。
|
||||
*
|
||||
* @param visitor 回调:bool(LODNode&, const Transform3D& parent_tf, int depth)
|
||||
* 返回 false 可提前终止遍历
|
||||
*/
|
||||
template <typename Visitor>
|
||||
bool traverse_with_context(Visitor&& visitor) const {
|
||||
return traverse_impl(&assembly_.root, Transform3D::Identity(), 0,
|
||||
std::forward<Visitor>(visitor));
|
||||
}
|
||||
|
||||
/// 获取 InstanceCache
|
||||
[[nodiscard]] InstanceCache& cache() { return cache_; }
|
||||
[[nodiscard]] const InstanceCache& cache() const { return cache_; }
|
||||
|
||||
/// 零件总数
|
||||
[[nodiscard]] size_t part_count() const { return nodes_.size(); }
|
||||
|
||||
/// 各级别统计
|
||||
struct LODStats {
|
||||
size_t full_count = 0;
|
||||
size_t simplified_count = 0;
|
||||
size_t bbox_count = 0;
|
||||
size_t manual_count = 0;
|
||||
};
|
||||
|
||||
/// 获取当前 LOD 统计信息
|
||||
[[nodiscard]] LODStats statistics() const;
|
||||
|
||||
/// 获取装配体总包围盒
|
||||
[[nodiscard]] core::AABB3D total_bounds() const { return total_bounds_; }
|
||||
|
||||
/// 更新所有节点的世界空间包围盒(变换改变后调用)
|
||||
void update_bounds();
|
||||
|
||||
private:
|
||||
Assembly& assembly_;
|
||||
LODConfig config_;
|
||||
std::vector<LODNode> nodes_;
|
||||
InstanceCache cache_;
|
||||
core::AABB3D total_bounds_;
|
||||
|
||||
/// 收集所有零件节点
|
||||
void collect_nodes(AssemblyNode* node, const Transform3D& parent_tf);
|
||||
|
||||
/// 带上下文的遍历实现
|
||||
template <typename Visitor>
|
||||
bool traverse_impl(AssemblyNode* node, const Transform3D& parent_tf,
|
||||
int depth, Visitor&& visitor) const {
|
||||
Transform3D world = parent_tf * node->local_transform;
|
||||
if (node->is_part()) {
|
||||
// 查找对应的 LODNode
|
||||
for (auto& ln : nodes_) {
|
||||
if (ln.node == node) {
|
||||
if (!visitor(ln, world, depth))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto& child : node->children) {
|
||||
if (!traverse_impl(child.get(), world, depth + 1,
|
||||
std::forward<Visitor>(visitor)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace vde::brep
|
||||
@@ -1,75 +1,393 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file constraint_solver.h
|
||||
* @brief 3D constraint solver for assembly
|
||||
* @brief 3D 装配约束求解器 — 约束图 + Newton-Raphson + DOF 分析
|
||||
*
|
||||
* Iterative relaxation solver for spatial constraints between assembly nodes.
|
||||
* Supports coincident, concentric, distance, angle, parallel, perpendicular,
|
||||
* and tangent constraints over 3D bounding box proxies.
|
||||
* 为 3D 装配提供完整的约束求解系统:
|
||||
* - ConstraintGraph: 约束图(节点=零件, 边=约束)
|
||||
* - Newton-Raphson 迭代求解
|
||||
* - DOF 分析(每个零件 6 DOF)
|
||||
* - 过度约束检测(冗余约束识别 + 报告)
|
||||
* - 联动求解(增量更新)
|
||||
*
|
||||
* @ingroup brep
|
||||
*/
|
||||
|
||||
#include "vde/brep/assembly.h"
|
||||
#include "vde/core/point.h"
|
||||
#include "vde/core/transform.h"
|
||||
#include "vde/core/aabb.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
namespace vde::brep {
|
||||
|
||||
/// Constraint type for 3D assembly solving
|
||||
enum class Constraint3D {
|
||||
Coincident, ///< Face-face alignment (coplanar, opposite normals)
|
||||
Concentric, ///< Axis-axis alignment
|
||||
Distance, ///< Fixed distance between faces
|
||||
Angle, ///< Fixed angle between faces
|
||||
Parallel, ///< Face normals parallel
|
||||
Perpendicular, ///< Face normals perpendicular
|
||||
Tangent ///< Face tangent contact
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// ConstraintType
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
/// 3D 约束类型
|
||||
enum class ConstraintType {
|
||||
Coincident, ///< 面-面贴合(共面,法向相反)
|
||||
Concentric, ///< 轴-轴对齐(同轴)
|
||||
Tangent, ///< 面相切接触
|
||||
Distance, ///< 固定面间距
|
||||
Angle, ///< 固定面夹角(弧度)
|
||||
Parallel, ///< 面法线平行
|
||||
Perpendicular ///< 面法线垂直
|
||||
};
|
||||
|
||||
/// A single constraint between two assembly nodes
|
||||
struct ConstraintEntry {
|
||||
int node_a; ///< Index into a flattened node list (or 0-based child index)
|
||||
int node_b; ///< Index of the node that moves to satisfy constraint
|
||||
Constraint3D type;
|
||||
double value = 0.0; ///< Distance or angle value (radians for Angle)
|
||||
/// 约束类型转字符串
|
||||
[[nodiscard]] inline const char* constraint_type_name(ConstraintType t) {
|
||||
switch (t) {
|
||||
case ConstraintType::Coincident: return "Coincident";
|
||||
case ConstraintType::Concentric: return "Concentric";
|
||||
case ConstraintType::Tangent: return "Tangent";
|
||||
case ConstraintType::Distance: return "Distance";
|
||||
case ConstraintType::Angle: return "Angle";
|
||||
case ConstraintType::Parallel: return "Parallel";
|
||||
case ConstraintType::Perpendicular: return "Perpendicular";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
/// 每个约束消除的自由度数(估算)
|
||||
[[nodiscard]] inline int constraint_dof_elimination(ConstraintType t) {
|
||||
switch (t) {
|
||||
case ConstraintType::Coincident: return 3; // 1 平移 + 2 旋转
|
||||
case ConstraintType::Concentric: return 4; // 2 平移 + 2 旋转
|
||||
case ConstraintType::Tangent: return 1; // 1 平移
|
||||
case ConstraintType::Distance: return 1; // 1 平移
|
||||
case ConstraintType::Angle: return 1; // 1 旋转
|
||||
case ConstraintType::Parallel: return 2; // 2 旋转
|
||||
case ConstraintType::Perpendicular: return 2; // 2 旋转
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// Constraint — 单个约束边
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
/// 单个约束描述
|
||||
struct Constraint {
|
||||
int node_a; ///< 约束的零件 A 索引
|
||||
int node_b; ///< 约束的零件 B 索引
|
||||
ConstraintType type; ///< 约束类型
|
||||
double value = 0.0; ///< 约束值(Distance=distance, Angle=radians)
|
||||
double weight = 1.0; ///< 权重(用于过约束系统的加权最小二乘)
|
||||
std::string name; ///< 约束名称(可选)
|
||||
|
||||
Constraint() = default;
|
||||
Constraint(int a, int b, ConstraintType t, double v = 0.0, double w = 1.0)
|
||||
: node_a(a), node_b(b), type(t), value(v), weight(w) {}
|
||||
};
|
||||
|
||||
/// Solve a system of 3D constraints on an assembly using iterative relaxation.
|
||||
///
|
||||
/// Repeatedly adjusts transforms for each constraint in round-robin order
|
||||
/// until all constraints are satisfied within tolerance or max_iterations
|
||||
/// is exhausted.
|
||||
///
|
||||
/// @param assembly Target assembly (root children are the constrained nodes)
|
||||
/// @param constraints Ordered list of constraints to satisfy
|
||||
/// @param max_iterations Maximum number of relaxation passes (default 100)
|
||||
/// @param tolerance Convergence tolerance (default 1e-6)
|
||||
/// @return true if all constraints satisfied within tolerance
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// DOFInfo — 每个节点的自由度信息
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
/// 单个零件的自由度分析结果
|
||||
struct DOFInfo {
|
||||
int total_dof = 6; ///< 起始 DOF(空间刚体:6)
|
||||
int eliminated_dof = 0; ///< 已消除的 DOF
|
||||
int remaining_dof = 6; ///< 剩余 DOF
|
||||
bool is_fixed = false; ///< 是否完全约束
|
||||
std::vector<int> constraining; ///< 约束此零件的约束索引列表
|
||||
};
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// ConstraintGraph
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* @brief 3D 约束图
|
||||
*
|
||||
* 节点 = 装配零件(AssemblyNode),边 = 约束。
|
||||
* 提供图遍历、DOF 分析、过度约束检测。
|
||||
*
|
||||
* @ingroup brep
|
||||
*/
|
||||
class ConstraintGraph {
|
||||
public:
|
||||
/// 添加零件节点
|
||||
/// @param name 零件名称
|
||||
/// @param node 零件节点指针
|
||||
/// @return 节点索引
|
||||
int add_node(const std::string& name, AssemblyNode* node);
|
||||
|
||||
/// 添加约束边
|
||||
/// @param c 约束描述
|
||||
/// @return 约束索引
|
||||
int add_constraint(const Constraint& c);
|
||||
|
||||
/// 删除约束
|
||||
/// @param index 约束索引
|
||||
void remove_constraint(int index);
|
||||
|
||||
/// 获取节点数
|
||||
[[nodiscard]] int node_count() const { return static_cast<int>(nodes_.size()); }
|
||||
|
||||
/// 获取约束数
|
||||
[[nodiscard]] int constraint_count() const { return static_cast<int>(constraints_.size()); }
|
||||
|
||||
/// 获取节点名
|
||||
[[nodiscard]] const std::string& node_name(int idx) const;
|
||||
|
||||
/// 获取节点指针
|
||||
[[nodiscard]] AssemblyNode* node_ptr(int idx) const;
|
||||
|
||||
/// 获取约束
|
||||
[[nodiscard]] const Constraint& constraint(int idx) const;
|
||||
|
||||
/// 获取可修改约束引用(用于增量更新)
|
||||
[[nodiscard]] Constraint& constraint_mut(int idx);
|
||||
|
||||
/// 获取某节点的所有相邻约束
|
||||
[[nodiscard]] std::vector<int> node_constraints(int node_idx) const;
|
||||
|
||||
/// 获取所有节点索引
|
||||
[[nodiscard]] const std::vector<int>& node_indices() const { return node_ids_; }
|
||||
|
||||
// ── DOF 分析 ──
|
||||
|
||||
/**
|
||||
* @brief 执行 DOF 分析
|
||||
*
|
||||
* 对每个零件计算自由度状态:
|
||||
* - 初始 6 DOF(3 平移 + 3 旋转)
|
||||
* - 每个约束消除若干 DOF
|
||||
* - 返回每个节点的 DOFInfo
|
||||
*
|
||||
* @return 节点索引 → DOF 信息
|
||||
*/
|
||||
[[nodiscard]] std::vector<DOFInfo> analyze_dof() const;
|
||||
|
||||
/**
|
||||
* @brief 计算单个节点的剩余 DOF
|
||||
* @param node_idx 节点索引
|
||||
* @return 剩余自由度数
|
||||
*/
|
||||
[[nodiscard]] int remaining_dof(int node_idx) const;
|
||||
|
||||
/**
|
||||
* @brief 检查图是否完全约束(所有节点 fixed)
|
||||
* @return true 如果所有节点 DOF=0
|
||||
*/
|
||||
[[nodiscard]] bool is_fully_constrained() const;
|
||||
|
||||
// ── 过度约束检测 ──
|
||||
|
||||
/**
|
||||
* @brief 过度约束检测结果
|
||||
*/
|
||||
struct OverConstraintInfo {
|
||||
int node_index; ///< 哪个节点
|
||||
int eliminated_dof; ///< 已消除 DOF
|
||||
bool over_constrained; ///< 是否过度约束(eliminated > 6)
|
||||
std::vector<int> redundant; ///< 冗余约束索引列表
|
||||
std::string message; ///< 人类可读的消息
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 检测过度约束
|
||||
*
|
||||
* 对每个节点检查:已消除 DOF > 6 即为过度约束。
|
||||
* 识别并报告冗余约束。
|
||||
*
|
||||
* @return 过度约束节点列表
|
||||
*/
|
||||
[[nodiscard]] std::vector<OverConstraintInfo> detect_over_constraints() const;
|
||||
|
||||
// ── 图结构查询 ──
|
||||
|
||||
/// 获取所有约束
|
||||
[[nodiscard]] const std::vector<Constraint>& constraints() const { return constraints_; }
|
||||
|
||||
/// 检查两个节点之间是否已存在约束
|
||||
[[nodiscard]] bool has_constraint_between(int a, int b) const;
|
||||
|
||||
/// 获取两个节点之间的所有约束
|
||||
[[nodiscard]] std::vector<int> constraints_between(int a, int b) const;
|
||||
|
||||
/// 清空图
|
||||
void clear();
|
||||
|
||||
private:
|
||||
struct NodeInfo {
|
||||
std::string name;
|
||||
AssemblyNode* ptr = nullptr;
|
||||
};
|
||||
|
||||
std::vector<NodeInfo> nodes_;
|
||||
std::vector<int> node_ids_; // 压缩的索引映射
|
||||
std::vector<Constraint> constraints_;
|
||||
std::vector<bool> constraint_active_; // 约束是否激活(未删除)
|
||||
|
||||
/// 邻接表:node_idx → [constraint_idx...]
|
||||
std::vector<std::vector<int>> adjacency_;
|
||||
};
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// Newton-Raphson 求解器
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* @brief Newton-Raphson 求解器配置
|
||||
*/
|
||||
struct NRSolverConfig {
|
||||
int max_iterations = 100; ///< 最大迭代次数
|
||||
double tolerance = 1e-6; ///< 收敛容差
|
||||
double step_size = 0.5; ///< 步长衰减因子(0~1,防震荡)
|
||||
double damping = 0.5; ///< 阻尼因子
|
||||
bool check_over_constrained = true; ///< 求解前检测过度约束
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 求解器状态
|
||||
*/
|
||||
struct SolveResult {
|
||||
bool converged = false; ///< 是否收敛
|
||||
int iterations = 0; ///< 实际迭代次数
|
||||
double final_error = 0.0; ///< 最终残差 L2 范数
|
||||
std::vector<double> error_history; ///< 每步误差历史
|
||||
std::string message; ///< 人类可读的消息
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Newton-Raphson 约束求解器
|
||||
*
|
||||
* 将约束表示为方程系统 f(x)=0,使用 Newton-Raphson 迭代求解。
|
||||
*
|
||||
* 状态向量 x = [t1_x, t1_y, t1_z, r1_x, r1_y, r1_z, t2_..., ...]
|
||||
* 每个零件有 6 个参数:3 平移 + 3 旋转(轴-角表示的一部分,用增量旋转)。
|
||||
*
|
||||
* 每一步:
|
||||
* 1. 评估约束函数 f(x) → 残差向量
|
||||
* 2. 数值计算 Jacobian J = ∂f/∂x
|
||||
* 3. 求解 J·Δx = -f(x)
|
||||
* 4. 更新 x ← x + α·Δx(α 为步长)
|
||||
*
|
||||
* @ingroup brep
|
||||
*/
|
||||
class NewtonRaphsonSolver {
|
||||
public:
|
||||
/**
|
||||
* @brief 求解约束图
|
||||
*
|
||||
* @param graph 约束图
|
||||
* @param assembly 装配体(将被修改以满足约束)
|
||||
* @param config 求解器配置
|
||||
* @return SolveResult 求解结果
|
||||
*/
|
||||
[[nodiscard]] SolveResult solve(
|
||||
ConstraintGraph& graph,
|
||||
Assembly& assembly,
|
||||
const NRSolverConfig& config = NRSolverConfig{});
|
||||
|
||||
/**
|
||||
* @brief 增量求解:修改单个约束值后更新
|
||||
*
|
||||
* 在已有求解结果基础上,仅修改一个约束值,
|
||||
* 从当前状态出发重新求解(热启动)。
|
||||
*
|
||||
* @param graph 约束图
|
||||
* @param assembly 装配体
|
||||
* @param constraint_idx 被修改的约束索引
|
||||
* @param new_value 新的约束值
|
||||
* @param config 求解器配置
|
||||
* @return SolveResult
|
||||
*/
|
||||
[[nodiscard]] SolveResult incremental_solve(
|
||||
ConstraintGraph& graph,
|
||||
Assembly& assembly,
|
||||
int constraint_idx,
|
||||
double new_value,
|
||||
const NRSolverConfig& config = NRSolverConfig{});
|
||||
|
||||
/// 获取最后一次求解的状态向量
|
||||
[[nodiscard]] const std::vector<double>& last_state() const { return state_; }
|
||||
|
||||
private:
|
||||
int n_parts_ = 0; ///< 零件数
|
||||
std::vector<double> state_; ///< 状态向量 [tx,ty,tz,rx,ry,rz]*n
|
||||
std::vector<double> last_error_; ///< 最近误差向量
|
||||
|
||||
/// 从 assembly 读取变换到状态向量
|
||||
void read_state(const ConstraintGraph& graph, const Assembly& assembly);
|
||||
|
||||
/// 将状态向量写回 assembly
|
||||
void write_state(const ConstraintGraph& graph, Assembly& assembly) const;
|
||||
|
||||
/// 评估所有约束函数,填充残差向量 f
|
||||
/// @return 残差的 L2 范数
|
||||
double evaluate_constraints(
|
||||
const ConstraintGraph& graph,
|
||||
const Assembly& assembly,
|
||||
std::vector<double>& residual) const;
|
||||
|
||||
/// 数值计算 Jacobian(中心差分)
|
||||
void compute_jacobian(
|
||||
const ConstraintGraph& graph,
|
||||
Assembly& assembly,
|
||||
const std::vector<double>& residual,
|
||||
Eigen::MatrixXd& J);
|
||||
|
||||
/// 单个约束的评估函数
|
||||
double evaluate_single_constraint(
|
||||
const Constraint& c,
|
||||
const AssemblyNode& na,
|
||||
const AssemblyNode& nb) const;
|
||||
|
||||
/// 求解线性最小二乘问题 J·Δx = -f
|
||||
Eigen::VectorXd solve_linear_step(
|
||||
const Eigen::MatrixXd& J,
|
||||
const Eigen::VectorXd& f) const;
|
||||
};
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 向后兼容 API(保留旧接口)
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
/// @deprecated 使用 ConstraintType 代替
|
||||
using Constraint3D = ConstraintType;
|
||||
|
||||
/// @deprecated 使用 Constraint 代替
|
||||
struct ConstraintEntry : public Constraint {
|
||||
using Constraint::Constraint;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 简化版求解器(向后兼容)
|
||||
*
|
||||
* 使用迭代松弛法求解约束系统。
|
||||
*
|
||||
* @param assembly 目标装配体
|
||||
* @param constraints 约束列表(node_a, node_b 为 root.children 中的直接索引)
|
||||
* @param max_iterations 最大迭代次数
|
||||
* @param tolerance 收敛容差
|
||||
* @return true 如果所有约束在容差内满足
|
||||
*/
|
||||
[[nodiscard]] bool solve_constraints(
|
||||
Assembly& assembly,
|
||||
const std::vector<ConstraintEntry>& constraints,
|
||||
int max_iterations = 100,
|
||||
double tolerance = 1e-6);
|
||||
|
||||
/// Apply a single coincident (mate) constraint: align the closest opposing
|
||||
/// faces of node_a and node_b so they are coplanar.
|
||||
///
|
||||
/// @return The correction transform that was applied to node_b
|
||||
/// 应用贴合约束
|
||||
[[nodiscard]] core::Transform3D apply_coincident(
|
||||
const AssemblyNode& node_a, AssemblyNode& node_b);
|
||||
|
||||
/// Apply a single concentric constraint: align the bounding-box-estimated
|
||||
/// cylinder axes of node_a and node_b.
|
||||
///
|
||||
/// @return The correction transform that was applied to node_b
|
||||
/// 应用同轴约束
|
||||
[[nodiscard]] core::Transform3D apply_concentric(
|
||||
const AssemblyNode& node_a, AssemblyNode& node_b);
|
||||
|
||||
/// Apply a distance constraint: set the closest-approach gap between
|
||||
/// the bounding boxes of node_a and node_b to @p distance.
|
||||
///
|
||||
/// @return The correction transform that was applied to node_b
|
||||
/// 应用距离约束
|
||||
[[nodiscard]] core::Transform3D apply_distance(
|
||||
const AssemblyNode& node_a, AssemblyNode& node_b, double distance);
|
||||
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file direct_modeling.h
|
||||
* @brief 直接建模操作 — 面级推拉/偏移/移动/替换
|
||||
*
|
||||
* 直接建模(Direct Modeling / Synchronous Technology)允许用户
|
||||
* 直接操纵几何面而不依赖特征历史树。该模块提供:
|
||||
*
|
||||
* | 操作 | 含义 |
|
||||
* |--------------|-----------------------------------------|
|
||||
* | tweak_face | 面沿法向微调偏移,邻面自动延伸保持水密 |
|
||||
* | move_face | 面刚体移动(平移+旋转),检测不穿透邻面 |
|
||||
* | replace_face | 面替换(交换曲面),边界兼容性检查 |
|
||||
* | push_pull | 推拉:正值=挤出加材料,负值=切除减材料 |
|
||||
* | offset_face | 面等距偏移 |
|
||||
*
|
||||
* 所有操作返回 DirectModelingResult,含成功/失败诊断及生成的新模型。
|
||||
*
|
||||
* @ingroup brep
|
||||
*/
|
||||
|
||||
#include "vde/brep/brep.h"
|
||||
#include "vde/curves/nurbs_surface.h"
|
||||
#include "vde/core/transform.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace vde::brep {
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// DirectModelingResult — 操作结果
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* @brief 直接建模操作结果
|
||||
*
|
||||
* 包含成功/失败标志、错误/警告诊断信息及生成的新模型。
|
||||
* 即使操作部分成功(如某些邻面未能延伸)也会在 warnings 中记录。
|
||||
*/
|
||||
struct DirectModelingResult {
|
||||
/** @brief 操作是否成功(至少基本几何有效) */
|
||||
bool success = false;
|
||||
|
||||
/** @brief 结果模型(success=true 时有效,否则为输入副本) */
|
||||
BrepModel body;
|
||||
|
||||
/** @brief 错误消息列表(导致 success=false) */
|
||||
std::vector<std::string> errors;
|
||||
|
||||
/** @brief 警告消息列表(不影响 success) */
|
||||
std::vector<std::string> warnings;
|
||||
|
||||
/** @brief 受影响的面数 */
|
||||
int affected_faces = 0;
|
||||
|
||||
/** @brief 新建的面数(推拉产生的侧面等) */
|
||||
int new_faces = 0;
|
||||
|
||||
/** @brief 操作类型名称(供日志/UI 显示) */
|
||||
std::string operation;
|
||||
};
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// Direct Modeling Operations
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* @brief 面微调:沿法向偏移指定距离
|
||||
*
|
||||
* 将面沿其法向量方向偏移 delta。邻面自动延伸/裁剪
|
||||
* 以保持水密封闭体。适合小范围的面调整。
|
||||
*
|
||||
* @param body 输入 B-Rep 实体
|
||||
* @param face_id 目标面索引(0..num_faces-1)
|
||||
* @param delta 偏移距离(正=沿法向向外,负=向内)
|
||||
* @return DirectModelingResult 含新模型和诊断信息
|
||||
*
|
||||
* @pre face_id 在 [0, body.num_faces()) 范围内
|
||||
* @pre 实体应为封闭水密体
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto box = make_box(2, 2, 2);
|
||||
* auto result = tweak_face(box, 0, 0.5); // 顶面上移 0.5
|
||||
* // 四个侧面自动延伸保持水密
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] DirectModelingResult tweak_face(const BrepModel& body,
|
||||
int face_id, double delta);
|
||||
|
||||
/**
|
||||
* @brief 面移动:对指定面施加刚体变换
|
||||
*
|
||||
* 通过 4x4 仿射变换矩阵移动面。检测移动后面是否
|
||||
* 与邻面相交(产生自交),相交时返回错误。
|
||||
*
|
||||
* @param body 输入 B-Rep 实体
|
||||
* @param face_id 目标面索引
|
||||
* @param transform 刚体变换矩阵(仅平移+旋转,不含缩放)
|
||||
* @return DirectModelingResult 含新模型和诊断
|
||||
*
|
||||
* @note 非均匀缩放会导致法线失真;使用 Transform3D 时建议只用平移+旋转
|
||||
* @note 移动后检测面是否穿透邻面(通过法线方向变化判断)
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto box = make_box(2, 2, 2);
|
||||
* auto T = translate(Vector3D(0.5, 0, 0)) * rotate_z(M_PI / 4);
|
||||
* auto result = move_face(box, 0, T);
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] DirectModelingResult move_face(const BrepModel& body,
|
||||
int face_id,
|
||||
const core::Transform3D& transform);
|
||||
|
||||
/**
|
||||
* @brief 面替换:用新曲面替换面的现有曲面
|
||||
*
|
||||
* 新曲面与原面必须有兼容的边界:新曲面的四条边界
|
||||
* 应近似匹配面的四条边界边。不兼容时操作失败。
|
||||
*
|
||||
* @param body 输入 B-Rep 实体
|
||||
* @param face_id 目标面索引
|
||||
* @param new_surface 替换用的新 NURBS 曲面
|
||||
* @return DirectModelingResult 含新模型和诊断
|
||||
*
|
||||
* @note 仅替换曲面的几何定义,拓扑结构不变
|
||||
* @note 新曲面参数域应与原曲面兼容(边界对应对齐)
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto box = make_box(2, 2, 2);
|
||||
* NurbsSurface curved_surf = ...; // 曲面边界与 box 顶面匹配
|
||||
* auto result = replace_face(box, 0, curved_surf);
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] DirectModelingResult replace_face(const BrepModel& body,
|
||||
int face_id,
|
||||
const curves::NurbsSurface& new_surface);
|
||||
|
||||
/**
|
||||
* @brief 推拉操作:沿法线挤出(正值)或切除(负值)
|
||||
*
|
||||
* 正值 distance:面沿法向向外挤出,自动创建四侧面
|
||||
* 闭合新体积。等同于"挤出添加材料"。
|
||||
*
|
||||
* 负值 distance:面沿法向向内凹陷,邻面自动延伸
|
||||
* 封闭。等同于"切除材料"。
|
||||
*
|
||||
* @param body 输入 B-Rep 实体
|
||||
* @param face_id 目标面索引
|
||||
* @param distance 推拉距离(正=挤出加材料,负=切除减材料)
|
||||
* @return DirectModelingResult 含新模型和诊断
|
||||
*
|
||||
* @pre distance 的绝对值不超过实体在法线方向的最小厚度
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto box = make_box(2, 2, 2);
|
||||
* // 顶面挤出 1.0 → 凸台
|
||||
* auto pad = push_pull(box, 0, 1.0);
|
||||
* // 顶面切除 0.5 → 凹陷
|
||||
* auto pocket = push_pull(box, 0, -0.5);
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] DirectModelingResult push_pull(const BrepModel& body,
|
||||
int face_id, double distance);
|
||||
|
||||
/**
|
||||
* @brief 面等距偏移:将面均匀偏移指定距离
|
||||
*
|
||||
* 面等距偏移与 tweak_face 的区别:
|
||||
* - offset_face 保证偏移后曲面与原曲面处处等距(等距曲面)
|
||||
* - tweak_face 是近似偏移(沿平均法向移动顶点)
|
||||
*
|
||||
* 对于平面,两者等价。对于曲面,offset_face 生成
|
||||
* 真正的等距曲面。
|
||||
*
|
||||
* @param body 输入 B-Rep 实体
|
||||
* @param face_id 目标面索引
|
||||
* @param offset_distance 等距偏移距离(正=向外,负=向内)
|
||||
* @return DirectModelingResult 含新模型和诊断
|
||||
*
|
||||
* @warning 自由曲面等距偏移可能产生自交,需检查结果有效性
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto sphere = make_sphere(3.0);
|
||||
* auto result = offset_face(sphere, 0, 0.2); // 面均匀外扩 0.2
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] DirectModelingResult offset_face(const BrepModel& body,
|
||||
int face_id, double offset_distance);
|
||||
|
||||
} // namespace vde::brep
|
||||
@@ -0,0 +1,260 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file cam_strategies.h
|
||||
* @brief 完整 CAM 加工策略 — 粗加工、精加工、钻孔、刀具库、后处理、仿真
|
||||
*
|
||||
* 在 cam_toolpath.h 的基础刀路(contour/pocket)之上提供:
|
||||
* - 层切粗加工 (roughing_toolpath)
|
||||
* - 精加工平行/环绕 (finishing_toolpath)
|
||||
* - 钻孔循环 G81/G83/G84 (drilling_toolpath)
|
||||
* - 刀具结构与刀具库 (Tool, ToolLibrary)
|
||||
* - 后处理器框架 (PostProcessor → FanucPost, SiemensPost, HeidenhainPost)
|
||||
* - 加工仿真数据生成 (material_removal_simulation)
|
||||
*
|
||||
* @ingroup core
|
||||
*/
|
||||
#include "vde/core/point.h"
|
||||
#include "vde/core/aabb.h"
|
||||
#include "vde/core/cam_toolpath.h"
|
||||
#include "vde/mesh/halfedge_mesh.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
namespace vde::brep {
|
||||
class BrepModel;
|
||||
} // namespace vde::brep
|
||||
|
||||
namespace vde::core {
|
||||
|
||||
using core::Point3D;
|
||||
using core::Vector3D;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// 刀具定义
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// 刀具类型枚举
|
||||
enum class ToolType {
|
||||
ENDMILL, ///< 平底铣刀
|
||||
BALLNOSE, ///< 球头铣刀
|
||||
DRILL, ///< 钻头
|
||||
FACEMILL, ///< 面铣刀
|
||||
TAP ///< 丝锥
|
||||
};
|
||||
|
||||
/// 刀具参数结构体
|
||||
struct Tool {
|
||||
int id = 0; ///< 刀具编号
|
||||
std::string name; ///< 刀具名称
|
||||
ToolType type = ToolType::ENDMILL; ///< 刀具类型
|
||||
double diameter = 10.0; ///< 刀具直径 (mm)
|
||||
int flutes = 2; ///< 刃数
|
||||
double length = 50.0; ///< 有效刃长 (mm)
|
||||
double overall_length = 75.0; ///< 总长 (mm)
|
||||
double shank_diameter = 10.0; ///< 柄径 (mm)
|
||||
|
||||
/// 计算推荐转速(基于切削速度 m/min)
|
||||
[[nodiscard]] double spindle_rpm(double cutting_speed_m_per_min) const;
|
||||
/// 计算推荐进给速度(mm/min,基于每齿进给量 mm/tooth)
|
||||
[[nodiscard]] double feed_rate_mm_per_min(double feed_per_tooth) const;
|
||||
};
|
||||
|
||||
/// 刀具库 — 管理多个刀具
|
||||
class ToolLibrary {
|
||||
public:
|
||||
/// 添加刀具,返回内部索引
|
||||
int add_tool(const Tool& tool);
|
||||
/// 按编号查找刀具
|
||||
[[nodiscard]] std::optional<Tool> find_tool(int id) const;
|
||||
/// 按名称查找刀具
|
||||
[[nodiscard]] std::optional<Tool> find_tool(const std::string& name) const;
|
||||
/// 列出所有刀具
|
||||
[[nodiscard]] const std::vector<Tool>& list_tools() const { return tools_; }
|
||||
/// 刀具数量
|
||||
[[nodiscard]] size_t size() const { return tools_.size(); }
|
||||
|
||||
private:
|
||||
std::vector<Tool> tools_;
|
||||
};
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// 加工参数
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// 粗加工参数
|
||||
struct RoughingParams {
|
||||
double step_down = 1.0; ///< 每层切深 (mm)
|
||||
double step_over = 2.0; ///< 横向步距 (mm)
|
||||
double stock_to_leave = 0.5; ///< 留量 (mm)
|
||||
double feed_rate = 800.0; ///< 进给速度 (mm/min)
|
||||
double safe_z = 10.0; ///< 安全高度 (mm)
|
||||
};
|
||||
|
||||
/// 精加工参数
|
||||
struct FinishingParams {
|
||||
double step_over = 0.5; ///< 行距 (mm)
|
||||
double feed_rate = 500.0; ///< 进给速度 (mm/min)
|
||||
double safe_z = 10.0; ///< 安全高度 (mm)
|
||||
double depth_of_cut = 0.0; ///< 精加工深度 (Z 坐标;0=最终 Z,负=往下)
|
||||
};
|
||||
|
||||
/// 精加工策略类型
|
||||
enum class FinishingStrategy {
|
||||
PARALLEL, ///< 平行刀路 — 等距平行线
|
||||
SPIRAL ///< 环绕刀路 — 轮廓向内偏移
|
||||
};
|
||||
|
||||
/// 钻孔循环类型
|
||||
enum class DrillingCycle {
|
||||
G81, ///< 简单钻孔:G81 X.. Y.. Z.. R.. F..
|
||||
G83, ///< 深孔啄钻:G83 X.. Y.. Z.. R.. Q.. F..
|
||||
G84 ///< 攻丝: G84 X.. Y.. Z.. R.. F..
|
||||
};
|
||||
|
||||
/// 钻孔点定义
|
||||
struct DrillPoint {
|
||||
Point3D position; ///< 孔位坐标
|
||||
double depth = -10.0; ///< 钻深(Z 坐标)
|
||||
double peck_depth = 2.0; ///< 啄钻每次深度 (G83 用)
|
||||
};
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// 后处理器框架
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// 抽象后处理器基类
|
||||
class PostProcessor {
|
||||
public:
|
||||
virtual ~PostProcessor() = default;
|
||||
|
||||
/// 程序头部(初始化 G-code、换刀等)
|
||||
[[nodiscard]] virtual std::string prologue(const Toolpath& tp) const = 0;
|
||||
/// 程序尾部(退刀、程序结束)
|
||||
[[nodiscard]] virtual std::string epilogue(const Toolpath& tp) const = 0;
|
||||
/// 格式化一条 G-code 行
|
||||
[[nodiscard]] virtual std::string format_gcode(const PathSegment& seg) const = 0;
|
||||
|
||||
/// 完整后处理:prologue + segments + epilogue
|
||||
[[nodiscard]] std::string post_process(const Toolpath& tp) const;
|
||||
};
|
||||
|
||||
/// Fanuc 控制器后处理器
|
||||
class FanucPost : public PostProcessor {
|
||||
public:
|
||||
[[nodiscard]] std::string prologue(const Toolpath& tp) const override;
|
||||
[[nodiscard]] std::string epilogue(const Toolpath& tp) const override;
|
||||
[[nodiscard]] std::string format_gcode(const PathSegment& seg) const override;
|
||||
};
|
||||
|
||||
/// Siemens (Sinumerik) 控制器后处理器
|
||||
class SiemensPost : public PostProcessor {
|
||||
public:
|
||||
[[nodiscard]] std::string prologue(const Toolpath& tp) const override;
|
||||
[[nodiscard]] std::string epilogue(const Toolpath& tp) const override;
|
||||
[[nodiscard]] std::string format_gcode(const PathSegment& seg) const override;
|
||||
};
|
||||
|
||||
/// Heidenhain 控制器后处理器
|
||||
class HeidenhainPost : public PostProcessor {
|
||||
public:
|
||||
[[nodiscard]] std::string prologue(const Toolpath& tp) const override;
|
||||
[[nodiscard]] std::string epilogue(const Toolpath& tp) const override;
|
||||
[[nodiscard]] std::string format_gcode(const PathSegment& seg) const override;
|
||||
};
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// 加工策略函数
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// 层切粗加工刀路
|
||||
///
|
||||
/// 对 B-Rep 实体进行 Z 层切粗加工:
|
||||
/// 1. 计算模型的 Z 范围
|
||||
/// 2. 从安全高度开始,以 step_down 步距逐层往下切
|
||||
/// 3. 每层将模型轮廓投影到当前 Z 高度,偏移 stock_to_leave 生成刀路
|
||||
///
|
||||
/// @param body B-Rep 实体模型
|
||||
/// @param tool 使用的刀具
|
||||
/// @param params 粗加工参数
|
||||
/// @return 粗加工刀路
|
||||
///
|
||||
/// @ingroup core
|
||||
[[nodiscard]] Toolpath roughing_toolpath(
|
||||
const brep::BrepModel& body,
|
||||
const Tool& tool,
|
||||
const RoughingParams& params);
|
||||
|
||||
/// 精加工刀路
|
||||
///
|
||||
/// 对 B-Rep 实体生成精加工刀路,支持两种策略:
|
||||
/// - PARALLEL:等距平行线覆盖整个加工面
|
||||
/// - SPIRAL:从轮廓向内逐步偏移
|
||||
///
|
||||
/// @param body B-Rep 实体模型
|
||||
/// @param tool 使用的刀具
|
||||
/// @param params 精加工参数
|
||||
/// @param strategy 加工策略(PARALLEL 或 SPIRAL)
|
||||
/// @return 精加工刀路
|
||||
///
|
||||
/// @ingroup core
|
||||
[[nodiscard]] Toolpath finishing_toolpath(
|
||||
const brep::BrepModel& body,
|
||||
const Tool& tool,
|
||||
const FinishingParams& params,
|
||||
FinishingStrategy strategy = FinishingStrategy::PARALLEL);
|
||||
|
||||
/// 钻孔循环刀路
|
||||
///
|
||||
/// 对一组钻孔点生成指定钻孔循环的刀路。
|
||||
/// - G81:简单钻孔
|
||||
/// - G83:深孔啄钻(带 Q 参数)
|
||||
/// - G84:攻丝
|
||||
///
|
||||
/// @param points 钻孔点列表
|
||||
/// @param tool 使用的钻头/丝锥
|
||||
/// @param cycle 钻孔循环类型
|
||||
/// @param safe_z 安全高度 (mm)
|
||||
/// @param feed_rate 进给速度 (mm/min)
|
||||
/// @return 钻孔刀路
|
||||
///
|
||||
/// @ingroup core
|
||||
[[nodiscard]] Toolpath drilling_toolpath(
|
||||
const std::vector<DrillPoint>& points,
|
||||
const Tool& tool,
|
||||
DrillingCycle cycle = DrillingCycle::G81,
|
||||
double safe_z = 10.0,
|
||||
double feed_rate = 200.0);
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// 加工仿真
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
/// 加工仿真结果
|
||||
struct SimulationResult {
|
||||
mesh::HalfedgeMesh remaining_mesh; ///< 加工后剩余材料网格
|
||||
mesh::HalfedgeMesh removed_mesh; ///< 被切除材料网格
|
||||
double volume_removed = 0.0; ///< 切除体积 (mm³)
|
||||
double volume_remaining = 0.0; ///< 剩余体积 (mm³)
|
||||
int steps = 0; ///< 仿真步数
|
||||
};
|
||||
|
||||
/// 材料去除仿真
|
||||
///
|
||||
/// 给定毛坯 B-Rep 和刀路,模拟刀具沿刀路切割材料的过程,
|
||||
/// 输出剩余材料网格、切除材料网格和体积统计。
|
||||
///
|
||||
/// @param body 毛坯 B-Rep 实体
|
||||
/// @param toolpath 加工刀路
|
||||
/// @param tool 使用的刀具(用于确定切削截面)
|
||||
/// @return 仿真结果
|
||||
///
|
||||
/// @ingroup core
|
||||
[[nodiscard]] SimulationResult material_removal_simulation(
|
||||
const brep::BrepModel& body,
|
||||
const Toolpath& toolpath,
|
||||
const Tool& tool);
|
||||
|
||||
} // namespace vde::core
|
||||
Reference in New Issue
Block a user