在AutoCAD的二次开发中,最有用和最难的当属自定义实体技术,这应当说是二次开发中最有魅力的部分。在本文中,我通过一个简单的自定义实体,向大家介绍ObjectARX Wizard的安装使用方法,以及自定义实体中一些常用接口的写法。
本文以VS2017+ObjectARX2019+cad2020进行演示说明,最终实体效果如下图所示。本文包含所有源码(除了向导生成的以外),同时包含一些重要的成员函数讲解。
整个解决方案可以从https://download.csdn.net/download/mary288267/87243676进行下载。
首先,下载ObjectARXWizard2020.msi,可以从CAD的官网下载,若官网网速慢或者无法连接,可以通过该链接下载https://download.csdn.net/download/mary288267/87233949
在ObjectARX中,一般建议将自定义实体和使用这个实体的工程分开,接下来,我们分别创建两个工程。首先创建自定义实体工程CustomStair。
在刚刚创建的CustomStair工程中,添加自定义实体类。选中CustomStair工程,右键:添加/新建项,选中下图所示类型,点击添加。
在下面向导对话框中,输入自定义实体类的名称,自定义实体的DXF名称,基类名称(我们选择AcDbEntity),应用程序的名称等,然后点击Finish,完成创建。
这样,向导自动为我们创建了实体类CZdfCustomStair,可以看到有一些基本的成员函数,我们之后会扩充完善类成员函数。
创建好这个类之后,我们不要着急去重写基类的各个虚函数。我们需要“初始化”这个自定义类,什么意思呢?ObjectARX中,每个自定义类都有一个静态的AcRxClass对象,这个AcRxClass对象是ObjectARX类层次结构树的一个节点,表示这个自定义类在层次结构树的位置(这样,就能找到其父对象和子对象)。这实际上是ObjectARX实现RTTI(运行时类型识别)的方式。参见以下帮助原文。
AcRxClass objects (actually objects of an internal class derived from AcRxClass, since AcRxClass is an abstract base class) are used as the nodes in the ObjectARX runtime class hierarchical tree. Each instance of an AcRxClass represents a C++ class derived from AcRxObject (or AcRxObject itself). The run-time information about such C++ classes and their hierarchical relationships is available through the AcRxClass objects that make up the runtime tree.
为了把我们的自定义实体类加到ObjectARX的类层次结构树上,我们需要在本工程的acrxEntryPoint.cpp文件中找到CCustomStairApp::On_kInitAppMsg成员函数,在这个函数中加入CZdfCustomStair::rxInit()和acrxBuildClassHierarchy()函数:
virtual AcRx::AppRetCode On_kInitAppMsg (void *pkt) {
// TODO: Load dependencies here
// You *must* call On_kInitAppMsg here
AcRx::AppRetCode retCode =AcRxDbxApp::On_kInitAppMsg (pkt) ;
//这些是加入的代码,目的是使我们的自定义类加入到ObjectARX的类层次结构树中
CZdfCustomStair::rxInit();
acrxBuildClassHierarchy();
return (retCode) ;
}
同时,在卸载这个动态库时,也需要删除这个类的AcRxClass对象,删除其在类结构树中的节点。同样在acrxEntryPoint.cpp文件中找到CCustomStairApp::On_kUnloadAppMsg 函数,并在其中调用deleteAcRxClass(CZdfCustomStair::desc())。
virtual AcRx::AppRetCode On_kUnloadAppMsg (void *pkt) {
// TODO: Add your code here
// You *must* call On_kUnloadAppMsg here
AcRx::AppRetCode retCode =AcRxDbxApp::On_kUnloadAppMsg (pkt) ;
// TODO: Unload dependencies here
deleteAcRxClass(CZdfCustomStair::desc());
return (retCode) ;
}
至此,我们终于搭完了框架!接下来,我们看看最关键的——如何添加类的成员函数。
这里,我把自定义实体类的头文件和实现文件罗列出来,之后,会对关键的一些函数做出说明。
以下是CZdfCustomStair的头文件
//-----------------------------------------------------------------------------
//----- ZdfCustomStair.h : Declaration of the CZdfCustomStair
//-----------------------------------------------------------------------------
#pragma once
#ifdef CUSTOMSTAIR_MODULE
#define DLLIMPEXP __declspec(dllexport)
#else
//----- Note: we don't use __declspec(dllimport) here, because of the
//----- "local vtable" problem with msvc. If you use __declspec(dllimport),
//----- then, when a client dll does a new on the class, the object's
//----- vtable pointer points to a vtable allocated in that client
//----- dll. If the client dll then passes the object to another dll,
//----- and the client dll is then unloaded, the vtable becomes invalid
//----- and any virtual calls on the object will access invalid memory.
//-----
//----- By not using __declspec(dllimport), we guarantee that the
//----- vtable is allocated in the server dll during the ctor and the
//----- client dll does not overwrite the vtable pointer after calling
//----- the ctor. And, since we expect the server dll to remain in
//----- memory indefinitely, there is no problem with vtables unexpectedly
//----- going away.
#define DLLIMPEXP
#endif
//-----------------------------------------------------------------------------
#include "dbmain.h"
//-----------------------------------------------------------------------------
class DLLIMPEXP CZdfCustomStair : public AcDbEntity
{
public:
ACRX_DECLARE_MEMBERS(CZdfCustomStair) ;
CZdfCustomStair () ;
virtual ~CZdfCustomStair () ;
//楼梯参数设置
void SetStepNum(Adesk::Int32 nStepNum); //楼梯总台阶数
void SetStepWidth(double dWidth); //台阶数目
void SetStepHeight(double dHeight); //台阶高度
void SetStairPos(AcGePoint3d pt); //楼梯起始点
void SetStairOrient(AcGeVector3d vt); //楼梯走向
void SetStairNormal(AcGeVector3d vt); //楼梯法向量
void SetStairText(LPCTSTR psz, int iHeight = 4);//楼梯文字高度和内容
//楼梯参数获取
int GetStepNum() const; //获取楼梯总台阶数
double GetStepWidth() const; //获取楼梯总宽度
double GetStepHeight() const; //获取楼梯总高度
AcGePoint3d GetStairPos() const; //获取楼梯的起始位置
AcGeVector3d GetStairOrient() const;
AcGeVector3d GetStairNormal() const;
const CString& GetStairText() const;
//保存数据
virtual Acad::ErrorStatus dwgOutFields(AcDbDwgFiler *pFiler) const;
//加载数据
virtual Acad::ErrorStatus dwgInFields(AcDbDwgFiler *pFiler);
protected:
static Adesk::UInt32 kCurrentVersionNumber;
//外包矩形
virtual Acad::ErrorStatus subGetGeomExtents(AcDbExtents& extents) const;
//分解(炸开)
virtual Acad::ErrorStatus subExplode(AcDbVoidPtrArray& entitySet) const;
//sList
virtual void subList() const;
//实体绘制
virtual Adesk::Boolean subWorldDraw(AcGiWorldDraw *mode);
//捕捉点
virtual Acad::ErrorStatus subGetOsnapPoints(
AcDb::OsnapMode osnapMode,
Adesk::GsMarker gsSelectionMark,
const AcGePoint3d &pickPoint,
const AcGePoint3d &lastPoint,
const AcGeMatrix3d &viewXform,
AcGePoint3dArray &snapPoints,
AcDbIntArray &geomIds) const;
//显示夹点
virtual Acad::ErrorStatus subGetGripPoints(
AcGePoint3dArray &gripPoints,
AcDbIntArray &osnapModes,
AcDbIntArray &geomIds) const;
//移动夹点
virtual Acad::ErrorStatus subMoveGripPointsAt(const AcDbIntArray &indices, const AcGeVector3d &offset);
//矩阵转换
virtual Acad::ErrorStatus subTransformBy(const AcGeMatrix3d& xform);
private:
void UpdateEntity();
//调用者删除动态分配的内容
AcDbPolyline* ConvertToPolyline() const;
//序列化的数据
AcGeVector3d m_vtStairOrient; //楼梯方向,指水平踏步的方向
AcGeVector3d m_vtStairNormal; //法向量方向
AcGePoint3d m_ptStairOrigin; //楼梯起点
Adesk::Int32 m_nStepNum; //踏步总数
double m_dStepWidth; //踏步宽度
double m_dStepHeight; //踏步高度
double m_dTextHeight; //文字高度
CString m_sTextContent; //文字内容
//辅助数据
AcGePoint3dArray m_arptStairVertex; //存储楼梯多段线所有顶点坐标
AcDbText m_dbtextName; //楼梯下方显示的文字
};
#ifdef CUSTOMSTAIR_MODULE
ACDB_REGISTER_OBJECT_ENTRY_AUTO(CZdfCustomStair)
#endif
以下为CZdfCustomStair的实现文件
//-----------------------------------------------------------------------------
//----- ZdfCustomStair.cpp : Implementation of CZdfCustomStair
//-----------------------------------------------------------------------------
#include "StdAfx.h"
#include "ZdfCustomStair.h"
#define _USE_MATH_DEFINES
#include
Adesk::UInt32 CZdfCustomStair::kCurrentVersionNumber =1 ;
ACRX_DXF_DEFINE_MEMBERS (
CZdfCustomStair, AcDbEntity,
AcDb::kDHL_CURRENT, AcDb::kMReleaseCurrent,
AcDbProxyEntity::kNoOperation, ZDFCUSTOMSTAIR,
ZDFCUSTOMSTAIRAPP
|Product Desc: A description for your object
|Company: Your company name
|WEB Address: Your company WEB site address
)
CZdfCustomStair::CZdfCustomStair() : AcDbEntity()
, m_vtStairOrient(1, 0, 0)
, m_vtStairNormal(0, 0, 1)
, m_ptStairOrigin(0, 0, 0)
, m_nStepNum(18)
, m_dStepWidth(300)
, m_dStepHeight(180)
, m_dTextHeight(4)
, m_sTextContent(_T(""))
{
}
CZdfCustomStair::~CZdfCustomStair () {
}
void CZdfCustomStair::SetStepNum(Adesk::Int32 nStepNum)
{
assertWriteEnabled();
m_nStepNum = nStepNum;
UpdateEntity();
}
void CZdfCustomStair::SetStepWidth(double dWidth)
{
assertWriteEnabled();
m_dStepWidth = dWidth;
UpdateEntity();
}
void CZdfCustomStair::SetStepHeight(double dHeight)
{
assertWriteEnabled();
m_dStepHeight = dHeight;
UpdateEntity();
}
void CZdfCustomStair::SetStairPos(AcGePoint3d pt)
{
assertWriteEnabled();
m_ptStairOrigin = pt;
UpdateEntity();
}
void CZdfCustomStair::SetStairOrient(AcGeVector3d vt)
{
assertWriteEnabled();
m_vtStairOrient = vt.normal();
UpdateEntity();
}
void CZdfCustomStair::SetStairNormal(AcGeVector3d vt)
{
assertWriteEnabled();
m_vtStairNormal = vt;
UpdateEntity();
}
void CZdfCustomStair::SetStairText(LPCTSTR psz, int iHeight)
{
assertWriteEnabled();
m_sTextContent = psz;
m_dTextHeight = iHeight;
UpdateEntity();
}
double CZdfCustomStair::GetStepWidth() const
{
assertReadEnabled();
return m_dStepWidth;
}
double CZdfCustomStair::GetStepHeight() const
{
assertReadEnabled();
return m_dStepHeight;
}
AcGePoint3d CZdfCustomStair::GetStairPos() const
{
assertReadEnabled();
return m_ptStairOrigin;
}
AcGeVector3d CZdfCustomStair::GetStairOrient() const
{
assertReadEnabled();
return m_vtStairOrient;
}
AcGeVector3d CZdfCustomStair::GetStairNormal() const
{
assertReadEnabled();
return m_vtStairNormal;
}
const CString& CZdfCustomStair::GetStairText() const
{
assertReadEnabled();
return m_sTextContent;
}
//-----------------------------------------------------------------------------
//----- AcDbObject protocols
//- Dwg Filing protocol
Acad::ErrorStatus CZdfCustomStair::dwgOutFields(AcDbDwgFiler *pFiler) const {
assertReadEnabled();
//----- Save parent class information first.
Acad::ErrorStatus es = AcDbEntity::dwgOutFields(pFiler);
if (es != Acad::eOk)
return (es);
//----- Object version number needs to be saved first
if ((es = pFiler->writeUInt32(CZdfCustomStair::kCurrentVersionNumber)) != Acad::eOk)
return (es);
//向dwg文件写入数据
es = pFiler->writeItem(m_vtStairOrient);
if (Acad::eOk != es) return es;
es = pFiler->writeItem(m_vtStairNormal);
if (Acad::eOk != es) return es;
es = pFiler->writeItem(m_ptStairOrigin);
if (Acad::eOk != es) return es;
es = pFiler->writeItem(m_nStepNum);
if (Acad::eOk != es) return es;
es = pFiler->writeItem(m_dStepWidth);
if (Acad::eOk != es) return es;
es = pFiler->writeItem(m_dStepHeight);
if (Acad::eOk != es) return es;
es = pFiler->writeItem(m_dTextHeight);
if (Acad::eOk != es) return es;
es = pFiler->writeItem(m_sTextContent.GetString());
if (Acad::eOk != es) return es;
return (pFiler->filerStatus());
}
Acad::ErrorStatus CZdfCustomStair::dwgInFields(AcDbDwgFiler *pFiler) {
assertWriteEnabled();
//----- Read parent class information first.
Acad::ErrorStatus es = AcDbEntity::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 > CZdfCustomStair::kCurrentVersionNumber)
return (Acad::eMakeMeProxy);
//- Uncomment the 2 following lines if your current object implementation cannot
//- support previous version of that object.
//if ( version < CZdfCustomStair::kCurrentVersionNumber )
// return (Acad::eMakeMeProxy) ;
//----- Read params
//从dwg文件读取文件
if (version >= 1)
{
es = pFiler->readItem(&m_vtStairOrient);
if (Acad::eOk != es) return es;
es = pFiler->readItem(&m_vtStairNormal);
if (Acad::eOk != es) return es;
es = pFiler->readItem(&m_ptStairOrigin);
if (Acad::eOk != es) return es;
es = pFiler->readItem(&m_nStepNum);
if (Acad::eOk != es) return es;
es = pFiler->readItem(&m_dStepWidth);
if (Acad::eOk != es) return es;
es = pFiler->readItem(&m_dStepHeight);
if (Acad::eOk != es) return es;
es = pFiler->readItem(&m_dTextHeight);
if (Acad::eOk != es) return es;
TCHAR *psz=NULL;
es = pFiler->readItem(&psz);
if (Acad::eOk != es) {
delete psz;
return es;
}
m_sTextContent = psz;
delete psz;
}
UpdateEntity();
return (pFiler->filerStatus());
}
Acad::ErrorStatus CZdfCustomStair::subGetGeomExtents(AcDbExtents& extents) const
{
assertReadEnabled();
for (int i = 0; i < m_arptStairVertex.length(); i++)
extents.addPoint(m_arptStairVertex[i]);
AcDbExtents extText;
m_dbtextName.getGeomExtents(extText);
extents.addExt(extText);
return Acad::eOk;
}
Acad::ErrorStatus CZdfCustomStair::subExplode(AcDbVoidPtrArray& entitySet) const
{
assertReadEnabled();
for (int i = 0; i + 1 < m_arptStairVertex.length(); i++)
{
AcDbLine* pLine = new AcDbLine(m_arptStairVertex[i], m_arptStairVertex[i + 1]);
pLine->setPropertiesFrom(this);
entitySet.append(pLine);
}
AcDbText* pText = AcDbText::cast(m_dbtextName.clone());
if (pText)
entitySet.append(pText);
return Acad::eOk;
}
Adesk::Boolean CZdfCustomStair::subWorldDraw(AcGiWorldDraw *mode)
{
assertReadEnabled();
if (!m_arptStairVertex.isEmpty())
mode->geometry().polyline(m_arptStairVertex.length(), m_arptStairVertex.asArrayPtr());
m_dbtextName.worldDraw(mode);
return Adesk::kTrue;
}
//- Osnap points protocol
Acad::ErrorStatus CZdfCustomStair::subGetOsnapPoints(
AcDb::OsnapMode osnapMode,
Adesk::GsMarker gsSelectionMark,
const AcGePoint3d &pickPoint,
const AcGePoint3d &lastPoint,
const AcGeMatrix3d &viewXform,
AcGePoint3dArray &snapPoints,
AcDbIntArray &geomIds) const
{
assertReadEnabled();
Acad::ErrorStatus es = Acad::eOk;
AcDbPolyline* pPoly = NULL;
pPoly = ConvertToPolyline();
if (pPoly)
{
pPoly->getOsnapPoints(osnapMode, gsSelectionMark, pickPoint, lastPoint,
viewXform, snapPoints, geomIds);
delete pPoly;
}
m_dbtextName.getOsnapPoints(osnapMode, gsSelectionMark, pickPoint, lastPoint,
viewXform, snapPoints, geomIds);
return Acad::eOk;
}
//- Grip points protocol
Acad::ErrorStatus CZdfCustomStair::subGetGripPoints(
AcGePoint3dArray &gripPoints, AcDbIntArray &osnapModes, AcDbIntArray &geomIds) const
{
assertReadEnabled();
//----- This method is never called unless you return eNotImplemented
//----- from the new getGripPoints() method below (which is the default implementation)
gripPoints.append(m_ptStairOrigin);
gripPoints.append(m_arptStairVertex.last());
return Acad::eOk;
}
Acad::ErrorStatus CZdfCustomStair::subMoveGripPointsAt(const AcDbIntArray &indices, const AcGeVector3d &offset)
{
assertWriteEnabled();
//----- This method is never called unless you return eNotImplemented
//----- from the new moveGripPointsAt() method below (which is the default implementation)
for (int i = 0; i < indices.length(); i++)
{
switch (indices[i])
{
case 0:
SetStairPos(m_ptStairOrigin + offset);
break;
case 1:
//计算新的楼梯台阶数目
AcGePoint3d pt;
AcGePoint3d ptDrag = m_arptStairVertex.last() + offset;
AcDbLine line(m_ptStairOrigin, m_arptStairVertex.last());
line.getClosestPointTo(ptDrag, pt, true); //获取垂足的方法
double dStepLen = sqrt(pow(m_dStepWidth, 2) + pow(m_dStepHeight, 2));
int nStepNum = (int)(pt.distanceTo(m_ptStairOrigin) / dStepLen);
SetStepNum(nStepNum);
break;
}
}
return Acad::eOk;
}
void CZdfCustomStair::subList() const
{
assertReadEnabled();
AcDbEntity::subList();
acutPrintf(_T("\n\t\t踏步总数: \t\t%g"), m_nStepNum);
acutPrintf(_T("\n\t\t踏步宽度: \t\t%g"), m_dStepWidth);
acutPrintf(_T("\n\t\t踏步高度: \t\t%g"), m_dStepHeight);
acutPrintf(_T("\n\t\t踏步方向: \t\t%g"), m_vtStairOrient.angleTo(AcGeVector3d::kXAxis));
acutPrintf(_T("\n\t\t楼梯说明: \t\t%g"), m_dbtextName.textStringConst());
}
Acad::ErrorStatus CZdfCustomStair::subTransformBy(const AcGeMatrix3d& xform)
{
assertWriteEnabled();
m_vtStairOrient.transformBy(xform);
m_vtStairNormal.transformBy(xform);
m_ptStairOrigin.transformBy(xform);
double dScale = xform.scale();
m_dStepWidth *= dScale;
m_dStepHeight *= dScale;
m_dTextHeight *= dScale;
UpdateEntity();
return Acad::eOk;
}
int CZdfCustomStair::GetStepNum() const
{
assertReadEnabled();
return m_nStepNum;
}
void CZdfCustomStair::UpdateEntity()
{
assertWriteEnabled();
//绘制每一级台阶
m_arptStairVertex.removeAll();
int nSteps = GetStepNum();
if (nSteps < 1)
return;
AcGeVector3d vtOrientHor = m_vtStairOrient.normal();
AcGeVector3d vtOrientVert = m_vtStairOrient;
vtOrientVert.rotateBy(M_PI_2, m_vtStairNormal).normalize();
AcGePoint3d pt = m_ptStairOrigin - m_dStepWidth * vtOrientHor;
for (int i = 0; i < nSteps * 2; i += 2)
{
pt += m_dStepWidth * vtOrientHor;
m_arptStairVertex.append(pt);
pt += m_dStepHeight * vtOrientVert;
m_arptStairVertex.append(pt);
}
pt += m_dStepWidth * vtOrientHor;
m_arptStairVertex.append(pt);
//初始文字位置
m_dbtextName.setDatabaseDefaults();
m_dbtextName.setTextString(m_sTextContent);
m_dbtextName.setHeight(m_dTextHeight);
m_dbtextName.setPosition(m_arptStairVertex[0]);
double dRotate = AcGeVector3d::kXAxis.angleTo(vtOrientHor,m_vtStairNormal);
m_dbtextName.setRotation(dRotate);
}
AcDbPolyline* CZdfCustomStair::ConvertToPolyline() const
{
assertReadEnabled();
if (m_arptStairVertex.isEmpty())
return NULL;
AcDbPolyline* pLine = new AcDbPolyline();
for (int i = 0; i < m_arptStairVertex.length(); i++)
pLine->addVertexAt(i, AcGePoint2d(m_arptStairVertex[i].x, m_arptStairVertex[i].y));
return pLine;
}
关于成员函数的实现方法,需要做出以下说明:
Adesk::Boolean CZdfCustomStair::subWorldDraw(AcGiWorldDraw *mode)
{
assertReadEnabled();
if (!m_arptStairVertex.isEmpty())
mode->geometry().polyline(m_arptStairVertex.length(), m_arptStairVertex.asArrayPtr());
m_dbtextName.worldDraw(mode);
return Adesk::kTrue;
}
Acad::ErrorStatus CZdfCustomStair::subGetOsnapPoints(
AcDb::OsnapMode osnapMode,
Adesk::GsMarker gsSelectionMark,
const AcGePoint3d &pickPoint,
const AcGePoint3d &lastPoint,
const AcGeMatrix3d &viewXform,
AcGePoint3dArray &snapPoints,
AcDbIntArray &geomIds) const
{
assertReadEnabled();
Acad::ErrorStatus es = Acad::eOk;
AcDbPolyline* pPoly = NULL;
pPoly = ConvertToPolyline();
if (pPoly)
{
pPoly->getOsnapPoints(osnapMode, gsSelectionMark, pickPoint, lastPoint,
viewXform, snapPoints, geomIds);
delete pPoly;
}
m_dbtextName.getOsnapPoints(osnapMode, gsSelectionMark, pickPoint, lastPoint,
viewXform, snapPoints, geomIds);
return Acad::eOk;
}
Acad::ErrorStatus CZdfCustomStair::subGetGripPoints(
AcGePoint3dArray &gripPoints, AcDbIntArray &osnapModes, AcDbIntArray &geomIds) const
{
assertReadEnabled();
//----- This method is never called unless you return eNotImplemented
//----- from the new getGripPoints() method below (which is the default implementation)
//这个函数添加了所有需要编辑的夹点
gripPoints.append(m_ptStairOrigin);
gripPoints.append(m_arptStairVertex.last());
return Acad::eOk;
}
subMoveGripPointsAt用于根据夹点修改实体外形,它有两个输入参数,第一个参数是指编辑的夹点序号(这个序号是按照subGetGripPoints添加夹点的顺序确定的),第二个参数是指夹点移动的距离。通过执行一个循环,依次取出每个编辑的夹点,对0号夹点,我们整体移动实体;对1号夹点,我们增加或者减少楼梯的台阶数目。
Acad::ErrorStatus CZdfCustomStair::subMoveGripPointsAt(const AcDbIntArray &indices, const AcGeVector3d &offset)
{
assertWriteEnabled();
//----- This method is never called unless you return eNotImplemented
//----- from the new moveGripPointsAt() method below (which is the default implementation)
for (int i = 0; i < indices.length(); i++)
{
switch (indices[i])
{
case 0:
SetStairPos(m_ptStairOrigin + offset);
break;
case 1:
//计算新的楼梯台阶数目
AcGePoint3d pt;
AcGePoint3d ptDrag = m_arptStairVertex.last() + offset;
AcDbLine line(m_ptStairOrigin, m_arptStairVertex.last());
line.getClosestPointTo(ptDrag, pt, true); //获取垂足的方法
double dStepLen = sqrt(pow(m_dStepWidth, 2) + pow(m_dStepHeight, 2));
int nStepNum = (int)(pt.distanceTo(m_ptStairOrigin) / dStepLen);
SetStepNum(nStepNum);
break;
}
}
return Acad::eOk;
}
在UseStair工程acrxEntryPoint.cpp文件中,在CUseStairApp类中添加下面静态成员函数。这是调用CZdfCustomStair的命令函数。
static void ZdfMyGroupAddStair () {
// Put your command code here
CZdfCustomStair* pStair = new CZdfCustomStair();
pStair->SetStairOrient(AcGeVector3d(1, 0, 0));
pStair->SetStairPos(AcGePoint3d(100, 0, 0));
pStair->SetStepNum(20);
pStair->SetStepWidth(300);
pStair->SetStepHeight(180);
pStair->SetStairNormal(AcGeVector3d(0, 0, 1));
pStair->SetStairText(_T("你好,arx!"), 150);
AcDbBlockTable* pBlkTble = NULL;
if (Acad::eOk == acdbHostApplicationServices()->workingDatabase()->getSymbolTable(pBlkTble, AcDb::kForRead))
{
AcDbBlockTableRecord* pRec = NULL;
if (Acad::eOk == pBlkTble->getAt(ACDB_MODEL_SPACE, pRec, AcDb::kForWrite))
{
if (Acad::eOk != pRec->appendAcDbEntity(pStair))
{
delete pStair;
pStair = NULL;
}
else
{
pStair->close();
}
pRec->close();
}
pBlkTble->close();
}
}
在acrxEntryPoint.cpp文件的末尾,加上下面宏调用,这是ObjectARX2019注册命令的方法,命令名为AddStair。组名(ZdfMyGroup)+命令名(AddStair)就是命令函数的函数名。
ACED_ARXCOMMAND_ENTRY_AUTO(CUseStairApp, ZdfMyGroup, AddStair, AddStair, ACRX_CMD_MODAL, NULL)
编译这两个工程,得到一个.dbx和一个.arx文件,用ap命令将他们依次加入到cad中,执行AddStair命令即可。