- UID
 - 5043
 
- 积分
 - 1347
 
- 精华
 
- 贡献
 -  
 
- 威望
 -  
 
- 活跃度
 -  
 
- D豆
 -  
 
- 在线时间
 -  小时
 
- 注册时间
 - 2002-5-13
 
- 最后登录
 - 1970-1-1
 
 
 
 
 
  
 | 
 
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册 
 
 
 
 
×
 
 本帖最后由 LoveArx 于 2019-1-21 08:17 编辑  
 
(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, 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, 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文件。从下图中可见图形显示范围自动自行调整: 
 
 
 
总结思路: 
 
 
 
 
 
项目的完整源代码: 
 
 
      
 
 
 参考资料: 
 
     《AutoCAD ObjectARX(VC)开发基础与实例教程》 
 
 
 |   
 
 
 
 |