|
[code]目录
一、基本概念
1.1 筛选器
1.2 命令流转顺序
1.3 文件排布及思路
二、添加直线
2.1 入口文件acrxEntryPoint.cpp
2.2 业务逻辑Commands类
2.3 编辑器Editor类
2.4 直线Line类
2.5 数据库Database类
一、基本概念
1.1 筛选器
功能:使用Vistual Studio开发项目时,有时源码文件过多,想按功能进行分类管理,可以在类视图里快速切换
添加:
筛选器:在项目上右键单击,选择“添加 | 新建筛选器”
类和头文件:在项目上右键单击,选择“添加 | 类…”,将生成的两个文件拖到筛选器中
注意:筛选器仅是逻辑目录,只是方便分类管理,默认情况下新建的文件均在同一个文件夹下
1.2 命令流转顺序
顺序列表
序号 工作
1 文件acrxEntryPoint.cpp中注册命令(宏acedRegCmds->addCommand),其链接命令与函数
2 函数在内存中创建实体等其他元素
3 打开硬盘中数据库(即dwg文件)中的某个表,将内存中的元素添加进某个表的记录中,释放各级指针
4 文件acrxEntryPoint.cpp中卸载命令(宏acedRegCmds->removeGroup),卸载arx文件
1.3 文件排布及思路
图示
程序行进途径(以AddLine命令为例)
curve类继承关系
二、添加直线
2.1 入口文件acrxEntryPoint.cpp
代码示例
// C++默认创建的通用头文件,每个cpp都引入,公用性高的头文件写进去
#include "StdAfx.h"
// C++创建的系统资源头文件
#include "resource.h"
// 引入头文件用于创建命令
#include "Commands.h"
#define szRDS _RXST("Base")
class CBaseApp : public AcRxArxApp {
public:
CBaseApp () : AcRxArxApp () {}
virtual AcRx::AppRetCode On_kInitAppMsg (void *pkt) {
AcRx::AppRetCode retCode =AcRxArxApp::On_kInitAppMsg (pkt) ;
// 添加命令Commands::AddCommands();
AddCommands();
return (retCode) ;
}
virtual AcRx::AppRetCode On_kUnloadAppMsg (void *pkt) {
// 卸载命令组,组名在Editor::AddCommand中被写死了
acedRegCmds->removeGroup(_T("ToolsBox"));
AcRx::AppRetCode retCode =AcRxArxApp::On_kUnloadAppMsg (pkt) ;
return (retCode) ;
}
...
}
...
2.2 业务逻辑Commands类
功能:此类根据业务需求创建命令,操作函数实现某项功能,也可以用来作为测试用
Commands.h
#include "StdAfx.h"
// 批量添加命令
void AddCommands();
// 画一条直线
void CreateLine();
// 画一条直线,并修改颜色
void ChangeColor();
Commands.cpp
#include "StdAfx.h"
#include "Line.h"
#include "Editor.h"
#include "Commands.h"
// 此函数可以批量添加命令
// 命令:可以想象成是一系列操作的快捷键
void AddCommands()
{ // 添加AddLine命令,命令调用CreateLine函数
Editor::AddCommand(_T("AddLine"), ACRX_CMD_MODAL, CreateLine);
// 添加ChangeLineColor命令,命令调用ChangeColor函数
Editor::AddCommand(_T("ChangeLineColor"), ACRX_CMD_MODAL, ChangeColor);
}
// 定义画直线函数
void CreateLine()
{ // 传入两个3d点给Line类的Add函数
Line::Add(AcGePoint3d(0, 0, 0), AcGePoint3d(100, 100, 0));
}
// 定义改变直线颜色函数
void ChangeColor()
{ // 画直线,并返回直线实体对象在数据库dwg文件中的id
AcDbObjectId lineId = Line::Add(AcGePoint3d(0, 0, 0),
AcGePoint3d(-100, 100, 0));
// 接收传入的id ,并修改颜色为1(红色)
Editor::SetColor(lineId, 1);
}
2.3 编辑器Editor类
功能:此类可编辑实体属性,为静态的,写一次以后可以复用
Editor.h
// 此语句会让所在的文件在一个单独的编译中只被包含一次,加快编译速度
#pragma once
class Editor
{
public:
Editor();
~Editor();
public:
// 添加命令:按命令名(ACHAR是),命令标识符,调用函数传参
static void AddCommand(const ACHAR * cmdName,
Adesk::Int32 commandFlags,
AcRxFunctionPtr FunctionAddr);
// 重载添加命令:按命令名,调用函数传参
static void AddCommand(const ACHAR *cmdName,
AcRxFunctionPtr FunctionAddr);
// 修改颜色:传入数据库实体对象id,颜色索引
static void SetColor(AcDbObjectId entId,
Adesk::UInt16 colorIndex);
// 点选同时获取实体指针、实体id,打开方式
static AcDbEntity *Editor::selectEntity(AcDbObjectId &eId,
AcDb::OpenMode openMode);
};
Editor.cpp
#include "StdAfx.h"
#include "Editor.h"
Editor::Editor(){}
Editor::~Editor(){}
// 添加命令:需要三个参数
void Editor::AddCommand(const ACHAR * cmdName,
Adesk::Int32 commandFlags,
AcRxFunctionPtr FunctionAddr)
{ // 调用了acedRegCmds宏来新增命令,写死命令组为ToolsBox
acedRegCmds->addCommand(_T("ToolsBox"),
cmdName, // 命令名
cmdName, // 命令别名
commandFlags, // 控制参数
FunctionAddr); // 调用函数名
}
// 重载添加命令:需要两个参数
void Editor::AddCommand(const ACHAR *cmdName,
AcRxFunctionPtr FunctionAddr)
{ // 自我调用:调用需要三个参数的AddCommand
AddCommand(cmdName,
ACRX_CMD_MODAL, // 写死这个参数,就只需要两个参数了
FunctionAddr);
}
// 修改颜色:对象ID,颜色索引
void Editor::SetColor(AcDbObjectId entId, Adesk::UInt16 colorIndex)
{ // 断言颜色索引的范围
assert(colorIndex >= 0 && colorIndex <= 256);
// 声明并初始化数据库实体指针
AcDbEntity *pEnt = NULL;
// acdbOpenObject函数:以数据库对象id即entId为线索,从dwg中找到对象读入内存
// 并返回指针给pEnt,kForWrite为写控制参数
// 判断函数返回值是否正常Acad::eOk
if (acdbOpenObject(pEnt, entId, AcDb::kForWrite) == Acad::eOk)
{ // AcDbEntity类对象的方法setColorIndex,设置颜色
pEnt->setColorIndex(colorIndex);
// 操作完必须关闭指针
pEnt->close();
}
// 打开错误,打印原因
else
{ // 此函数类似C语言的printf
acutPrintf(_T("\n无法更改对象颜色"));
}
}
// 点选获取实体指针:返回实体id,打开方式
AcDbEntity *Editor::selectEntity(AcDbObjectId &eId, AcDb::OpenMode openMode)
{
ads_name en;
ads_point pt;
if (acedEntSel(NULL, en, pt) != RTNORM)
{
return NULL;
}
acdbGetObjectId(eId, en);
AcDbEntity *pEnt;
acdbOpenObject(pEnt, eId, openMode);
return pEnt;
}
2.4 直线Line类
功能:此类为画直线,为静态的,写一次以后可以复用
Line.h
#pragma once
class Line
{
public:
Line();
~Line();
public:
// 函数返回所画直线的对象ID为后续修改属性操作做准备:
// 两个3d点,一个数据库指针(有默认值,固定的)
static AcDbObjectId Add(const AcGePoint3d &startPoint,
const AcGePoint3d &endPoint,
AcDbDatabase *pDb =
acdbHostApplicationServices()->
workingDatabase());
};
Line.cpp
#include "StdAfx.h"
#include "Line.h"
// 用于将内存中的实体添加到数据库文件dwg中
#include "Database.h"
Line::Line() {}
Line::~Line() {}
AcDbObjectId Line::Add(const AcGePoint3d &startPoint,
const AcGePoint3d &endPoint,
AcDbDatabase *pDb)
{ // AcDbLine类,继承自AcDbCurve类,传入两个点内存中创建直线对象
AcDbLine *pLine = new AcDbLine(startPoint, endPoint);
// 将直线对象的指针、数据库对象指针传入PostToModelSpace函数添加到数据库文件dwg中
return Database::PostToModelSpace(pLine, pDb);
}
2.5 数据库Database类
功能:此类为数据库操作,为静态的,写一次以后可以复用
代码思路:
获得数据库指针==>获得块表指针==>获得块表记录指针==>
在其末尾添加内存中创建的块表记录==>
关闭块表记录指针==>关闭块表==>清空内存中块表记录
Database.h
#pragma once
class Database
{
public:
Database();
~Database();
public:
// 在模型空间中创建对象:传入实体对象指针,数据库指针(头文件有默认值)
static AcDbObjectId PostToModelSpace(AcDbEntity *pEnt, AcDbDatabase *pDb =
acdbHostApplicationServices()->workingDatabase());
// 获取层上所有实体:图层名(默认为空)、数据库对象
static AcDbObjectIdArray GetAllEntIds(const ACHAR *layer = NULL, AcDbDatabase *pDb =
acdbHostApplicationServices()->workingDatabase());
// 总目录6.1:获得模型空间的范围盒:数据库指针
static AcDbExtents GetModelSpaceExtent(AcDbDatabase *pDb =
acdbHostApplicationServices()->workingDatabase());
};
Database.cpp
#include "StdAfx.h"
#include "Database.h"
Database::Database(){}
Database::~Database(){}
// 在模型空间中创建对象:传入实体对象指针,数据库指针(头文件有默认值)
AcDbObjectId Database::PostToModelSpace(AcDbEntity *pEnt, AcDbDatabase *pDb)
{ // 声明并初始化块表对象指针
AcDbBlockTable *pBlkTbl = NULL;
// 声明并初始化错误状态
Acad::ErrorStatus es;
// 数据库对象调用,以读方式打开块表,将块表指针赋值给pBlkTbl
es = pDb->getBlockTable(pBlkTbl, AcDb::kForRead);
// 纠错函数1:如果块表获取失败;若没纠错函数,cad会直接崩溃关闭
if (es != Acad::eOk)
{ // _RXST,宽字符串另一种写法,acadErrorStatusText函数将es转换为字符串
acutPrintf(_RXST("\n块表打开失败,错误代码:%s"),
acadErrorStatusText(es));
// 返回数据库对象id为空,跳出函数
return AcDbObjectId::kNull;
}
// 声明并初始化块表记录对象指针
AcDbBlockTableRecord *pBlkTblRcd = NULL;
// 块表对象指针调用getAt方法获得块表记录指针pBlkTblRcd
// 参数:模型空间(acdb.h中的一个宏)、块表记录指针(接收返回值)、以写方式定位
es = pBlkTbl->getAt(ACDB_MODEL_SPACE, pBlkTblRcd, AcDb::kForWrite);
// 纠错函数2:如果块表记录获取失败;若没纠错函数,cad会直接崩溃关闭
if (es != Acad::eOk)
{
acutPrintf(_RXST("\n模型空间块表记录打开失败,错误代码:%s"),
acadErrorStatusText(es));
// 关闭已经打开的块表
pBlkTbl->close();
// 返回数据库对象id为空,跳出函数
return AcDbObjectId::kNull;
}
// 已经获取到块表记录指针,可以关闭块表了
pBlkTbl->close();
// 声明数据库对象ID变量
AcDbObjectId outId;
// 块表记录对象 指针 调用 函数appendAcDbEntity,
// 将实体对象指针pEnt指向的内存中的记录添加到数据库文件dwg中,块表记录的最后
// 并将添加成功后的实体对象id赋值给outId
es = pBlkTblRcd->appendAcDbEntity(outId, pEnt);
// 纠错函数3:如果块表记录添加失败;若没纠错函数,cad会直接崩溃关闭
if (es != Acad::eOk)
{
acutPrintf(_RXST("\n无法在模型空间中添加实体,错误代码:%s"),
acadErrorStatusText(es));
// 关闭块表记录
pBlkTblRcd->close();
// 返回数据库对象id为空,跳出函数
return AcDbObjectId::kNull;
}
// 若一切正常,清空数据库实体对象指针指向的内存
pEnt->close();
// 关闭块表记录
pBlkTblRcd->close();
// 返回实体对象ID给程序
return outId;
}
// 获取层上所有实体:图层名(默认为空)、数据库对象
AcDbObjectIdArray Database::GetAllEntIds(const ACHAR *layer, AcDbDatabase *pDb)
{
AcDbObjectIdArray entIds;
// 图层过滤控制符
bool bFilterLayer = false;
AcDbObjectId layerId;
// 如果传入了图层名
if (layer != NULL)
{ // 获取层表->判断是否有该图层->获得层表id->设置过滤控制符
AcDbLayerTable *pLayerTbl = NULL;
pDb->getLayerTable(pLayerTbl, AcDb::kForRead);
// 容错函数:如果层表不包含该图层,关闭层表,返回空id列表
if (!pLayerTbl->has(layer))
{
pLayerTbl->close();
return entIds;
}
pLayerTbl->getAt(layer, layerId);
pLayerTbl->close();
bFilterLayer = true;
}
// 获取数据库块表->数据库块表记录->关闭块表
AcDbBlockTable *pBlkTbl = NULL;
pDb->getBlockTable(pBlkTbl, AcDb::kForRead);
AcDbBlockTableRecord *pBlkTblRcd = NULL;
pBlkTbl->getAt(ACDB_MODEL_SPACE, pBlkTblRcd, AcDb::kForRead);
pBlkTbl->close();
// 遍历数据库块表记录
AcDbBlockTableRecordIterator *pItr = NULL;
pBlkTblRcd->newIterator(pItr);
for (pItr->start();!pItr->done();pItr->step())
{ // 如果过滤控制符为真,获得该层上所有实体的id
if (bFilterLayer == true)
{ // 获得每个实体的指针
AcDbEntity *pEnt;
pItr->getEntity(pEnt, AcDb::kForRead);
// 如果实体的图层为指定过滤的图层
if (pEnt->layerId() == layerId)
{ // 将实体id添加进id列表 entIds 中
entIds.append(pEnt->objectId());
}
pEnt->close();
}
else
{
// 将所有实体id添加进id列表 entIds 中
AcDbObjectId objId;
pItr->getEntityId(objId);
entIds.append(objId);
}
}
delete pItr;
pBlkTblRcd->close();
return entIds;
}
// 总目录6.1:获得模型空间的范围盒:数据库指针
AcDbExtents Database::GetModelSpaceExtent(AcDbDatabase *pDb)
{ // 获得数据库块表指针-》获得模型空间的块表记录指针
AcDbBlockTable *pBlkTbl = NULL;
pDb->getBlockTable(pBlkTbl, AcDb::kForRead);
AcDbBlockTableRecord *pBlkTblRcd = NULL;
pBlkTbl->getAt(ACDB_MODEL_SPACE, pBlkTblRcd, AcDb::kForRead);
pBlkTbl->close();
// 计算包含块表记录中所有实体的最小范围盒
AcDbExtents extent;
Acad::ErrorStatus es = extent.addBlockExt(pBlkTblRcd);
pBlkTblRcd->close();
// 如果范围盒生成成功
if (es != Acad::eOk)
{ // 遍历获取所有模型实体的指针
AcDbObjectIdArray allEnts = GetAllEntIds(NULL, pDb);
for (int i = 0; i < allEnts.length(); i++)
{
AcDbEntity *pEnt = NULL;
if (acdbOpenObject(pEnt, allEnts.at(i), AcDb::kForRead) == Acad::eOk)
{ // 获得实体的范围盒
AcDbExtents extents;
if (pEnt->getGeomExtents(extents) == Acad::eOk)
{ // 累积型扩大范围盒
extent.addExt(extents);
}
pEnt->close();
}
}
}
// 返回范围盒
return extent;
}
[/code] |
|