【ObjectARX】--创建和访问图形数据库(DwgDatabase)

2023-11-02

(1)使用ObjectARX创建新工程DwgDatabase,选择MFC支持。

(2)注册一个命令CreateDwg创建一个新的图形文件,并保存在AutoCAD的安装路径中.

实现函数为:

static void AAAMyGroupCreateDwg() {
		// 创建新的图形数据库,分配内存空间
		AcDbDatabase *pDb = new AcDbDatabase(true, false);

		AcDbBlockTable *pBlkTbl = NULL;
		pDb->getSymbolTable(pBlkTbl, AcDb::kForRead);

		AcDbBlockTableRecord *pBlkTblRcd = NULL;
		pBlkTbl->getAt(ACDB_MODEL_SPACE, pBlkTblRcd,
			AcDb::kForWrite); //返回指向打开的pBlkTblRcd
		pBlkTbl->close();

		//创建两个圆
		AcDbCircle *pCir1 = new AcDbCircle(AcGePoint3d(1, 1, 1), 
			AcGeVector3d(0, 0, 1),1.0);
		pBlkTblRcd->appendAcDbEntity(pCir1);
		pCir1->close();
		AcDbCircle *pCir2 = new AcDbCircle(AcGePoint3d(4, 4, 4), 
			AcGeVector3d(0, 0, 1), 2.0);
		pBlkTblRcd->appendAcDbEntity(pCir2);
		pCir2->close();
		pBlkTblRcd->close();

		//获得acad.exe的位置
		CString acadPath;
		GetAcadPath(acadPath);
		
		//去掉路径最后的"acad.exe"字符串,得到AutoCAD安装路径
		acadPath = acadPath.Left(acadPath.GetLength() - 8);
		CString filePath = acadPath + TEXT("test.dwg");

		//使用savaAs成员函数时,必须指定包含dwg扩展名的文件名称
		pDb->saveAs(filePath);

		delete pDb;  //pDb不是数据库的常驻对象,必须手工销毁

	}

 获得当前运行的AutoCAD程序的acad.exe的位置 :

 GetAcadPath函数实现:(注意应写在命令CreateDwg函数的前面)

	static bool GetAcadPath(CString &acadPath)
	{
		DWORD dwRet = ::GetModuleFileName(acedGetAcadWinApp()
			->m_hInstance, acadPath.GetBuffer(_MAX_PATH), _MAX_PATH);
		acadPath.ReleaseBuffer();

		if (dwRet == 0)
		{
			return false;
		}
		else
		{
			return true;
		}
	}

(3)注册一个命令ReadDwg,读取CreateDwg命令中创建的test.dwg文件,在窗口中显示图形数据库的模型空间块表记录中所有实体的实体名。

ReadDwg命令的实现函数为:

static void AAAMyGroupReadDwg() {
		// 使用false作为构造函数的参数,创建一个空的图形数据库
		// 这样保证图形数据库仅仅包含读入的内容    
		AcDbDatabase *pDb = new AcDbDatabase(false);

		// AcDbDatabase::readDwgFile()函数可以自动添加dwg扩展名 
		CString acadPath;
		GetAcadPath(acadPath);
		// 去掉路径最后的"acad.exe"字符串
		acadPath = acadPath.Left(acadPath.GetLength() - 8);
		CString filePath = acadPath + "test.dwg";
		pDb->readDwgFile(filePath,(AcDbDatabase::OpenMode)_SH_DENYWR);

		// 获得模型空间的所有实体
		AcDbObjectIdArray allEntIds = CDwgDatabaseUtil::GetAllEntityIds(NULL, pDb);
		for (int i = 0; i < allEntIds.length(); i++)
		{
			AcDbEntity *pEnt = NULL;
			if (acdbOpenObject(pEnt, allEntIds[i], AcDb::kForRead) == Acad::eOk)
			{
				acutPrintf(TEXT("\n类名称: %s"), (pEnt->isA())->name());
				pEnt->close();
			}
		}

		// 删除图形数据库
		delete pDb;
	}

