6bc9db663e
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
268 lines
9.3 KiB
C++
268 lines
9.3 KiB
C++
#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
|