- 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)开发基础与实例教程》
|
|