其中, 

 GetAllEntityIds函数的声明:

	// 获得模型空间所有实体ID数组(可以将图层作为过滤条件)
	static AcDbObjectIdArray GetAllEntityIds(const TCHAR* layerName = NULL, 
		AcDbDatabase *pDb = acdbHostApplicationServices()->workingDatabase());

  GetAllEntityIds函数的实现:

AcDbObjectIdArray CDwgDatabaseUtil::GetAllEntityIds( const TCHAR* layerName, AcDbDatabase *pDb )
{
	AcDbObjectIdArray entIds;		// 满足条件的实体集合
	bool bFilterLayer = false;			// 是否需要过滤图层
	AcDbObjectId layerId;
	// 获得指定图层的对象ID
	if (layerName != NULL)
	{
		AcDbLayerTable *pLayerTbl = NULL;
		acdbHostApplicationServices()->workingDatabase()
			->getSymbolTable(pLayerTbl, AcDb::kForRead);
		if (!pLayerTbl->has(layerName))
		{
			pLayerTbl->close();
			return entIds;
		}
		pLayerTbl->getAt(layerName, 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 *it = NULL;
	pBlkTblRcd->newIterator(it);
	for (it->start(); !it->done(); it->step())
	{
		AcDbEntity *pEnt = NULL;
		Acad::ErrorStatus es = it->getEntity(pEnt, AcDb::kForRead);
		if (es == Acad::eOk)
		{
			if (bFilterLayer)				// 过滤图层
			{
				if (pEnt->layerId() == layerId)
				{
					entIds.append(pEnt->objectId());
				}				
			}
			else
			{
				entIds.append(pEnt->objectId());
			}
			
			pEnt->close();
		}
		else
		{
			acutPrintf(TEXT("\nCDwgDatabaseUtil::GetAllEntityIds中打开实体失败(错误代码:%d)."), (int)es);
		}
	}
	delete it;
	pBlkTblRcd->close();
	
	return entIds;
}

(4)创建一个C++类CViewUtil,并在类中添加DwgZoomExtent函数来调整后台创建的DWG文件的默认视图范围。

DwgZoomExtent函数的实现代码:

void CViewUtil::DwgZoomExtent(AcDbDatabase *pDb)
{
	assert(pDb);

	//获得模型空间所有实体的最小包围框
	AcDbExtents ext = CDwgDatabaseUtil::GetModeSpaceExtent(pDb);
	AcDbViewportTable* pViewportTable = NULL;
	if (pDb->getViewportTable(pViewportTable, AcDb::kForWrite) == Acad::eOk)
	{
		AcDbViewportTableRecord *pRecord = NULL;
		if (pViewportTable->getAt(TEXT("*ACTIVE"), pRecord, AcDb::kForWrite) == 
			Acad::eOk)
		{
			AcGePoint3d center = CGePointUtil::GetMiddlePoint(ext.minPoint(),
				ext.maxPoint());
			double height = ext.maxPoint().y - ext.minPoint().y;
			double width = ext.maxPoint().x - ext.minPoint().x;
			pRecord->setCenterPoint(CConvertUtil::ToPoint2d(center));
			
			pRecord->setHeight(height * 1.2);
			pRecord->setWidth(width * 1.2);
			pRecord->close();
		
		}
		pViewportTable->close();
	}
}

代码段getViewportTable(pViewportTable, AcDb::kForWrite) 表示: 

  在指定的模式 AcDb::kForWrite下打开数据库的Viewport表。pViewportTable指针被填入Viewport表的地址。
如果打开是成功的,返回Acad::eOk。 

代码段getAt(TEXT("*ACTIVE"), pRecord, AcDb::kForWrite) 表示:

  这个函数在带有名称为"*ACTIVE"的记录中搜索AbstractViewTable。如果找到,它将在openMode指定的模式AcDb::kForWrite下打开记录。如果open operation成功,它将返回pRecord指向打开的record。

代码段setHeight(height * 1.2) 表示:

这个函数将viewport的窗口设置为高度height * 1.2 的绘制单元。

 

GetModeSpaceExtent函数的是实现:

注意声明为    static成员。

AcDbExtents CDwgDatabaseUtil::GetModeSpaceExtent(AcDbDatabase *pDb)
{
	AcDbBlockTable *pBlkTbl = NULL;
	pDb->getBlockTable(pBlkTbl, AcDb::kForRead); //pBlkTbl指针获取块表的地址。

	//获得模型空间的块表记录
	AcDbBlockTableRecord *pBlkTblRcd = NULL;
	pBlkTbl->getAt(ACDB_MODEL_SPACE, pBlkTblRcd, AcDb::kForRead);
	     //搜索记录ACDB_MODEL_SPACE,pBlkTblRcd指向打开的记录

	pBlkTbl->close();

	AcDbExtents extent; //l类AcDbExtents:它体现了一个三维空间中的box,
	                    //它的边缘与WCS的轴平行。这个盒子在AcDbExtents对象的私有数据中
	                    //表示示为最小点(minPoint)和最大点(maxPoint)。
	Acad::ErrorStatus es = extent.addBlockExt(pBlkTblRcd);
			//addBlockExt计算一个最小的box,它包含了由pBlkTblRcd所指向的块中的所有实体

	pBlkTblRcd->close();

	//如果图形数据库不是当前的工作数据库,则有时候直接获取模型空间的范围会失败
	if (es != Acad::eOk)
	{
		AcDbObjectIdArray allEnts = GetAllEntityIds(NULL, pDb);
		for (int i = 0; i < allEnts.length(); i++)
		{
			AcDbEntity *pEnt = NULL;
			if (acdbOpenObject(pEnt, allEnts[i], AcDb::kForRead) == Acad::eOk)
			{
				AcDbExtents ext;
				if (pEnt->getGeomExtents(ext) == Acad::eOk) //输出实体的ext
				{
					extent.addExt(ext);//展开由该extent定义的box,并包含由ext定义的box
				}
				pEnt->close();
			}
		}
	}
	return extent;
}

ToPoint2d函数的实现:

AcGePoint2d CConvertUtil::ToPoint2d(const AcGePoint3d &point3d)
{
	return AcGePoint2d(point3d.x, point3d.y);
}

GetMiddlePoint函数的实现:

AcGePoint3d CGePointUtil::GetMiddlePoint(const AcGePoint3d &startPoint, const AcGePoint3d &endPoint)
{
	double x = (startPoint.x + endPoint.x) * 0.5;
	double y = (startPoint.y + endPoint.y) * 0.5;
	double z = (startPoint.z + endPoint.z) * 0.5;

	return AcGePoint3d(x, y, z);
}

(5) 注册CreateDwg2命令,使用公共函数修改创建后台图形数据库的代码,并且在创建图形库之后对其视图进行调整。

实现代码为:

static void AAAMyGroupCreateDwg2() {
		// 创建新的图形数据库,分配内存空间
		AcDbDatabase *pDb = new AcDbDatabase(true, false);
		
		//创建两个圆
		AcDbCircle *pCir1 = new AcDbCircle(AcGePoint3d(1, 1, 1),
			AcGeVector3d(0, 0, 1), 1.0);
		CDwgDatabaseUtil::PostToModelSpace(pCir1, pDb);
		AcDbCircle *pCir2 = new AcDbCircle(AcGePoint3d(4, 4, 4), 
			AcGeVector3d(0, 0, 1), 2.0);

		CDwgDatabaseUtil::PostToModelSpace(pCir2, pDb);

		//调整DWG文件视图
		CViewUtil::DwgZoomExtent(pDb);

		//获得acad.exe的位置
		CString acadPath;
		GetAcadPath(acadPath);

		//去掉路径最后的"acad.exe"字符串,得到AutoCAD安装路径
		acadPath = acadPath.Left(acadPath.GetLength() - 8);
		CString filePath = acadPath + TEXT("test2.dwg");

		//使用saveAs成员函数时,必须指定包含dwg扩展名的文件名称
		pDb->saveAs(filePath);

		delete pDb;  //pDb不是数据库的常驻对象,必须手工销毁

	}

其中,

PostToModelSpace函数的实现:

AcDbObjectId CDwgDatabaseUtil::PostToModelSpace(AcDbEntity *pEnt, AcDbDatabase *pDb)
{
	// 检查输入参数的有效性
	assert(pEnt);		// 等效于assert (pEnt != NULL);

						// 获得当前图形数据库的块表
	AcDbBlockTable *pBlkTbl = NULL;
	pDb->getBlockTable(pBlkTbl, AcDb::kForRead);

	// 获得模型空间对应的块表记录
	AcDbBlockTableRecord *pBlkTblRcd = NULL;
	pBlkTbl->getAt(ACDB_MODEL_SPACE, pBlkTblRcd, AcDb::kForWrite);
	pBlkTbl->close();

	// 将实体添加到模型空间的块表记录
	AcDbObjectId entId;
	Acad::ErrorStatus es = pBlkTblRcd->appendAcDbEntity(entId, pEnt);
	if (es != Acad::eOk)
	{
		pBlkTblRcd->close();
		delete pEnt;	// 添加失败时,要delete
		pEnt = NULL;

		return AcDbObjectId::kNull;
	}

	// 关闭模型空间块表记录和实体
	pBlkTblRcd->close();
	pEnt->close();

	return entId;
}

添加头文件:

#include "DwgDatabaseUtil.h"
#include "ViewUtil.h"

 

效果:

①在AutoCAD2018加载ARX程序,在命令栏执行CreateDwg命令,然后选择【文件/打开】菜单项,打开生成的test.dwg,在CAD的安装目录,比如我的:D:\Program Files\Autodesk\CAD_2018_64bit\AutoCAD 2018;

然后执行ZOOM命令并选择E选项:

②执行ReadDwg命令,观察命令窗口输出结果;

③执行CreateDwg2命令,同样在安装目录下打开生成test2.dwg文件。从下图中可见图形显示范围自动自行调整:

 

总结思路:

 

项目的完整源代码:

   https://pan.baidu.com/s/1GV7Eq58F4TFjZeGZ_pIJjQ 

 

 参考资料:

     《AutoCAD ObjectARX(VC)开发基础与实例教程》

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【ObjectARX】--创建和访问图形数据库(DwgDatabase) 的相关文章

随机推荐

  • 西门子S7-200 PLC接地和接线

    对于所有的电器设备 接地和接线是非常重要的 它能够确保系统具备最优的操作特性 同时能够为系统提供更好的电子噪声保护 在接地和接线之前 必须先确保设备的电源已被切断 也要保证与该设备相关的设备电源已被切断 在对S7 200及其相关设备接线时
  • 从零推导一个多层感知机神经网络(附matlab源码,可直接运行)

    可以先跳到代码示例部分看看效果 算法基础 激活函数 损失函数 链式法则 向量求导 代码示例 代码文件结构说明 函数脚本 可运行脚本 效果演示 代码下载链接 算法基础 激活函数 激活函数的作用 激活函数把非线性引入了神经网络 后面的代码用到的
  • pnpm替换lerna+yarn的踩坑记录

    如果有使用monorepo的需求 lerna yarn会是很多开发者的选择 然而在实际开发中 lerna的很多功能我们并不需要 同时它也存在着一定的上手学习成本 而且 yarn也会存在一些问题比如多个项目会重复安装依赖 幽灵依赖等 这时候不
  • redis命令行基本操作

    文章目录 基本概念 对数据库的操作 对数据的操作 增删改查 数值操作 整数数据 浮点数据 其他 基本概念 redis的键是区分大小写的 user 与 USER 是两个键 配置文件 redis conf 对数据库的操作 SELECT
  • mpeg4视频中,I帧、p帧、B帧的判定

    mpeg4的每一帧开头是固定的 00 00 01 b6 那么我们如何判断当前帧属于什么帧呢 在接下来的2bit 将会告诉我们答案 注意 是2bit 不是byte 下面是各类型帧与2bit的对应关系 00 I Frame 01 P Frame
  • PBFT简单介绍

    PBFT是一种常用于联盟链的共识算法 中文名是实用拜占庭容错算法 首先用户发送交易到区块链网络中 主节点接收到交易并向其他节点进行广播 其他节点收到广播后记录下交易并广播给其他节点 当各节点收到相同交易的广播次数 包括节点自己本身一次 达到
  • windows10+python3.6+anaconda+pytorch-cpu的初步环境搭建

    windows10 python3 6 anaconda pytorch cpu的初步环境搭建 安装pytorch cpu 新建环境 1 利用anaconda进行创建新的环境 cmd conda create n pytorch pytho
  • 2018年LeetCode高频算法面试题刷题笔记——分割回文串(字符串)

    1 解答之前的碎碎念 这个题我的想法是 第一刀依次切在第1 s length 2个元素后面 得到两个字符串s0和s1 首先判断s0整体是否为回文 不是则第一刀的位置 1 然后再检测s1整体是否为回文 并在s1的第1 s1 length 2个
  • C++关于(*i)->n为何要加括号

    include
  • Linux基础命令--文件和目录管理命令

    目录 常用文件和目录管理命令 1 ls命令 ls命令还支持一些选项和参数 例如 2 ll命令 基本用法如下 3 cd命令 除了基础用法外 cd命令还有一些常用的选项 如 4 pwd命令 基础用法如下 5 mkdir命令 基础用法如下 6 r
  • Dilated Convolution介绍

    Dilated Convolution介绍 相关的两篇论文分别是 ICLR2016 MULTI SCALE CONTEXT AGGREGATION BY DILATED CONVOLUTIONS 和 CVPR2017 Dilated Res
  • vcruntime140.dll重新安装方法,vcruntime140.dll修复教程

    vcruntime140 dll是Microsoft Visual C Redistributable的一部分 它是Windows操作系统上非常重要的一个动态链接库文件 这个文件包含了一些运行时库函数 用于支持运行在Windows上使用了M
  • C# RestSharp,Body提交

    关于RestSharp Body提交 需要引用RestSharp 遇到一个问题 使用Httprequest提交Post请求时 各种值传不过去 使用Postman用同样的 添加请求头 传输json格式亦然 经过大佬指点 用Postman里面的
  • MATLAB删除任意字符

    删除空格 s isspace s 去除空格 删除字符串中所有的16进制的0 char2asc2 abs s 转asc2 char2asc2 char2asc2 0 删除NULL 0 s char char2asc2 删除字符串中所有的16进
  • 在Windows下使用Curl工具完美操作ElasticSearch

    首先可以从 http curl haxx se download html上下载并安装Windows环境下的Curl 安装完成后 将Curl的I386目录的完整路径添加到Windows的Path环境变量中 C Users Carl gt c
  • 专利与论文-1:为什么要写专利?专利有什么好处?

    前言 很多人 都认为写专利没什么多大的用处 不过是个人赚一点公司申请专利的奖励而已 对个人和公司 用处都不是大 还不如做学习一些专业技能或做一些实际项目 花在专利上的实际不太值得 随着时间和知识双重积累 越来越会发现专利 无论对于个人还公司
  • 强化学习代码实战入门

    这是一个易理解的 demo 300行左右 可以作为RL的入门代码 辅助基础公式的理解 这个是我自己的学习笔记 三连留下邮箱 可以直接发送完整的代码标注文件 如有错误 麻烦指出 我已经蛮久没写博了 上一篇RL博客也快一年半了 很久没做这一块了
  • Java生成二维码并解决中文乱码问题

    Java生成二维码并解决中文乱码问题 引入依赖 JAVA代码 引入依赖 maven工程
  • ESP32+st7789/ili9341运行LVGL例程,依赖ESP-IDF编译lv_port_esp32官方Demo(1)

    LVGL是一个C语言编写的免费的开源图形库 其提供了用于嵌入式GUI的各种元素 用户可以利用丰富的图形库资源 在消耗极低内存的情况下构建视觉效果丰富多彩的GUI 只需 64kB 闪存和 8kB RAM 就足以满足简单的用户界面 LVGL 可
  • 【ObjectARX】--创建和访问图形数据库(DwgDatabase)

    1 使用ObjectARX创建新工程DwgDatabase 选择MFC支持 2 注册一个命令CreateDwg创建一个新的图形文件 并保存在AutoCAD的安装路径中 实现函数为 static void AAAMyGroupCreateDw