问题描述:
在中望 CAD 二次开发过程中,三维实体的包络框经常被用于各种几何分析和逻辑判断,例如:
实体之间的空间碰撞检测
模型范围裁剪
可视区域过滤
三维构件位置自动排布等
一般情况下,我们可能会直接调用 ZcDbEntity::getGeomExtents() 接口来获取实体的包络框信息,但在实际项目中会发现:
该接口返回的包络框往往是基于实体几何外接范围的近似结果,对于圆角、曲面或复杂三维实体来说,其精度并不能完全满足高精度计算或精细化判断的需求。
解决方案:
针对上述问题,中望 CAD 在三维运算模块中,内部提供了一套更高精度的包络框计算接口,可以用于获取更接近真实几何形状的三维包络框,使用内部接口zcdbGetModelerEntityExactExtents。
#include "stdafx.h"
#include "tchar.h"
#include <aced.h>
#include <rxregsvc.h>
#include "dbapserv.h"
#include "dbsymtb.h"
#include "geassign.h"
#include "adscodes.h"
#include "dbregion.h"
#include "dbmain.h"
#include "dbobjptr.h"
#include "dbsol3d.h"
#include <chrono>
#define TIME_REOCRD(...) \
do \
{ \
auto start = std::chrono::steady_clock::now(); \
__VA_ARGS__ \
auto end = std::chrono::steady_clock::now(); \
acutPrintf(ACRX_T("spend time : %.3lf ms."), std::chrono::duration<double>(end - start).count() * 1000.0); \
} while (false)
void initApp();
void unloadApp();
/*
函数原型: Zcad::ErrorStatus zcdbGetModelerEntityExactExtents(ZcDbEntity*, AcDbExtents&);
模块:该函数由ZwDataBase.dll模块导出,函数名zcdbGetModelerEntityExactExtents
输入:ZcDbEntity目前支持以Modeler建模的实体ZcDbRegion/AcDb3dSolid/ZcDbBody/ZcDbSurface
输出: AcDbExtents输出该三维实体的精确包围盒
返回值: Zcad::ErrorStatus错误码,仅在返回Zcad::eOk时包围盒有效
*/
struct GetModelerExactExtentFunc
{
using PROC = Zcad::ErrorStatus(*)(ZcDbEntity*, AcDbExtents&);
GetModelerExactExtentFunc()
{
init();
}
void init()
{
if (m_proc)
{
return;
}
HMODULE hMoudle = ::GetModuleHandle(TEXT("ZwDataBase.dll"));
if (NULL == hMoudle)
{
return;
}
m_proc = (PROC)::GetProcAddress(hMoudle, "zcdbGetModelerEntityExactExtents");
}
Zcad::ErrorStatus operator()(ZcDbEntity* pEntity, AcDbExtents& extent)
{
return m_proc(pEntity, extent);
}
operator bool() const { return nullptr != m_proc; }
PROC m_proc = nullptr;
};
/*
用于精确计算region/3dsolid/surface/body的仿函数
*/
GetModelerExactExtentFunc gsGetModelerEntExactExtent;
/*
将获取的实体加入数据库
*/
void appendToDb(AcDbEntity* pEntity)
{
if (!pEntity)
{
return;
}
ZcDbDatabase* db = acdbHostApplicationServices()->workingDatabase();
if (!db)
{
return;
}
AcDbBlockTable* pBT = nullptr;
db->getBlockTable(pBT, AcDb::kForWrite);
AcDbObjectId objectId;
pBT->getAt(ACDB_MODEL_SPACE, objectId);
pBT->close();
if (objectId.isNull())
{
return;
}
AcDbBlockTableRecord* pBTR = nullptr;
acdbOpenObject(pBTR, objectId, AcDb::kForWrite);
pBTR->appendZcDbEntity(pEntity);
pBTR->close();
}
/*
交互获取一个实体
*/
template<class T>
ZcDbObjectPointer<T> acuqireEnt(ZcDb::OpenMode mode = ZcDb::kForRead)
{
ads_name name;
acedSSGet(NULL, NULL, NULL, NULL, name);
int len = 0;
acedSSLength(name, &len);
if (len != 1)
{
return nullptr;
}
ads_name ent;
acedSSName(name, 0, ent);
AcDbObjectId objectId;
acdbGetObjectId(objectId, ent);
return ZcDbObjectPointer<T>(objectId, mode);
}
/*
绘制包围盒
*/
void drawExtentBox(const AcDbExtents& extent)
{
const auto& minPoint = extent.minPoint();
const auto& maxPoint = extent.maxPoint();
const auto offVec = maxPoint - minPoint;
const auto midOff = minPoint.asVector() + offVec / 2.0;
AcDb3dSolid* box = new AcDb3dSolid;
box->createBox(offVec.x, offVec.y, offVec.z);
box->transformBy(ZcGeMatrix3d::translation(midOff));
appendToDb(box);
box->close();
}
/*
给交互选择的实体进行一个旋转变换
*/
void testTransformEnt()
{
auto ent = acuqireEnt<ZcDbEntity>(AcDb::kForWrite);
if (!ent)
{
acutPrintf(ZCRX_T("null ent\n"));
return;
}
ZcGeMatrix3d mat;
mat.setToRotation(1.0, ZcGeVector3d(1.0, 1.0, 1.0));
ent->transformBy(mat);
}
/*
获取交互选择的region的粗糙包围盒并绘制
*/
void testGetRoughExtent()
{
auto pRegion = acuqireEnt<ZcDbRegion>();
if (!pRegion)
{
acutPrintf(ACRX_T("invalid input, please put a region."));
return;
}
AcDbExtents extent;
TIME_REOCRD(pRegion->getGeomExtents(extent););
drawExtentBox(extent);
}
/*
获取交互选择的region的精确包围盒并绘制
*/
void testGetExactExtent()
{
auto pRegion = acuqireEnt<ZcDbRegion>();
if (!pRegion)
{
acutPrintf(ACRX_T("invalid input, please put a region."));
return;
}
if (!gsGetModelerEntExactExtent)
{
acutPrintf(ACRX_T("load zcdbGetModelerEntityExactExtents failed.\n"));
return;
}
AcDbExtents extent;
TIME_REOCRD(gsGetModelerEntExactExtent(pRegion, extent););
drawExtentBox(extent);
}
void initApp()
{
acrxBuildClassHierarchy();
acedRegCmds->addCommand(_T("CUSCURVE_COMMANDS"), _T("testGetRoughExtent"), _T("testGetRoughExtent"), ACRX_CMD_MODAL, testGetRoughExtent);
acedRegCmds->addCommand(_T("CUSCURVE_COMMANDS"), _T("testGetExactExtent"), _T("testGetExactExtent"), ACRX_CMD_MODAL, testGetExactExtent);
acedRegCmds->addCommand(_T("CUSCURVE_COMMANDS"), _T("testTransformEnt"), _T("testTransformEnt"), ACRX_CMD_MODAL, testTransformEnt);
}
void unloadApp()
{
acedRegCmds->removeGroup(_T("CUSCURVE_COMMANDS"));
}
extern "C" AcRx::AppRetCode
zcrxEntryPoint(AcRx::AppMsgCode msg, void* pkt)
{
switch (msg)
{
case AcRx::kInitAppMsg:
acrxDynamicLinker->unlockApplication(pkt);
acrxRegisterAppMDIAware(pkt);
initApp();
break;
case AcRx::kUnloadAppMsg:
unloadApp();
break;
default:
break;
}
return AcRx::kRetOK;
}
zcdbGetModelerEntityExactExtents效果:
| 英文空间链接 |
|---|
★★中望CAD中如何获取三维实体精确包络框?:https://confluence.zwcad.com/pages/viewpage.action?pageId=302515974
