Files
envi-code/SourceCode/Code2026/CoreCommand/CollisionDetection.h
T
2026-09-28 15:28:50 +08:00

208 lines
4.9 KiB
C++

#pragma once
#include <vector>
#include "resource.h"
#include "xlistctrl.h"
#include <algorithm> // 包含 std::min, std::max
namespace CDA
{
template <typename T>
static bool isKindOf(const AcDbObjectId &id)
{
if (!id.isValid()) return false;
AcRxClass *pIdClass = id.objectClass();
if (pIdClass == NULL) return false;
return pIdClass->isDerivedFrom( T::desc());
}
template <typename T>
static bool isSameOf(const AcDbObjectId &id)
{
if (!id.isValid()) return false;
return id.objectClass() == T::desc();
}
struct AABB
{
AABB();
AABB(const AcDbExtents &ext);
// 辅助方法:合并另一个 AABB
void grow(const AABB &other);
void set(const AcDbExtents &ext);
// 辅助方法:计算包围盒的中心点 (用于拆分节点)
AcGePoint3d centroid() const;
// 辅助方法:获取最长轴 (0=X, 1=Y, 2=Z)
int getLongestAxis() const;
bool intersects(const AABB &other) const;
AcGePoint3d m_minPt;
AcGePoint3d m_maxPt;
};
struct EntityProxy
{
bool set(const AcDbObjectId &id);
AcDbObjectId m_entityId;
// 彻底抛弃 m_entPtr 成员,避免悬空指针和内存灾难
AABB m_box;
AcGePoint3d m_centroid;
};
// 使用 alignas 确保内存对齐 (可选,但对现代 CPU 缓存极其友好)
struct BVHNode
{
AABB box;
int leftFirst;
int primitiveCount;
bool isLeaf() const { return primitiveCount > 0; }
};
class BVHTree
{
public:
// 外部世界只需要调用这一个接口
void Build(const AcDbObjectIdArray &ar);
// 给定一个查询的包围盒,返回所有与它发生包围盒碰撞的实体 ID
void GetIntersections(const AABB &queryBox, std::vector<AcDbObjectId> &hitIds) const;
void GetIntersections(AcDbObjectId &id, std::vector<AcDbObjectId> &hitIds) const;
// 两两自检接口
void GetAllIntersections(std::vector< std::pair<AcDbObjectId, AcDbObjectId> > &hitPairs) const;
// 供后续碰撞查询使用的只读接口
const std::vector<BVHNode> &GetNodes() const { return m_bvhNodes; }
const std::vector<EntityProxy> &GetEntities() const { return m_allEntities; }
private:
std::vector<EntityProxy> m_allEntities;
std::vector<BVHNode> m_bvhNodes;
// C++98 的仿函数作为私有嵌套结构体,保持命名空间干净
struct PartitionPredicate
{
int m_axis;
double m_splitPos;
PartitionPredicate(int axis, double splitPos): m_axis(axis), m_splitPos(splitPos) {}
bool operator()(const EntityProxy &proxy) const
{
double pos = 0.0;
if (m_axis == 0)
pos = proxy.m_centroid.x;
else if (m_axis == 1)
pos = proxy.m_centroid.y;
else
pos = proxy.m_centroid.z;
return pos < m_splitPos;
}
};
// 内部递归建树函数,直接操作类成员变量
void BuildNode(int nodeIdx, int entityOffset, int entityCount);
// 核心的双树递归遍历函数
void CollideNodes(int nodeIdxA, int nodeIdxB, std::vector< std::pair<AcDbObjectId, AcDbObjectId> > &hitPairs) const;
};
}
class CCollisionDetectionDlg: public CDialog
{
public:
typedef std::pair<AcDbObjectId, AcDbObjectId> IDPair;
typedef std::vector<IDPair> IDPairs;
struct SortContext
{
int m_nColumn;
bool m_bAscending;
};
struct DataContext
{
DataContext(int &idx, LPCTSTR name1, LPCTSTR sys1, LPCTSTR name2, LPCTSTR sys2)
: m_nIdx(idx)
, m_sName1(name1)
, m_sName2(name2)
, m_sSys1(sys1)
, m_sSys2(sys2) { }
// 此数据位于m_idPairs的位置,同时,它也是m_CdFlags的位置
int m_nIdx;
CString m_sName1, m_sName2, m_sSys1, m_sSys2;
};
DECLARE_DYNAMIC(CCollisionDetectionDlg)
public:
CCollisionDetectionDlg(IDPairs &pairs, CWnd* pParent = NULL);
virtual ~CCollisionDetectionDlg();
enum { IDD = IDD_CD_DLG };
protected:
virtual void DoDataExchange(CDataExchange* pDX);
virtual BOOL OnInitDialog();
virtual void PostNcDestroy();
virtual void OnCancel();
void refreshList();
void initColumns();
void layoutControls(const int &cx, const int &cy);
void eraseFlag(AcDbObjectId &id);
AcDbObjectId createFlag(const AcDbObjectId &id1, const AcDbObjectId &id2);
void clearDatas();
DECLARE_MESSAGE_MAP()
afx_msg void OnClose();
afx_msg void OnOK();
afx_msg void OnRefreshBtnClicked();
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI);
afx_msg LRESULT OnCheckBoxClicked(WPARAM, LPARAM);
afx_msg LRESULT OnHeaderMouseClicked(WPARAM, LPARAM);
afx_msg void OnNMDblclkList(NMHDR* pNMHDR, LRESULT* pResult);
private:
CXListCtrl m_wndList;
// 对话框的最小尺寸
CSize m_szMinDlgSize;
// 碰撞实体记录
// 不要操作这个变量,列表的item关联了里面元素的地址
IDPairs m_idPairs;
// 标识碰撞点的球体id,数量与 m_idPairs的数量一致
// 与m_idPairs一起初始化,初始化后数量固定
std::vector<AcDbObjectId> m_CdFlags;
// 排序的列号,由于第一列带checkbox,所以 列号>1
int m_nSortCol;
// 升序还是降序
bool m_bAscending;
};