feat(v4.5): draft analysis + incremental mesh + kinematic chain solvers
M1 — Draft Analysis (拔模分析): - draft_angle(face, pull_dir): compute draft angle from NURBS surface normal - analyze_draft(body, pull_dir, min_angle): full-model analysis with face classification - DraftFaceType: Positive/Negative/ZeroDraft/Undercut with area-weighted stats - draft_report(): human-readable moldability report - create_draft_face / apply_draft: face rotation stubs (needs mutable surface access) M2 — Incremental Mesh (增量网格): - IncrementalMesher: face_id → mesh fragment mapping with dirty tracking - invalidate_face / rebuild_dirty / rebuild_all: targeted remeshing - merged_mesh(): combine clean face meshes into single HalfedgeMesh - Cache statistics: hit rate + memory estimation M3 — Kinematic Chain (运动链求解): - FourBarLinkage: Grashof classification + Freudenstein position solver - GearPair/GearTrain: ratio-based transmission solver with multi-stage support - CamFollower: 5 motion types (Dwell/CV/SHM/Cycloidal/3-4-5 Polynomial) - Full-cycle analysis for all solvers 7 new files, ~1400 lines of header + implementation
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file draft_analysis.h
|
||||
* @brief 拔模分析
|
||||
*
|
||||
* 模具设计中的关键分析工具:
|
||||
* - 计算每个面相对于拔模方向的拔模角
|
||||
* - 分类面:正拔模 / 负拔模 / 零拔模 / 倒扣
|
||||
* - 生成拔模面
|
||||
*
|
||||
* @ingroup brep
|
||||
*/
|
||||
|
||||
#include "vde/brep/brep.h"
|
||||
#include "vde/core/point.h"
|
||||
#include "vde/core/aabb.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace vde::brep {
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// Draft Result Types
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
/// 拔模面分类
|
||||
enum class DraftFaceType {
|
||||
Positive, ///< 正拔模:角度 > min_draft_angle
|
||||
Negative, ///< 负拔模:角度 < -min_draft_angle
|
||||
ZeroDraft, ///< 零拔模:|角度| ≤ min_draft_angle(平行于拔模方向)
|
||||
Undercut, ///< 倒扣:面法线与拔模方向法向分量不一致(侧面障碍)
|
||||
};
|
||||
|
||||
/// 单个面的拔模分析结果
|
||||
struct DraftFaceResult {
|
||||
int face_id = -1; ///< 面ID
|
||||
double draft_angle = 0.0; ///< 拔模角(弧度),正值 = 向外张开
|
||||
DraftFaceType classification = DraftFaceType::ZeroDraft;
|
||||
core::Vector3D face_normal; ///< 面法线(近似)
|
||||
double face_area = 0.0; ///< 面面积(用于加权统计)
|
||||
};
|
||||
|
||||
/// 全模型拔模分析结果
|
||||
struct DraftAnalysisResult {
|
||||
/// 拔模方向(输入)
|
||||
core::Vector3D pull_direction{0, 0, 1};
|
||||
|
||||
/// 最小允许拔模角(弧度)
|
||||
double min_draft_angle = 0.0;
|
||||
|
||||
/// 每个面的拔模分析
|
||||
std::vector<DraftFaceResult> faces;
|
||||
|
||||
// ─── 汇总统计 ───
|
||||
|
||||
/// 面分类统计
|
||||
int positive_count = 0;
|
||||
int negative_count = 0;
|
||||
int zero_draft_count = 0;
|
||||
int undercut_count = 0;
|
||||
|
||||
/// 面积加权平均拔模角
|
||||
double area_weighted_angle = 0.0;
|
||||
|
||||
/// 最小/最大拔模角(正拔模面)
|
||||
double min_positive_angle = std::numeric_limits<double>::max();
|
||||
double max_positive_angle = -std::numeric_limits<double>::max();
|
||||
|
||||
/// 是否有倒扣(模具无法脱出)
|
||||
[[nodiscard]] bool has_undercut() const { return undercut_count > 0; }
|
||||
|
||||
/// 是否全部可脱模
|
||||
[[nodiscard]] bool is_moldable() const { return undercut_count == 0; }
|
||||
|
||||
/// 拔模角分布:角度区间 → 面数量(用于热力图)
|
||||
[[nodiscard]] std::map<int, int> angle_distribution(int bins = 18) const;
|
||||
};
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// Draft Analysis Functions
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* @brief 计算单个面的近似拔模角
|
||||
*
|
||||
* 拔模角 = π/2 - arccos(|n·d|),其中 n 为面法线,d 为拔模方向。
|
||||
* 正值表示面沿拔模方向向外张开。
|
||||
*
|
||||
* @param body B-Rep 实体
|
||||
* @param face_id 面ID
|
||||
* @param pull_dir 拔模方向(会被归一化)
|
||||
* @return 拔模角(弧度),范围 [-π/2, π/2]
|
||||
*/
|
||||
[[nodiscard]] double draft_angle(const BrepModel& body, int face_id,
|
||||
const core::Vector3D& pull_dir);
|
||||
|
||||
/**
|
||||
* @brief 全模型拔模分析
|
||||
*
|
||||
* 对 B-Rep 实体的每个面计算拔模角并分类。
|
||||
*
|
||||
* @param body B-Rep 实体
|
||||
* @param pull_dir 拔模方向
|
||||
* @param min_draft_angle 最小允许拔模角(弧度),默认 1° (≈0.0175 rad)
|
||||
* @return 完整分析结果
|
||||
*/
|
||||
[[nodiscard]] DraftAnalysisResult analyze_draft(const BrepModel& body,
|
||||
const core::Vector3D& pull_dir,
|
||||
double min_draft_angle = 0.0174533);
|
||||
|
||||
/**
|
||||
* @brief 创建拔模面
|
||||
*
|
||||
* 沿拔模方向偏转面,使其达到指定拔模角度。
|
||||
* (基础实现:沿边界旋转面法线)
|
||||
*
|
||||
* @param body B-Rep 实体(会被修改)
|
||||
* @param face_id 面ID
|
||||
* @param pull_dir 拔模方向
|
||||
* @param angle 目标拔模角(弧度,正值 = 向外)
|
||||
* @return 是否成功
|
||||
*/
|
||||
[[nodiscard]] bool create_draft_face(BrepModel& body, int face_id,
|
||||
const core::Vector3D& pull_dir, double angle);
|
||||
|
||||
/**
|
||||
* @brief 批量应用拔模
|
||||
*
|
||||
* 对指定面列表创建拔模面。
|
||||
*
|
||||
* @param body B-Rep 实体(会被修改)
|
||||
* @param face_ids 面ID列表
|
||||
* @param pull_dir 拔模方向
|
||||
* @param angle 目标拔模角(弧度)
|
||||
* @return 成功应用拔模的面数量
|
||||
*/
|
||||
[[nodiscard]] int apply_draft(BrepModel& body,
|
||||
const std::vector<int>& face_ids,
|
||||
const core::Vector3D& pull_dir, double angle);
|
||||
|
||||
/**
|
||||
* @brief 拔模分析报告(人类可读字符串)
|
||||
*
|
||||
* @param result 分析结果
|
||||
* @return 格式化报告
|
||||
*/
|
||||
[[nodiscard]] std::string draft_report(const DraftAnalysisResult& result);
|
||||
|
||||
} // namespace vde::brep
|
||||
@@ -0,0 +1,112 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file incremental_mesh.h
|
||||
* @brief 增量网格生成
|
||||
*
|
||||
* B-Rep 参数修改后,仅重建受影响面的 tessellation,而非全量重算。
|
||||
* 与 IncrementalUpdateEngine 集成,维护面级网格缓存。
|
||||
*
|
||||
* @ingroup brep
|
||||
*/
|
||||
|
||||
#include "vde/brep/brep.h"
|
||||
#include "vde/mesh/halfedge_mesh.h"
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace vde::brep {
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// IncrementalMesher
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* @brief 增量网格生成器
|
||||
*
|
||||
* 维护 face_id → 三角网格片段的映射。
|
||||
* 参数修改时仅标脏受影响面,重建时只重新 tessellate 脏面。
|
||||
*
|
||||
* @ingroup brep
|
||||
*/
|
||||
class IncrementalMesher {
|
||||
public:
|
||||
/// 网格片段:单个面的三角网格
|
||||
struct FaceMesh {
|
||||
std::vector<core::Point3D> vertices;
|
||||
std::vector<std::array<int, 3>> triangles;
|
||||
double tessellation_deflection = 0.01;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 标脏指定面(参数已修改,需要重新 tessellate)
|
||||
*
|
||||
* @param face_id 面ID
|
||||
*/
|
||||
void invalidate_face(int face_id);
|
||||
|
||||
/**
|
||||
* @brief 增量重建:仅重新 tessellate 脏面
|
||||
*
|
||||
* @param body B-Rep 实体(提供几何数据)
|
||||
* @param deflection tessellation 精度
|
||||
* @return 重建的面数量
|
||||
*/
|
||||
[[nodiscard]] int rebuild_dirty(const BrepModel& body, double deflection = 0.01);
|
||||
|
||||
/**
|
||||
* @brief 全量重建(清除所有缓存后重建)
|
||||
*
|
||||
* @param body B-Rep 实体
|
||||
* @param deflection tessellation 精度
|
||||
* @return 重建的面数量
|
||||
*/
|
||||
[[nodiscard]] int rebuild_all(const BrepModel& body, double deflection = 0.01);
|
||||
|
||||
/**
|
||||
* @brief 获取单个面的缓存网格
|
||||
*
|
||||
* @param face_id 面ID
|
||||
* @return 缓存网格指针,脏面返回 nullptr
|
||||
*/
|
||||
[[nodiscard]] const FaceMesh* get_mesh(int face_id) const;
|
||||
|
||||
/**
|
||||
* @brief 获取完整网格(合并所有已缓存面网格)
|
||||
*
|
||||
* 只包含非脏面的缓存数据。
|
||||
*
|
||||
* @return 合并后的完整网格
|
||||
*/
|
||||
[[nodiscard]] mesh::HalfedgeMesh merged_mesh() const;
|
||||
|
||||
/// 清除所有缓存
|
||||
void clear_all();
|
||||
|
||||
/// 统计
|
||||
[[nodiscard]] int dirty_count() const { return static_cast<int>(dirty_set_.size()); }
|
||||
[[nodiscard]] int total_faces() const { return static_cast<int>(meshes_.size()); }
|
||||
[[nodiscard]] int cache_hits() const { return cache_hits_; }
|
||||
[[nodiscard]] int cache_misses() const { return cache_misses_; }
|
||||
[[nodiscard]] double hit_rate() const;
|
||||
|
||||
/// 估计缓存占用内存(字节)
|
||||
[[nodiscard]] size_t memory_estimate() const;
|
||||
|
||||
private:
|
||||
std::unordered_map<int, FaceMesh> meshes_; ///< face_id → cached mesh
|
||||
std::unordered_set<int> dirty_set_; ///< 脏面集合
|
||||
int cache_hits_ = 0;
|
||||
int cache_misses_ = 0;
|
||||
|
||||
/// Tessellate a single face of the BrepModel
|
||||
[[nodiscard]] FaceMesh tessellate_face(const BrepModel& body, int face_id,
|
||||
double deflection) const;
|
||||
|
||||
/// Merge vertex arrays from multiple face meshes into one HalfedgeMesh
|
||||
[[nodiscard]] mesh::HalfedgeMesh merge_face_meshes(
|
||||
const std::vector<const FaceMesh*>& meshes) const;
|
||||
};
|
||||
|
||||
} // namespace vde::brep
|
||||
@@ -0,0 +1,194 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file kinematic_chain.h
|
||||
* @brief 运动链求解器
|
||||
*
|
||||
* 经典机构学求解器:四连杆、齿轮传动、凸轮机构。
|
||||
* 扩展 v4.0 运动仿真模块的机构学能力。
|
||||
*
|
||||
* @ingroup brep
|
||||
*/
|
||||
|
||||
#include "vde/core/point.h"
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
namespace vde::brep {
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 四连杆机构 (Four-Bar Linkage)
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
/// 四杆机构类型(按 Grashof 条件分类)
|
||||
enum class FourBarType {
|
||||
CrankRocker, ///< 曲柄摇杆:最短杆为曲柄,旋转完整 360°
|
||||
DoubleCrank, ///< 双曲柄:最短杆为机架
|
||||
DoubleRocker, ///< 双摇杆:最短杆为连杆
|
||||
ChangePoint, ///< 变点机构:Grashof 等号成立
|
||||
NonGrashof, ///< 非 Grashof:无杆可完整旋转
|
||||
};
|
||||
|
||||
/// 四杆机构定义
|
||||
struct FourBarLinkage {
|
||||
double ground = 1.0; ///< 机架长度(固定杆)
|
||||
double crank = 1.0; ///< 曲柄(输入杆)长度
|
||||
double coupler = 1.0; ///< 连杆长度
|
||||
double rocker = 1.0; ///< 摇杆(输出杆)长度
|
||||
|
||||
/// 按 Grashof 条件分类
|
||||
[[nodiscard]] FourBarType classify() const;
|
||||
|
||||
/// 检查是否为 Grashof 机构(至少一杆可完整旋转)
|
||||
[[nodiscard]] bool is_grashof() const;
|
||||
};
|
||||
|
||||
/// 四杆机构求解结果(单输入角度)
|
||||
struct FourBarSolution {
|
||||
double input_angle = 0.0; ///< 输入角(弧度)
|
||||
double output_angle = 0.0; ///< 输出角(弧度)
|
||||
double coupler_angle = 0.0; ///< 连杆角(弧度)
|
||||
double transmission_angle = 0.0; ///< 传动角(弧度)
|
||||
bool valid = false; ///< 解是否有效
|
||||
bool dead_point = false; ///< 是否处于死点
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 四杆机构位置求解
|
||||
*
|
||||
* 给定输入角度,计算输出角度和传动角。
|
||||
* 使用 Freudenstein 方程求解。
|
||||
*
|
||||
* @param linkage 四杆机构参数
|
||||
* @param input_angle 输入角(弧度),曲柄与机架的夹角
|
||||
* @param branch 分支选择:0 = 开式, 1 = 闭式
|
||||
* @return 求解结果
|
||||
*/
|
||||
[[nodiscard]] FourBarSolution solve_fourbar(
|
||||
const FourBarLinkage& linkage, double input_angle, int branch = 0);
|
||||
|
||||
/**
|
||||
* @brief 四杆机构运动分析(全周期)
|
||||
*
|
||||
* @param linkage 四杆机构参数
|
||||
* @param steps 采样步数
|
||||
* @return 各角度位置的解序列
|
||||
*/
|
||||
[[nodiscard]] std::vector<FourBarSolution> analyze_fourbar(
|
||||
const FourBarLinkage& linkage, int steps = 360);
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 齿轮传动 (Gear Train)
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
/// 齿轮副定义
|
||||
struct GearPair {
|
||||
int teeth_driver = 20; ///< 主动轮齿数
|
||||
int teeth_driven = 40; ///< 从动轮齿数
|
||||
double module = 1.0; ///< 模数 (mm)
|
||||
double pressure_angle = 20.0 * M_PI / 180.0; ///< 压力角(弧度,默认 20°)
|
||||
double center_distance = 0.0; ///< 中心距(0 = 自动计算)
|
||||
|
||||
/// 传动比 = driven_teeth / driver_teeth
|
||||
[[nodiscard]] double ratio() const {
|
||||
return static_cast<double>(teeth_driven) / teeth_driven;
|
||||
}
|
||||
|
||||
/// 计算中心距(若未指定)
|
||||
[[nodiscard]] double compute_center_distance() const {
|
||||
if (center_distance > 0) return center_distance;
|
||||
return module * (teeth_driver + teeth_driven) / 2.0;
|
||||
}
|
||||
};
|
||||
|
||||
/// 齿轮传动结果
|
||||
struct GearSolution {
|
||||
double driver_angle = 0.0; ///< 主动轮角度(弧度)
|
||||
double driven_angle = 0.0; ///< 从动轮角度(弧度)
|
||||
double angular_velocity_ratio = 0.0; ///< 角速度比
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 求解齿轮传动
|
||||
*
|
||||
* @param gear 齿轮副参数
|
||||
* @param driver_angle 主动轮转角(弧度)
|
||||
* @return 传动结果
|
||||
*/
|
||||
[[nodiscard]] GearSolution solve_gear(
|
||||
const GearPair& gear, double driver_angle);
|
||||
|
||||
/**
|
||||
* @brief 齿轮系求解(多级齿轮)
|
||||
*
|
||||
* @param stages 各级齿轮副(按传动顺序)
|
||||
* @param input_angle 第一级输入角
|
||||
* @return 各级输出角度
|
||||
*/
|
||||
[[nodiscard]] std::vector<GearSolution> solve_gear_train(
|
||||
const std::vector<GearPair>& stages, double input_angle);
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 凸轮机构 (Cam-Follower)
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
/// 从动件运动规律类型
|
||||
enum class CamMotionType {
|
||||
Dwell, ///< 停歇(无运动)
|
||||
ConstantVelocity, ///< 等速
|
||||
SimpleHarmonic, ///< 简谐运动
|
||||
Cycloidal, ///< 摆线运动
|
||||
Polynomial345, ///< 3-4-5 多项式
|
||||
};
|
||||
|
||||
/// 凸轮运动段定义
|
||||
struct CamSegment {
|
||||
double start_angle = 0.0; ///< 起始凸轮角(弧度)
|
||||
double end_angle = 0.0; ///< 终止凸轮角(弧度)
|
||||
double start_lift = 0.0; ///< 起始升程
|
||||
double end_lift = 0.0; ///< 终止升程
|
||||
CamMotionType motion = CamMotionType::Dwell;
|
||||
};
|
||||
|
||||
/// 凸轮-从动件系统
|
||||
struct CamFollowerSystem {
|
||||
double base_radius = 20.0; ///< 基圆半径
|
||||
std::vector<CamSegment> segments; ///< 运动段序列
|
||||
double follower_offset = 0.0; ///< 从动件偏距(对心 = 0)
|
||||
|
||||
/// 总升程
|
||||
[[nodiscard]] double total_lift() const;
|
||||
};
|
||||
|
||||
/// 从动件瞬时状态
|
||||
struct FollowerState {
|
||||
double cam_angle = 0.0; ///< 凸轮转角(弧度)
|
||||
double displacement = 0.0; ///< 从动件位移
|
||||
double velocity = 0.0; ///< 从动件速度(mm/rad)
|
||||
double acceleration = 0.0; ///< 从动件加速度(mm/rad²)
|
||||
double pressure_angle = 0.0; ///< 压力角(弧度)
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 凸轮机构求解
|
||||
*
|
||||
* 给定凸轮角度,计算从动件位移/速度/加速度。
|
||||
*
|
||||
* @param cam 凸轮-从动件系统
|
||||
* @param cam_angle 凸轮转角(弧度)
|
||||
* @return 从动件状态
|
||||
*/
|
||||
[[nodiscard]] FollowerState solve_cam(
|
||||
const CamFollowerSystem& cam, double cam_angle);
|
||||
|
||||
/**
|
||||
* @brief 凸轮运动全周期分析
|
||||
*
|
||||
* @param cam 凸轮-从动件系统
|
||||
* @param steps 采样步数
|
||||
* @return 全周期从动件状态序列
|
||||
*/
|
||||
[[nodiscard]] std::vector<FollowerState> analyze_cam(
|
||||
const CamFollowerSystem& cam, int steps = 360);
|
||||
|
||||
} // namespace vde::brep
|
||||
Reference in New Issue
Block a user