Files
ViewDesignEngine/include/vde/brep/assembly_lod.h
T
茂之钳 6bc9db663e
CI / Build & Test (push) Failing after 33s
CI / Release Build (push) Failing after 39s
Build & Test / build-and-test (push) Has been cancelled
Build & Test / python-bindings (push) Has been cancelled
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
2026-07-26 21:19:38 +08:00

268 lines
9.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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