Files
茂之钳 fcf25e561d feat(v4.4): complete remaining v4.1-v4.4 features + precision tolerance + Euler ops
v4.1 收尾:
- IncrementalUpdateEngine: dirty flag propagation, cache invalidation
- LargeAssembly: InstanceCache, assembly instancing
- STEP import: robust/graceful parsing with skip tracking

v4.3 分析工具:
- Mass properties (volume, centroid, inertia tensor)
- Clearance analysis, wall thickness analysis
- Enhanced drawing: hidden-line removal, offset sections, BOM
- DXF import (LINE/CIRCLE/ARC/LWPOLYLINE/SPLINE → B-Rep extrusion)

v4.4 地基加固:
- ToleranceChain: RSS cumulative tolerance propagation (7 tests)
- Euler operations: MEV/KEV/MEF/KEF/KEMR/MEKR (20 tests)
- Replace hardcoded tolerances with ToleranceConfig in validate
- Fix incremental_update test API mismatch (15/15 pass on Linux)

Docs:
- v4.1-v4.4 development plans + roadmap updated
- v4.4 marked complete on Linux

30 files, +3424/-210
2026-07-26 16:49:37 +08:00

228 lines
7.4 KiB
C++
Raw Permalink 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 euler_op.h
* @brief 欧拉操作 — B-Rep 拓扑编辑原语
*
* 实现 Baumgart-Mäntylä 欧拉操作,是 B-Rep 底层拓扑编辑的标准原语集合。
* 每个操作保持欧拉-庞加莱公式不变:
* V - E + F - (L - F) = 2(S - H) + R
*
* 其中 V=顶点数, E=边数, F=面数, L=环数, S=壳数, H=贯穿孔数, R=内环数
*
* ## 操作清单
*
* | 操作 | 含义 | ΔV | ΔE | ΔF | ΔL |
* |-------|------|----|----|----|----|
* | MEV | 边上插入顶点 | +1 | +1 | 0 | 0 |
* | KEV | 移除边上顶点 | -1 | -1 | 0 | 0 |
* | MEF | 面内建边分裂面 | 0 | +1 | +1 | +1 |
* | KEF | 删除边合并面 | 0 | -1 | -1 | -1 |
* | KEMR | 删边建内环 | 0 | -1 | 0 | 0 |
* | MEKR | 建边删内环 | 0 | +1 | 0 | 0 |
*
* 六个操作涵盖所有拓扑编辑需求。对偶操作(MEV↔KEV, MEF↔KEF, KEMR↔MEKR
* 互为逆操作。
*
* @ingroup brep
*/
#include "vde/brep/brep.h"
#include <string>
#include <vector>
#include <optional>
namespace vde::brep {
// ═══════════════════════════════════════════════════════════
// Euler operation result
// ═══════════════════════════════════════════════════════════
/**
* @brief 欧拉操作结果
*
* 记录操作创建和删除的拓扑元素 ID。
* 成功时 created/deleted 字段根据操作类型填充。
* 失败时 error 字段包含错误信息。
*/
struct EulerOpResult {
bool success = false;
std::string error;
// Created elements (操作新建的)
int new_vertex = -1;
int new_edge = -1;
int new_edge_2 = -1;
int new_face = -1;
int new_face_2 = -1;
int new_loop = -1;
int new_loop_2 = -1;
// Deleted elements (操作移除的,保留供查询)
int deleted_vertex = -1;
int deleted_edge = -1;
int deleted_face = -1;
};
// ═══════════════════════════════════════════════════════════
// EulerOp — 欧拉操作引擎
// ═══════════════════════════════════════════════════════════
/**
* @brief 欧拉操作引擎
*
* 提供六个核心欧拉操作的静态方法。
* 所有操作在 BrepModel 上就地执行,保持拓扑一致性。
*
* 使用模式:欧拉操作后应调用 euler_poincare() 验证公式不变。
*/
class EulerOp {
public:
// ─── 操作 1: MEV — Make Edge Vertex ───
/**
* @brief 在边上插入顶点,将边分裂为两条边
*
* @code
* Before: V1 ────E──── V2
* After: V1 ─E1─ Vnew ─E2─ V2
* @endcode
*
* @param body 目标 B-Rep 模型
* @param edge_idx 要分裂的边索引
* @param t 插入位置参数 (0 < t < 1)0=起点 1=终点
* @return 操作结果(含 new_vertex, new_edge=E1, new_edge_2=E2
*/
static EulerOpResult mev(BrepModel& body, int edge_idx, double t);
// ─── 操作 2: KEV — Kill Edge Vertex ───
/**
* @brief 移除顶点并合并两侧边
*
* 逆操作:MEV。
*
* @code
* Before: Va ─E1─ Vb ─E2─ Vc
* After: Va ────Enew──── Vc
* @endcode
*
* 要求 E1 和 E2 共线,Vb 的度为 2。
*
* @param body 目标 B-Rep 模型
* @param vertex_idx 要移除的顶点索引
* @return 操作结果(含 new_edge=Enew, deleted_vertex=Vb
*/
static EulerOpResult kev(BrepModel& body, int vertex_idx);
// ─── 操作 3: MEF — Make Edge Face ───
/**
* @brief 在面内建边,将面分裂为两个面
*
* @code
* Before: ┌─────────────┐
* After: ├──────┬──────┤ (新边垂直分割面)
* @endcode
*
* @param body 目标 B-Rep 模型
* @param face_idx 要分裂的面索引
* @param va_idx 新边起点顶点索引(必须在面内)
* @param vb_idx 新边终点顶点索引(必须在面内)
* @return 操作结果(含 new_edge, new_face, new_face_2
*/
static EulerOpResult mef(BrepModel& body, int face_idx, int va_idx, int vb_idx);
// ─── 操作 4: KEF — Kill Edge Face ───
/**
* @brief 删除边并合并两侧面
*
* 逆操作:MEF。
*
* @code
* Before: Fa │ E │ Fb (E 两侧是不同面)
* After: Fa+Fb merged
* @endcode
*
* 要求边的两个相邻面共面。
*
* @param body 目标 B-Rep 模型
* @param edge_idx 要删除的边索引
* @return 操作结果(含 new_face, deleted_edge, deleted_face
*/
static EulerOpResult kef(BrepModel& body, int edge_idx);
// ─── 操作 5: KEMR — Kill Edge Make Ring ───
/**
* @brief 删除内环上的边,合并内环
*
* @code
* Before: ┌─────┐ 内环 ┌──┐
* After: ┌──────┐ (内环扩大)
* @endcode
*
* 要求边两侧是同一个面(即边在内环上)。
*
* @param body 目标 B-Rep 模型
* @param edge_idx 要删除的边索引(必须在面的内环上)
* @return 操作结果
*/
static EulerOpResult kemr(BrepModel& body, int edge_idx);
// ─── 操作 6: MEKR — Make Edge Kill Ring ───
/**
* @brief 在内环上建边,分割内环
*
* 逆操作:KEMR。
*
* @param body 目标 B-Rep 模型
* @param face_idx 包含内环的面
* @param va_idx 内环上的起点顶点
* @param vb_idx 内环上的终点顶点(同内环)
* @return 操作结果(含 new_edge
*/
static EulerOpResult mekr(BrepModel& body, int face_idx, int va_idx, int vb_idx);
// ─── 验证 ───
/**
* @brief 计算欧拉-庞加莱特征数
*
* EP = V - E + F - (L - F) = 2(S - H) + R
*
* 对于简单封闭实体(S=1, H=0, R=0):EP = 2
*
* @return 特征数
*/
[[nodiscard]] static int euler_poincare(const BrepModel& body);
/**
* @brief 验证模型满足欧拉-庞加莱公式
*
* 计算 EP 并与期望值比较。对简单实体期望 EP=2。
*
* @return true 如果公式成立
*/
[[nodiscard]] static bool verify_euler(const BrepModel& body);
/// 计算顶点度(相连边数)
static int vertex_degree(const BrepModel& body, int vertex_idx);
private:
/// 获取顶点所在面的边界环索引(-1 表示不在任何环中)
static int find_vertex_in_loop(const BrepModel& body,
int vertex_idx, const TopoLoop& loop);
/// 在环中查找顶点出现的位置
static std::vector<int> find_vertex_positions_in_loop(
const BrepModel& body, int vertex_idx, const TopoLoop& loop);
/// 重建壳和体以引用新的面映射
static void rebuild_shells_with_new_faces(BrepModel& body,
const std::map<int, int>& face_map);
};
} // namespace vde::brep