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

一、基本概念

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;
    }
    

传送门 返回 列表

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: ObjectARX是一种用于AutoCAD软件定制化开发的API。张帆的《ObjectARX开发实例教程》是一本适合初学者入门的书籍,通过实例的方式对ObjectARX进行系统性讲解。 本书共分为18章,从AutoCAD开发环境的搭建开始讲起,引领读者逐步深入了解ObjectARX。每一章都包含了相关实例,全面讲解了AutoCAD编程基础、ObjectARX、COM技术等相关知识点,让读者能够深入了解各种开发技术,如绘图、编辑、图形操作等。 本书中的实例都是实用性强、综合性好的项目,作者在实例中讲述了ObjectARX的各种技术应用,通过详细讲解及代码演示,使读者能够掌握这些方法,进而灵活应用到实际项目中。此外,文中还介绍了D-BASE文件格式、UNIX操作系统等相关知识,以帮助读者更好地理解AutoCAD的架构原理。 总之,张帆的《ObjectARX开发实例教程》是一本详实而全面的AutoCAD相关书籍,适合有编程基础并对AutoCAD感兴趣的读者学习参考。其中的案例演示丰富,对初学者来说十分友好,同时也能帮助已有一定开发经验的开发人员深造提高。 ### 回答2: ObjectARX是AutoCAD的开放式编程接口,使得开发者可以在AutoCAD上创建个性化的工具和应用程序。这使得AutoCAD成为一个灵活性更高的应用程序。 张帆的《ObjectARX开发实例教程》是一本以实践为主的教程,带领读者从零开始学习如何使用ObjectARX进行自定义开发。教程分为四部分,以一个图像处理器为示例介绍了ObjectARX的编写、调试、应用等技术。 第一部分介绍了ObjectARX的介绍、编程工具的准备和环境的搭建。第二部分从绘图交互的角度介绍了如何利用ObjectARX实现AutoCAD图形处理。第部分以实例介绍了如何利用ObjectARX编写实用功能的插件程序,并介绍了用户界面设计方面的知识。第四部分介绍了如何编写和发布新的应用程序。 在实例教程中,张帆深入深出地剖析了ObjectARX开发的重要概念和技巧,介绍了它们在实际编程过程中的应用。该书比较深入且严谨,可以帮助读者了解ObjectARX中的各种实用细节,同时它也适合有一定编程基础的开发者学习。 总之,《ObjectARX开发实例教程》是入门到高阶的一本好书,对初学者和已有一定开发经验的开发者都非常适用。它既介绍了ObjectARX的基础,又让读者从编写插件和应用程序的角度发掘ObjectARX的灵活性和强大性。这使得读者可以在实践中学习编程技术,提升创造的灵活性和效率。 ### 回答3: “ObjectARX开发实例教程”是一本详细介绍了如何使用Autodesk的ObjectARX编程接口来进行CAD软件二次开发的实战教程。本书作者张帆是一位经验丰富的Autodesk软件开发专家,既有实践经验,也有丰富的教学经验,因此他在本书中将所涉及的内容讲解得非常清晰易懂。 本书从基础概念入手,先介绍了Autodesk的CAD软件和ObjectARX编程接口的基本知识,并且提供了许多实例来帮助读者更好地理解这些知识。在后续章节中,作者则依次介绍了ObjectARX的各个重要模块,如数据库、图形界面、用户界面、3D绘图等,针对每个模块提供了大量的实例代码,并详细讲解了其实现原理和使用技巧。 作为一本实战教程,本书还提供了很多实际应用场景下的编程技巧,例如如何处理大型CAD工程,如何实现CAD联网等等,这些内容将对实际开发非常有帮助。 总之,“ObjectARX开发实例教程”是一本很实用的CAD软件开发教程,对于想要学习ObjectARX编程接口的开发人员来说,读本书将是一种强有力的支持和帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值