找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 954|回复: 0

[分享] 创建和访问图形数据库(DwgDatabase)

[复制链接]

已领礼包: 13个

财富等级: 恭喜发财

发表于 2019-1-21 08:17:41 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
本帖最后由 LoveArx 于 2019-1-21 08:17 编辑

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

创建和访问图形数据库(DwgDatabase)-1.jpg

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

实现函数为:

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

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

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

  10.                 //创建两个圆
  11.                 AcDbCircle *pCir1 = new AcDbCircle(AcGePoint3d(1, 1, 1),
  12.                         AcGeVector3d(0, 0, 1),1.0);
  13.                 pBlkTblRcd->appendAcDbEntity(pCir1);
  14.                 pCir1->close();
  15.                 AcDbCircle *pCir2 = new AcDbCircle(AcGePoint3d(4, 4, 4),
  16.                         AcGeVector3d(0, 0, 1), 2.0);
  17.                 pBlkTblRcd->appendAcDbEntity(pCir2);
  18.                 pCir2->close();
  19.                 pBlkTblRcd->close();

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

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

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

  30.         }

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

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

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

  6.                 if (dwRet == 0)
  7.                 {
  8.                         return false;
  9.                 }
  10.                 else
  11.                 {
  12.                         return true;
  13.                 }
  14.         }
  15. (3)注册一个命令ReadDwg,读取CreateDwg命令中创建的test.dwg文件,在窗口中显示图形数据库的模型空间块表记录中所有实体的实体名。

  16. ReadDwg命令的实现函数为:

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

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

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

  39.                 // 删除图形数据库
  40.                 delete pDb;
  41.         }

其中,

GetAllEntityIds函数的声明:

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

  5. AcDbObjectIdArray CDwgDatabaseUtil::GetAllEntityIds( const TCHAR* layerName, AcDbDatabase *pDb )
  6. {
  7.         AcDbObjectIdArray entIds;                // 满足条件的实体集合
  8.         bool bFilterLayer = false;                        // 是否需要过滤图层
  9.         AcDbObjectId layerId;
  10.         // 获得指定图层的对象ID
  11.         if (layerName != NULL)
  12.         {
  13.                 AcDbLayerTable *pLayerTbl = NULL;
  14.                 acdbHostApplicationServices()->workingDatabase()
  15.                         ->getSymbolTable(pLayerTbl, AcDb::kForRead);
  16.                 if (!pLayerTbl->has(layerName))
  17.                 {
  18.                         pLayerTbl->close();
  19.                         return entIds;
  20.                 }
  21.                 pLayerTbl->getAt(layerName, layerId);
  22.                 pLayerTbl->close();

  23.                 bFilterLayer = true;
  24.         }
  25.         
  26.         // 获得块表
  27.         AcDbBlockTable *pBlkTbl = NULL;
  28.         pDb->getBlockTable(pBlkTbl, AcDb::kForRead);
  29.         
  30.         // 获得模型空间的块表记录
  31.         AcDbBlockTableRecord *pBlkTblRcd = NULL;
  32.         pBlkTbl->getAt(ACDB_MODEL_SPACE, pBlkTblRcd, AcDb::kForRead);
  33.         pBlkTbl->close();
  34.         
  35.         // 创建遍历器,依次访问模型空间的每一个实体
  36.         AcDbBlockTableRecordIterator *it = NULL;
  37.         pBlkTblRcd->newIterator(it);
  38.         for (it->start(); !it->done(); it->step())
  39.         {
  40.                 AcDbEntity *pEnt = NULL;
  41.                 Acad::ErrorStatus es = it->getEntity(pEnt, AcDb::kForRead);
  42.                 if (es == Acad::eOk)
  43.                 {
  44.                         if (bFilterLayer)                                // 过滤图层
  45.                         {
  46.                                 if (pEnt->layerId() == layerId)
  47.                                 {
  48.                                         entIds.append(pEnt->objectId());
  49.                                 }                                
  50.                         }
  51.                         else
  52.                         {
  53.                                 entIds.append(pEnt->objectId());
  54.                         }
  55.                         
  56.                         pEnt->close();
  57.                 }
  58.                 else
  59.                 {
  60.                         acutPrintf(TEXT("\nCDwgDatabaseUtil::GetAllEntityIds中打开实体失败(错误代码:%d)."), (int)es);
  61.                 }
  62.         }
  63.         delete it;
  64.         pBlkTblRcd->close();
  65.         
  66.         return entIds;
  67. }

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

