(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)开发基础与实例教程》
暂无评论内容