目录
1.1 概要
1.2 一步步实现
1.3 完整代码
在《中望CAD二次开发初级教程》中,我们介绍了很多图形实体,例如直线、圆、多段线等,这些都是CAD内置的实体类型,既可以在CAD中绘制也可以通过SDK接口绘制,但是这些只能绘制出指定样式(这里的样式不是指线型、颜色等基础样式)的图形。本节介绍,如何通过代码实现自定义图形实体。
1.1 概要
本讲的目标是绘制出下图所示的图形(一个北斗七星)。通过CAD内置的图形类型,可以很方便的绘制出来:利用多段线画出北斗七星的形状,然后在每个节点上绘制一个圆。这显然不是自定义图形类型——因为这是两种图形类型拼出来的。下面就是通过自定义图形类型,画出多段线,但是多段线的每个节点都自带一个圆。而他们是一个整体。

原理:观察ZcDbPolyline(多段线)可以知道,它是ZcDbCurve的派生类,而ZcDbCurve又是ZcDbEntity的派生类。ZcDbCurve是所有线性实体的抽象基类(见下图):

所以,这里通过重写ZcDbCurve来实现自定义图形实体。
1.2 一步步实现
第一步:创建一个继承自ZcDbCurve的类。
class MyLine :public ZcDbCurve
{
public:
MyLine();
virtual ~MyLine();
};
第二步:重写必要的虚函数。
virtual Zcad::ErrorStatus dwgInFields(ZcDbDwgFiler* filer) override;
virtual Zcad::ErrorStatus dwgOutFields(ZcDbDwgFiler* filer) const override;
virtual ZSoft::Boolean subWorldDraw(ZcGiWorldDraw* wd) override;
第三步:注入运行时类信息。
通过一个宏来让CAD系统在运行过程中识别此自定义类。
ZCRX_DECLARE_MEMBERS(MyLine); //这里的MyLine就是类名
通过下面的宏来实现自定义实体的“反射”与持久化注册:
ZCRX_DXF_DEFINE_MEMBERS(
MyLine, //类名
ZcDbCurve, //基类类名
ZcDb::kDHL_CURRENT, //指定该类支持的最低DWG维护版本
ZcDb::kMReleaseCurrent, //CAD维护版本
ZcDbProxyEntity::kAllAllowedBits, //允许所有操作
MYLINE,
MY_APP_ID | Product : My_Product | Company : My_Company | Website : www.csdn.net
);
解释:
MyLine:类名
ZcDbCurve:基类名称
ZcDb::kDHL_CURRENT: 指定该类支持的最低DWG维护版本。这里指的是当前版本。
ZcDb::kMReleaseCurrent:该类的维护发行版本。
ZcDbProxyEntity::kAllAllowedBits:代理行为参数。当CAD没有加载这个插件的时候,这个自定义实体通过代理呈现,这个参数指定允许有哪些代理行为。代理行为包括删除、移动、复制等。kAllAllowedBits就是允许所有的操作。
MYLINE:在DWG/DXF的唯一标识。
最后一行为描述信息,包括产品ID、产品名称等内容。
第四步:初始化与销毁
在插件入口kInitAppMsg下面执行初始化:MyLine::rxInit();
在插件入口kUnloadAppMsg下面实现销毁:deleteAcRxClass(MyLine::desc());
第五步:实现功能
(1)在MyLine中声明一个成员变量,来存放点:
private:
ZcGePoint3dArray m_points;
(2)提供一个公共方法用来传入点集合:
void MyLine::setPoints(const ZcGePoint3dArray& points)
{
m_points = points;
}
(3)实现第二步的三个方法:
dwgOutFields:
Zcad::ErrorStatus MyLine::dwgOutFields(ZcDbDwgFiler* filer) const
{
assertReadEnabled();
Zcad::ErrorStatus es = ZcDbCurve::dwgOutFields(filer);
if (es != Zcad::eOk)
return es;
ZSoft::UInt32 numPoints = m_points.length();
filer->writeUInt32(numPoints);
for (ZSoft::UInt32 i = 0; i < numPoints; i++)
{
if ((es = filer->writePoint3d(m_points[i])) != Zcad::eOk)
{
return es;
}
}
return es;
}
说明:
重写这个方法目的是实现,如何将该对象序列化到dwg文件中。
assertReadEnabled提供了一个状态保护宏,通过断言机制实现当代码访问改对象之前,该对象是可读的(kForRead)。
因为MyLine是ZcDbCurve的派生类,所以不需要全部去实现序列化过程,只需要把自己新加的部分实现,至于其他的ZcDbCurve固有的东西,通过调用ZcDbCurve::dwgOutFields实现。
代码的核心是下面的内容,通过writeUInt32写入点数量,通过循环实现写入点,即writePoint3d。
dwgInFields:
Zcad::ErrorStatus MyLine::dwgInFields(ZcDbDwgFiler* filer)
{
assertWriteEnabled();
Zcad::ErrorStatus es = ZcDbCurve::dwgInFields(filer);
if (Zcad::eOk != es)
return es;
ZSoft::UInt32 numPoints = 0;
if ((es = filer->readUInt32(&numPoints)) != Zcad::eOk)
{
return es;
}
m_points.setLogicalLength(numPoints);
for (ZSoft::UInt32 i = 0; i < numPoints; i++)
{
if ((es = filer->readPoint3d(&m_points[i])) != Zcad::eOk)
{
return es;
}
}
return es;
}
说明:这个方法是实现如何从dwg文件中读取,跟写入对应,这里不做赘述。
subWorldDraw:
ZSoft::Boolean MyLine::subWorldDraw(ZcGiWorldDraw* wd)
{
ZSoft::UInt32 numPoints = m_points.length();
if (numPoints < 2)
return ZSoft::kTrue;
wd->geometry().polyline(numPoints, m_points.asArrayPtr());
for (ZSoft::UInt32 i = 0; i < numPoints; i++)
{
wd->geometry().circle(m_points[i], 10, ZcGeVector3d::kZAxis);
}
return ZSoft::kTrue;
}
这个方法是本类核心内容,也就是实现绘制方法,即目标中提到的在每个线的节点上绘制一个圆。通过调用wd->geometry().polyline,来绘制正常的多段线,通过循环每个点并调用wd->geometry().circle类实现圆的绘制。
第六步:调用
上面的步骤实现后,就直接可以调用了,就像普通的图形实体一样,将它创建出来后,添加到模型空间中:
void createMyLine()
{
//当前活动数据库
AcDbDatabase* db = acdbHostApplicationServices()->workingDatabase();
//块表
AcDbBlockTable* blockTable = nullptr;
db->getBlockTable(blockTable, AcDb::OpenMode::kForRead);
//块表记录
AcDbBlockTableRecord* blockTableRec = nullptr;
blockTable->getAt(ACDB_MODEL_SPACE, blockTableRec, AcDb::OpenMode::kForWrite);
blockTable->close();
AcGePoint3dArray vertices;
vertices.append(AcGePoint3d(348.8989, 695.1864, 0.0000));
vertices.append(AcGePoint3d(595.1922, 632.7459, 0.0000));
vertices.append(AcGePoint3d(689.7203, 516.5371, 0.0000));
vertices.append(AcGePoint3d(853.6268, 438.4864, 0.0000));
vertices.append(AcGePoint3d(883.1126, 234.6873, 0.0000));
vertices.append(AcGePoint3d(1094.7167, 215.6083, 0.0000));
vertices.append(AcGePoint3d(1179.7052, 413.3367, 0.0000));
MyLine* line = new MyLine;
line->setPoints(vertices);
blockTableRec->appendZcDbEntity(line);
line->close();
blockTableRec->close();
}
1.3 完整代码
MyLine.h
#pragma once
#include "pch.h"
class MyLine :public ZcDbCurve
{
public:
ZCRX_DECLARE_MEMBERS(MyLine);
MyLine();
virtual ~MyLine();
virtual Zcad::ErrorStatus dwgInFields(ZcDbDwgFiler* filer) override;
virtual Zcad::ErrorStatus dwgOutFields(ZcDbDwgFiler* filer) const override;
virtual ZSoft::Boolean subWorldDraw(ZcGiWorldDraw* wd) override;
public:
void setPoints(const ZcGePoint3dArray& points);
private:
ZcGePoint3dArray m_points;
};
MyLine.cpp
#include "pch.h"
#include "MyLine.h"
#include "zdbproxy.h"
ZCRX_DXF_DEFINE_MEMBERS(
MyLine,
ZcDbCurve,
ZcDb::kDHL_CURRENT,
ZcDb::kMReleaseCurrent,
ZcDbProxyEntity::kAllAllowedBits,
MYLINE,
MY_APP_ID | Product : My_Product | Company : My_Company | Website : www.csdn.net
);
MyLine::MyLine()
{
}
MyLine::~MyLine()
{
}
Zcad::ErrorStatus MyLine::dwgInFields(ZcDbDwgFiler* filer)
{
assertWriteEnabled();
Zcad::ErrorStatus es = ZcDbCurve::dwgInFields(filer);
if (Zcad::eOk != es)
return es;
ZSoft::UInt32 numPoints = 0;
if ((es = filer->readUInt32(&numPoints)) != Zcad::eOk)
{
return es;
}
m_points.setLogicalLength(numPoints);
for (ZSoft::UInt32 i = 0; i < numPoints; i++)
{
if ((es = filer->readPoint3d(&m_points[i])) != Zcad::eOk)
{
return es;
}
}
return es;
}
Zcad::ErrorStatus MyLine::dwgOutFields(ZcDbDwgFiler* filer) const
{
assertReadEnabled();
Zcad::ErrorStatus es = ZcDbCurve::dwgOutFields(filer);
if (es != Zcad::eOk)
return es;
ZSoft::UInt32 numPoints = m_points.length();
filer->writeUInt32(numPoints);
for (ZSoft::UInt32 i = 0; i < numPoints; i++)
{
if ((es = filer->writePoint3d(m_points[i])) != Zcad::eOk)
{
return es;
}
}
return es;
}
ZSoft::Boolean MyLine::subWorldDraw(ZcGiWorldDraw* wd)
{
ZSoft::UInt32 numPoints = m_points.length();
if (numPoints < 2)
return ZSoft::kTrue;
wd->geometry().polyline(numPoints, m_points.asArrayPtr());
for (ZSoft::UInt32 i = 0; i < numPoints; i++)
{
wd->geometry().circle(m_points[i], 10, ZcGeVector3d::kZAxis);
}
return ZSoft::kTrue;
}
void MyLine::setPoints(const ZcGePoint3dArray& points)
{
m_points = points;
}
rxentrypoint.cpp
#include "pch.h"
#include "tchar.h"
#include <aced.h>
#include <rxregsvc.h>
#include "MyLine.h"
#include <dbapserv.h>
//调用示例
void createMyLine()
{
//当前活动数据库
AcDbDatabase* db = acdbHostApplicationServices()->workingDatabase();
//块表
AcDbBlockTable* blockTable = nullptr;
db->getBlockTable(blockTable, AcDb::OpenMode::kForRead);
//块表记录
AcDbBlockTableRecord* blockTableRec = nullptr;
blockTable->getAt(ACDB_MODEL_SPACE, blockTableRec, AcDb::OpenMode::kForWrite);
blockTable->close();
AcGePoint3dArray vertices;
vertices.append(AcGePoint3d(348.8989, 695.1864, 0.0000));
vertices.append(AcGePoint3d(595.1922, 632.7459, 0.0000));
vertices.append(AcGePoint3d(689.7203, 516.5371, 0.0000));
vertices.append(AcGePoint3d(853.6268, 438.4864, 0.0000));
vertices.append(AcGePoint3d(883.1126, 234.6873, 0.0000));
vertices.append(AcGePoint3d(1094.7167, 215.6083, 0.0000));
vertices.append(AcGePoint3d(1179.7052, 413.3367, 0.0000));
MyLine* line = new MyLine;
line->setPoints(vertices);
blockTableRec->appendZcDbEntity(line);
line->close();
blockTableRec->close();
}
void initapp()
{
acedRegCmds->addCommand(cmd_group_name, _T("bbb"), _T("bbb"), ACRX_CMD_MODAL, createMyLine);
}
void unloadapp()
{
acedRegCmds->removeGroup(cmd_group_name);
}
extern "C" AcRx::AppRetCode zcrxEntryPoint(AcRx::AppMsgCode msg, void* appId)
{
switch (msg)
{
case AcRx::kInitAppMsg:
{
//初始化自定义实体
MyLine::rxInit();
acrxDynamicLinker->unlockApplication(appId);
acrxDynamicLinker->registerAppMDIAware(appId);
initapp();
}
break;
case AcRx::kUnloadAppMsg:
{
//销毁自定义实体
deleteAcRxClass(MyLine::desc());
unloadapp();
}
break;
default:
break;
}
return AcRx::kRetOK;
}
#ifdef _WIN64
#pragma comment(linker, "/export:zcrxEntryPoint,PRIVATE")
#pragma comment(linker, "/export:zcrxGetApiVersion,PRIVATE")
#else // WIN32
#pragma comment(linker, "/export:_zcrxEntryPoint,PRIVATE")
#pragma comment(linker, "/export:_zcrxGetApiVersion,PRIVATE")
#endif