DwgZoomExtent函数的实现代码:

  1. void CViewUtil::DwgZoomExtent(AcDbDatabase *pDb)
  2. {
  3.         assert(pDb);

  4.         //获得模型空间所有实体的最小包围框
  5.         AcDbExtents ext = CDwgDatabaseUtil::GetModeSpaceExtent(pDb);
  6.         AcDbViewportTable* pViewportTable = NULL;
  7.         if (pDb->getViewportTable(pViewportTable, AcDb::kForWrite) == Acad::eOk)
  8.         {
  9.                 AcDbViewportTableRecord *pRecord = NULL;
  10.                 if (pViewportTable->getAt(TEXT("*ACTIVE"), pRecord, AcDb::kForWrite) ==
  11.                         Acad::eOk)
  12.                 {
  13.                         AcGePoint3d center = CGePointUtil::GetMiddlePoint(ext.minPoint(),
  14.                                 ext.maxPoint());
  15.                         double height = ext.maxPoint().y - ext.minPoint().y;
  16.                         double width = ext.maxPoint().x - ext.minPoint().x;
  17.                         pRecord->setCenterPoint(CConvertUtil::ToPoint2d(center));
  18.                         
  19.                         pRecord->setHeight(height * 1.2);
  20.                         pRecord->setWidth(width * 1.2);
  21.                         pRecord->close();
  22.                
  23.                 }
  24.                 pViewportTable->close();
  25.         }
  26. }

代码段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成员。

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

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

  9.         pBlkTbl->close();

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

  15.         pBlkTblRcd->close();

  16.         //如果图形数据库不是当前的工作数据库,则有时候直接获取模型空间的范围会失败
  17.         if (es != Acad::eOk)
  18.         {
  19.                 AcDbObjectIdArray allEnts = GetAllEntityIds(NULL, pDb);
  20.                 for (int i = 0; i < allEnts.length(); i++)
  21.                 {
  22.                         AcDbEntity *pEnt = NULL;
  23.                         if (acdbOpenObject(pEnt, allEnts, AcDb::kForRead) == Acad::eOk)
  24.                         {
  25.                                 AcDbExtents ext;
  26.                                 if (pEnt->getGeomExtents(ext) == Acad::eOk) //输出实体的ext
  27.                                 {
  28.                                         extent.addExt(ext);//展开由该extent定义的box,并包含由ext定义的box
  29.                                 }
  30.                                 pEnt->close();
  31.                         }
  32.                 }
  33.         }
  34.         return extent;
  35. }

ToPoint2d函数的实现:

AcGePoint2d CConvertUtil::ToPoint2d(const AcGePoint3d &point3d)
{
        return AcGePoint2d(point3d.x, point3d.y);
}
GetMiddlePoint函数的实现:

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

  6.         return AcGePoint3d(x, y, z);
  7. }

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

实现代码为:

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

  11.                 CDwgDatabaseUtil::PostToModelSpace(pCir2, pDb);

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

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

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

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

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

  23.         }

其中,

PostToModelSpace函数的实现:

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

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

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

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

  20.                 return AcDbObjectId::kNull;
  21.         }

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

  25.         return entId;
  26. }

添加头文件:

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


效果:

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

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

创建和访问图形数据库(DwgDatabase)-2.jpg

②执行ReadDwg命令,观察命令窗口输出结果;
创建和访问图形数据库(DwgDatabase)-3.jpg
③执行CreateDwg2命令,同样在安装目录下打开生成test2.dwg文件。从下图中可见图形显示范围自动自行调整:



总结思路:

创建和访问图形数据库(DwgDatabase)-5.jpg

项目的完整源代码:


请点击此处下载

请先注册会员后在进行下载

已注册会员,请先登录后下载

文件名称:代码(提取码:k628 ) 
下载次数:2  文件大小:0 Bytes  售价:1D豆 [记录]
下载权限: 不限 以上  [免费赚D豆]




参考资料:

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


论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|辽公网安备|晓东CAD家园 ( 辽ICP备15016793号 )

GMT+8, 2024-11-14 21:55 , Processed in 0.315726 second(s), 33 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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