目录
一、概述
- 意义:在ObjectArx中如AcDbLine,AcDbCircle,AcDbArc等均为实体类,用户可以根据需要,自定义实体类“,如一扇门等,效果如下图
二、项目初始化
- 目的:初始化项目,创建一个ChDbLine自定义实体类,跟AcDbLine一样
2.1 创建空解决方案
- 菜单-》文件-》新建-》项目…
2.2 DBX操作
2.2.1 创建DBX
- 在空解决方案中添加
- 向导设置
注意:未写可不修改,第一个选项前缀自己决定
2.2.2 调试DBX
- 选择Release/x64,按调试(F5)
- 错误1:
无法打开包括文件: “corecrt.h”: No such file or directory
解决1:将C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\ucrt
路径加入包含路径(注意数字不一定相同) - 错误2:
无法打开文件“ucrt.lib”
解决2:将C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17763.0\ucrt\x64
路径加入库路径(注意数字不一定相同) - 错误3:调用aced类。。。不可调用数据库类
- 错误1:
- 图示
注:将属性页中,调试-》命令一栏清空,否则调试后,会自动启动CAD
2.2.3 创建实体类
- 在DBX项目内添加自定义实体类
- 自定义线类(继承自曲线类)
2.2.4 调试实体类
- ChDbLine.cpp
... //----- AcDbEntity protocols Adesk::Boolean ChDbLine::subWorldDraw (AcGiWorldDraw *mode) { assertReadEnabled () ; // 设置图形颜色 mode->subEntityTraits().setColor(1); // 点数组 AcGePoint3d pts[2]; pts[0] = AcGePoint3d(0, 0, 0); pts[1] = AcGePoint3d(100, 100, 0); // geometry函数:返回AcGiGeometry对象,其类方法worldLine 在世界坐标系中画直线 mode->geometry().worldLine(pts); return (AcDbCurve::subWorldDraw (mode)) ; } ...
- 调试
遇到问题:switch 语句包含“default”但是未包含“case”标签,警告被视为错误
,解决方法如下
2.3 ARX操作
2.3.1 创建arx项
- ARX创建
向导只修改此默认项即可
- 添加依赖(arx是依赖于DBX的)
两文件职责:DBX负责创建自定义类,依赖于DBX的arx负责调用自定义类
2.3.2 调试ARX
- 方法:在解决方案中my_app上单击右键-》生成
- 遇到问题
- 错误1:
无法打开包括文件: “ctype.h”
解答1:将C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\ucrt
路径加入包含路径(注意数字不一定相同) - 错误2:
无法打开文件“ucrt.lib”
解决2:将C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17763.0\ucrt\x64
路径加入库路径(注意数字不一定相同)
- 错误1:
- 修改对话框:参考2.2.2
2.3.3 调用代码
- acrxEntryPoint.cpp文件(my_app项目)
... #include "ChDbLine.h" ... class Cmy_appApp : public AcRxArxApp { ... static void MyGroupMyCommand () { // 获取块表记录 AcDbBlockTable* pBlkTbl = NULL; acdbHostApplicationServices()->workingDatabase()->getBlockTable(pBlkTbl); AcDbBlockTableRecord* pBlkTblRcd = NULL; pBlkTbl->getAt(ACDB_MODEL_SPACE, pBlkTblRcd, AcDb::kForWrite); pBlkTbl->close(); // 创建 自定义实体类 对象,并添加进块表记录中 ChDbLine* pLine = new ChDbLine(); pBlkTblRcd->appendAcDbEntity(pLine); // 关闭自定义实体类、块表记录 pLine->close(); pBlkTblRcd->close(); } ... } ...
- 调试:在解决方案中my_app上单击右键-》生成
- 遇到问题:
无法打开包括文件: “ChDbLine.h”
解答:添加头文件D:\CPP\CustomerTest\my_entity
,修改对话框参考2.2.2,即包含ChDbLine.h文件的文件夹 - 遇到问题:
无法解析的外部符号 "public: __cdecl ChDbLine::ChDbLine(void)"
解答:添加库文件(理论上在对话框参考2.2.2添加库文件夹也行,这里有点小问题)
- 遇到问题:
2.4 CAD测试
- 加载:文件位置
D:\CPP\CustomerTest\x64\Release
注意:
- 隶属关系:DBX和依赖与它的arx两个文件,是一个解决方案内的项目,生成的目标文件属于CustomerTest解决方案
- 加载顺序:先加载DBX,后加载arx
- 加载后运行:
MYCOMMANDLOCAL
命令 - 效果
三、DBX项目深化
- 目的:深化ChDbLine类,添加功能如:显示夹点、移动、拉伸、捕捉等
3.1 依赖文件修改
- acrxEntryPoint.cpp文件(my_app项目)
... #include "ChDbLine.h" ... static void MyGroupMyCommand () { // 交互式 图中画自定义实体类 AcGePoint3d ptStart, ptEnd; // asDblArray函数可以实现AcGePoint3d 与 ads_real类型间转换 if (acedGetPoint(NULL, L"\n请输入起点:", asDblArray(ptStart)) != RTNORM) return; if (acedGetPoint(NULL, L"\n请输入终点:", asDblArray(ptEnd)) != RTNORM) return; AcDbBlockTable* pBlkTbl = NULL; acdbHostApplicationServices()->workingDatabase()->getBlockTable(pBlkTbl); AcDbBlockTableRecord* pBlkTblRcd = NULL; pBlkTbl->getAt(ACDB_MODEL_SPACE, pBlkTblRcd, AcDb::kForWrite); pBlkTbl->close(); // 主要修改了以下这句:重载了构造函数 ChDbLine* pLine = new ChDbLine(ptStart, ptEnd); pBlkTblRcd->appendAcDbEntity(pLine); pLine->close(); pBlkTblRcd->close(); } ... } ...
3.2 被依赖文件修改
- ChDbLine.h
... class DLLIMPEXP ChDbLine : public AcDbCurve { public: ACRX_DECLARE_MEMBERS(ChDbLine) ; protected: static Adesk::UInt32 kCurrentVersionNumber ; public: ChDbLine(); // 增加构造函数 ChDbLine(const AcGePoint3d &ptstart, const AcGePoint3d &ptend); virtual ~ChDbLine () ; //----- AcDbObject protocols //- Dwg Filing protocol // 存入DWG数据库参数:此处为起、终点 virtual Acad::ErrorStatus dwgOutFields (AcDbDwgFiler *pFiler) const ; // 读取DWG数据库参数:参数会提取出给subWorldDraw做渲染 virtual Acad::ErrorStatus dwgInFields (AcDbDwgFiler *pFiler) ; //- Dxf Filing protocol // 存入、读取DXF数据库参数 virtual Acad::ErrorStatus dxfOutFields (AcDbDxfFiler *pFiler) const ; virtual Acad::ErrorStatus dxfInFields (AcDbDxfFiler *pFiler) ; // 获取起、终点 virtual AcGePoint3d getStartPoint() const; virtual AcGePoint3d getEndPoint() const; // 写入起、终点 virtual Acad::ErrorStatus setStartPoint(AcGePoint3d newVal); virtual Acad::ErrorStatus setEndPoint(AcGePoint3d newVal); //----- AcDbEntity protocols //- Graphics protocol protected: // 绘制实体的图形显示:此处定义了自定义实体的样子 virtual Adesk::Boolean subWorldDraw (AcGiWorldDraw *mode) ; // 定义自定义实体属性:如果有特殊定义的话 virtual Adesk::UInt32 subSetAttributes (AcGiDrawableTraits *traits) ; // 重写夹点显示函数:开启显示夹点,只要添加进gripPoints点列表中即可 virtual Acad::ErrorStatus subGetGripPoints(AcGePoint3dArray& gripPoints, AcDbIntArray& osnapModes, AcDbIntArray &geomIds) const; // 重写几何变换函数:响应move命令,否则不可移动 virtual Acad::ErrorStatus subTransformBy(const AcGeMatrix3d& xform); // 重写移动夹点变换函数:否则点选起终点的夹点也是平移效果 virtual Acad::ErrorStatus subMoveGripPointsAt(const AcDbIntArray & indices, const AcGeVector3d& offset); // 重写捕捉点:捕捉点类型osnapMode、捕捉点列表snapPoints virtual Acad::ErrorStatus subGetOsnapPoints(AcDb::OsnapMode osnapMode, Adesk::GsMarker gsSelectionMark, const AcGePoint3d& pickPoint, const AcGePoint3d& lastPoint, const AcGeMatrix3d& viewXform, AcGePoint3dArray& snapPoints, AcDbIntArray& geomIds) const; // 类成员变量:起点、终点 AcGePoint3d ptStart; AcGePoint3d ptEnd; } ; #ifdef MY_ENTITY_MODULE ACDB_REGISTER_OBJECT_ENTRY_AUTO(ChDbLine) #endif
- ChDbLine.cpp
读前注意:
- 中文注释为新增加的,其他未注释的为向导自动生成的
- 重写函数首句必须为
assertReadEnabled () ;
或assertWriteEnabled () ;
CAD会在程序执行前测试实体是否满足函数读写的前置需求
... // 默认构造函数 ChDbLine::ChDbLine () : AcDbCurve () {} // 重载构造函数 ChDbLine::ChDbLine(const AcGePoint3d &ptstart, const AcGePoint3d &ptend) { ptStart = ptstart; ptEnd = ptend; } // 析构函数 ChDbLine::~ChDbLine () {} //----------------------------------------------------------------------------- //----- AcDbObject protocols //- Dwg Filing protocol Acad::ErrorStatus ChDbLine::dwgOutFields (AcDbDwgFiler *pFiler) const { assertReadEnabled () ; //----- Save parent class information first. Acad::ErrorStatus es =AcDbCurve::dwgOutFields (pFiler) ; if ( es != Acad::eOk ) return (es) ; //----- Object version number needs to be saved first if ( (es =pFiler->writeUInt32 (ChDbLine::kCurrentVersionNumber)) != Acad::eOk ) return (es) ; //----- Output params // 将数据写入数据库 pFiler->writeItem(ptStart); pFiler->writeItem(ptEnd); return (pFiler->filerStatus ()) ; } Acad::ErrorStatus ChDbLine::dwgInFields (AcDbDwgFiler *pFiler) { assertWriteEnabled () ; //----- Read parent class information first. Acad::ErrorStatus es =AcDbCurve::dwgInFields (pFiler) ; if ( es != Acad::eOk ) return (es) ; //----- Object version number needs to be read first Adesk::UInt32 version =0 ; if ( (es =pFiler->readUInt32 (&version)) != Acad::eOk ) return (es) ; if ( version > ChDbLine::kCurrentVersionNumber ) return (Acad::eMakeMeProxy) ; //----- Read params // 将数据读出数据库 pFiler->readItem(&ptStart); pFiler->readItem(&ptEnd); return (pFiler->filerStatus ()) ; } //- Dxf Filing protocol Acad::ErrorStatus ChDbLine::dxfOutFields (AcDbDxfFiler *pFiler) const { assertReadEnabled () ; //----- Save parent class information first. Acad::ErrorStatus es =AcDbCurve::dxfOutFields (pFiler) ; if ( es != Acad::eOk ) return (es) ; es =pFiler->writeItem (AcDb::kDxfSubclass, _RXST("ChDbLine")) ; if ( es != Acad::eOk ) return (es) ; //----- Object version number needs to be saved first if ( (es =pFiler->writeUInt32 (kDxfInt32, ChDbLine::kCurrentVersionNumber)) != Acad::eOk ) return (es) ; //----- Output params //..... return (pFiler->filerStatus ()) ; } Acad::ErrorStatus ChDbLine::dxfInFields (AcDbDxfFiler *pFiler) { assertWriteEnabled () ; //----- Read parent class information first. Acad::ErrorStatus es =AcDbCurve::dxfInFields (pFiler) ; if ( es != Acad::eOk || !pFiler->atSubclassData (_RXST("ChDbLine")) ) return (pFiler->filerStatus ()) ; //----- Object version number needs to be read first struct resbuf rb ; pFiler->readItem (&rb) ; if ( rb.restype != AcDb::kDxfInt32 ) { pFiler->pushBackItem () ; pFiler->setError (Acad::eInvalidDxfCode, _RXST("\nError: expected group code %d (version #)"), AcDb::kDxfInt32) ; return (pFiler->filerStatus ()) ; } Adesk::UInt32 version =(Adesk::UInt32)rb.resval.rlong ; if ( version > ChDbLine::kCurrentVersionNumber ) return (Acad::eMakeMeProxy) ; while ( es == Acad::eOk && (es =pFiler->readResBuf (&rb)) == Acad::eOk ) { switch ( rb.restype ) { default: pFiler->pushBackItem () ; es =Acad::eEndOfFile ; break ; } } if ( es != Acad::eEndOfFile ) return (Acad::eInvalidResBuf) ; return (pFiler->filerStatus ()) ; } //----------------------------------------------------------------------------- //----- AcDbEntity protocols Adesk::Boolean ChDbLine::subWorldDraw (AcGiWorldDraw *mode) { assertReadEnabled () ; // 点数组:设置起始点 AcGePoint3d pts[2]; pts[0] = ptStart; pts[1] = ptEnd; // geometry函数:返回AcGiGeometry对象,其类方法worldLine 在世界坐标系中画直线 // 传入的是点数组指针 mode->geometry().worldLine(pts); return (AcDbCurve::subWorldDraw (mode)) ; } Adesk::UInt32 ChDbLine::subSetAttributes (AcGiDrawableTraits *traits) { assertReadEnabled () ; return (AcDbCurve::subSetAttributes (traits)) ; } // 重写夹点显示函数 Acad::ErrorStatus ChDbLine::subGetGripPoints(AcGePoint3dArray& gripPoints, AcDbIntArray& osnapModes, AcDbIntArray & geomIds) const { assertReadEnabled(); // 注意此处添加顺序直接影响夹点顺序,影响后续几何变换换 gripPoints.append(ptStart); gripPoints.append(AcGePoint3d((ptStart.x + ptEnd.x) / 2, (ptStart.y + ptEnd.y) / 2, 0)); gripPoints.append(ptEnd); return Acad::eOk; } // 重写几何变换函数 Acad::ErrorStatus ChDbLine::subTransformBy(const AcGeMatrix3d& xform) { assertWriteEnabled(); ptStart.transformBy(xform); ptEnd.transformBy(xform); return Acad::eOk; } // 重写移动夹点变换函数 Acad::ErrorStatus ChDbLine::subMoveGripPointsAt(const AcDbIntArray & indices, const AcGeVector3d& offset) { assertWriteEnabled(); // 获取鼠标点击的夹点序号:与夹点添加顺序有关 int p = indices.at(0); // 起点:起点变换 if (p == 0) { ptStart += offset; } // 中点:起、终点均变换 if (p == 1) { ptStart += offset; ptEnd += offset; } // 终点:终点变换 if (p == 2) { ptEnd += offset; } return Acad::eOk; } // 重写捕捉点:osnapMode捕捉点类型、snapPoints捕捉点点列表 Acad::ErrorStatus ChDbLine::subGetOsnapPoints(AcDb::OsnapMode osnapMode, Adesk::GsMarker gsSelectionMark, const AcGePoint3d& pickPoint, const AcGePoint3d& lastPoint, const AcGeMatrix3d& viewXform, AcGePoint3dArray& snapPoints, AcDbIntArray& geomIds) const { assertReadEnabled(); switch (osnapMode) { // 端点:其他点类型点进AcDb结构体中看 case AcDb::kOsModeEnd: { snapPoints.append(ptStart); snapPoints.append(ptEnd); } break; // 中点 case AcDb::kOsModeMid: { snapPoints.append(AcGePoint3d((ptStart.x + ptEnd.x) / 2, (ptStart.y + ptEnd.y) / 2, 0)); } break; default: break; } return Acad::eOk; } // 获取起点 AcGePoint3d ChDbLine::getStartPoint() const { assertReadEnabled(); return ptStart; } // 获取终点 AcGePoint3d ChDbLine::getEndPoint() const { assertReadEnabled(); return ptEnd; } // 设置起点 Acad::ErrorStatus ChDbLine::setStartPoint(AcGePoint3d newVal) { assertWriteEnabled(); ptStart = newVal; return Acad::eOk; } // 设置终点 Acad::ErrorStatus ChDbLine::setEndPoint(AcGePoint3d newVal) { assertWriteEnabled(); ptEnd = newVal; return Acad::eOk; }
3.3 效果
四、COM创建OPM
- COM:即组件对象模型,是Component Object Model取前三个字母的缩写
- OPM:即对象属性管理器,是Object Property Management前三个字母缩写
后续补充,非自定义实体类的必要组件