天气与日历 切换到窄版

 找回密码
 立即注册
中国膜结构网
十大进口膜材评选 十大国产膜材评选 十大膜结构设计评选 十大膜结构公司评选
查看: 45|回复: 0

ObjectArx开发笔记(三)---封装代码

[复制链接]

该用户从未签到

主题

0

回帖

2912

积分

管理员

积分
2912
发表于 2024-6-22 09:46:18 | 显示全部楼层 |阅读模式
[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]

 

 

 

 

ObjectArx开发笔记(三)---封装代码
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|中国膜结构网|中国膜结构协会|进口膜材|国产膜材|ETFE|PVDF|PTFE|设计|施工|安装|车棚|看台|污水池|中国膜结构网_中国空间膜结构协会

GMT+8, 2024-11-1 10:20 , Processed in 0.150845 second(s), 28 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表