下载地址:
http://www.mxcad.net:2080/cpp/Tech-Database.zip
此实例将演示如何获取CAD图纸上常用的一些信息,如符号表(块表、层表、文字样式表、线型表、点样式表)、字典,演示程序在 MxDraw52\Src\MxDraw5.2\samples\Tech-Database 目录下即可编译运行, 运在行如下图:
我们打开一张CAD图纸用作测试,首先我们得到当前活动的数据库,对于获取当前的数据库,我们可以使用如下的几种方式:
//获得当前的数据库 McDbDatabase * pDatabase = nullptr; { MxDraw::GetDatabase(MxDraw::GetCurOcxHandle()); //1方式 acdbHostApplicationServices()->workingDatabase(); //2方式 pDatabase = Mx::mcdbCurDwg(); //3方式 }
再为当前的数据库添加一些内容,如在CAD图纸添加一些实体、图层、块引用,或者使用数据库来读取CAD图纸,比如调用McDbDatabase下的readDwgFile函数,该函数原型如下:
// ------------------------------------------------------------------------- // Summary: // 读取DWG文件 // Parameters: // pszFileName - DWG文件路径 // shmode - 暂没有使用 // bAllowCPConversion - 暂没有使用 // wszPassword - 暂没有使用 // rc - 指定需要读取的内容,不需要读取的内容可以不读取,这样能提高读取dwg文件的速度,可以取如下值: // enum ReadContent // { // kReadAll = 0xFFFFFFFF, // kReadNull = 0x0, // 下面数据都不读取 // kReadExData = 0x1, // kReadHandle = 0x2, // kReadBlockRefPreviewIcon = 0x4, // kReadBlockLayoutName = 0x8, // kReadObjectsDictionary = 0x10, // 是否读对象字典,如果不读,字典下所有数据都不会读取. // kReadGroupDict = 0x20, // 是否读取组字典 // kReadLayoutDict = 0x40, // kReadMlineStyleDict = 0x80, // kReadImageDict = 0x100, // kReadXrecord = 0x200, // kReadDrawOrder = 0x400, // kReadxData = 0x800, // kReadExRecord = 0x1000, // kReadExternalReference = 0x2000, // kReadCustomEntity = 0x4000 // 是否读取自定义实体,如果该为项为真,则自动让kReadHandle值也为真,因为自定义实体需要名柄支持. // }; // pInData - 如果从内存打开文件,pInData指向内存数据。 // lInDataLength - 内存数据的长度。 // Returns: // 如果成功返回Mcad::eOk,如果传递的数据非法则返回Mcad::eInvalidInput Mcad::ErrorStatus readDwgFile(LPCTSTR pszFileName, int shmode = 0x40, bool bAllowCPConversion = false, LPCTSTR wszPassword = NULL,int rc = Mcad::kReadAll, byte* pInData = NULL, long lInDataLength =0);
或者使用如下命令来打开CAD图纸文件:
acDocManager->sendStringToExecute(pDatabase->GetDocument(), L"OpenDwg");
此方式将以选择文件的方式来打开CAD图纸,如图:
得到当前数据库的文件名,在我们的当前数据库加载进数据之后,我们测试提取一些信息,比如获得文件名:
//获得文件名 HTREEITEM hRootDatabase = nullptr; { //Mx::mcdbCurDwg() 返回当前的数据对象 //McApDocument* McDbDatabase::GetDocument() const; auto sFileName = Mx::mcdbCurDwg()->GetDocument()->fileName(); //长度为零则返回 if (!wcslen(sFileName)) return ; hRootDatabase = m_DatabaseInfo.InsertItem(sFileName); }
下面将介绍如何获取个符号表的一些信息,如下图所示:
在数据库下包含了各种符号表与一个字典。符号表的在CAD控件的类声明如下:
// ------------------------------------------------------------------------- // Summary: // McDbSymbolTable是控件的内建符号表的所有类的基类 // ------------------------------------------------------------------------- class ARXDLL McDbSymbolTable : public McDbObject
而在符号变中,我们使用获取迭代器的接口来获取一个迭代器,接口如下:
// ------------------------------------------------------------------------- // Summary: // 创建一个遍历器对象,用于遍历SymbolTable中的内容,在不使用时调用delete释放内存 // Parameters: // pIterator - 新创建的遍历器的指针 // atBeginning - 输入布尔值,表示从表的开始处或结束处开始 // skipDeleted - 输入布尔值,表示是否忽略已删除的记录 // Returns: // 如果成功返回Mcad::eOk // ------------------------------------------------------------------------- Mcad::ErrorStatus newIterator(McDbSymbolTableIterator*& pIterator, bool atBeginning = true, bool skipDeleted = true);
而在迭代器中,我们将获取到符号表记录,符号表记录类声明如下:
// ------------------------------------------------------------------------- // Summary: // 符号表记录型类型,是不同符号表的记录的基类 // ------------------------------------------------------------------------- class ARXDLL McDbSymbolTableRecord : public McDbObject
在CAD控件中,已有的符号表包括:
McDbBlockTable | 块表 |
McDbLayerTable | 层表 |
McDbTextStyleTable | 文字样式表 |
McDbLinetypeTable | 线性表 |
McDbDimStyleTable | 标注样式表 |
他们都继承自上文的符号表(McDbSymbolTable ),而它们各自的获取迭代器接口(newIterator)中,迭代器可获取各自对应的表记录(McDbSymbolTableRecord )
对于符号表记录,在各种类型中对应不同的内容,在实例中将体现出来,在此实例中,我们将使用一个模板函数进行对于各个符号表进行读取数据并将他们的句柄挂载至树形结构图,该函数实现如下:
template< typename IteratorType, typename Value, typename Container > void CMxDatabaseDlg::CommonInitFunc( Container * pContainer, std::function<void(Value*, HTREEITEM)> func, HTREEITEM pParentNode) { IteratorType * pIterator = nullptr; McDbObjectPointer<Value> spValue; McDbObjectId mValueId; HTREEITEM pNode = nullptr; HTREEITEM pNextNode = nullptr; CString sFormatTemp; //将当前的表挂载至控件 if (pParentNode) pNode = m_DatabaseInfo.InsertItem(pContainer->isA()->name(), pParentNode); else pNode = m_DatabaseInfo.InsertItem(pContainer->isA()->name()); //创建一个遍历器,准备遍历块表 pContainer->newIterator(pIterator); std::auto_ptr<IteratorType> spIterator(pIterator);//该迭代器的生命周期绑定到智能指针 if (pIterator) { //遍历所有记录 for (; !pIterator->done(); pIterator->step()) { //获取ID pIterator->getRecordId(mValueId); //打开表 spValue.open(mValueId, McDb::kForRead); //获取符号表名 CString sTableName; { //... spValue->getNameEx(sTableName); //2方式 sTableName = MrxDbgUtils::getSymbolTableRecordName(mValueId); } //获取句柄 TCHAR szHandle[256] = {}; { McDbHandle hTableRechandle; spValue->getAcDbHandle(hTableRechandle); hTableRechandle.getIntoAsciiBuffer(szHandle); } //格式化字符串 sFormatTemp.Format(FORMAT, szHandle, sTableName); //将层表挂载到当前数据库下 pNextNode = m_DatabaseInfo.InsertItem(sFormatTemp, pNode); //上述代码是将符号记录表通用信息加载至控件,使用以下函数附加操作 func(spValue.object(), pNextNode); } } } template<> inline void CMxDatabaseDlg::CommonInitFunc< McDbBlockTableRecordIterator, McDbEntity, McDbBlockTableRecord >( McDbBlockTableRecord * pTable, std::function<void(McDbEntity*, HTREEITEM)> func, HTREEITEM pParentNode) { McDbBlockTableRecordIterator * pIterator = nullptr; McDbObjectPointer<McDbEntity> spValue; McDbObjectId mValueId; CString sFormatTemp; //创建一个遍历器,准备遍历块表 pTable->newIterator(pIterator); std::auto_ptr<McDbBlockTableRecordIterator> spIterator(pIterator);//该迭代器的生命周期绑定到智能指针 if (pIterator) { //遍历所有记录 for (; !pIterator->done(); pIterator->step()) { //获取ID pIterator->getEntityId(mValueId); //打开表 spValue.open(mValueId, McDb::kForRead); //获取句柄 TCHAR szHandle[256] = {}; { McDbHandle hTableRechandle; spValue->getAcDbHandle(hTableRechandle); hTableRechandle.getIntoAsciiBuffer(szHandle); } //格式化字符串 sFormatTemp.Format(FORMAT, szHandle, spValue->isA()->name()); //将层表挂载到当前数据库下 m_DatabaseInfo.InsertItem(sFormatTemp, pParentNode); } } }
对于每个符号表,我们进行如下调用:
//获取块表的一些信息 { McDbBlockTable * pBlockTable = nullptr; pDatabase->getBlockTable(pBlockTable, McDb::kForRead); CommonInitFunc<McDbBlockTableIterator, McDbBlockTableRecord, McDbBlockTable>( pBlockTable, [&](McDbBlockTableRecord * pTableRec, HTREEITEM pTreeTable) { this->CommonInitFunc< McDbBlockTableRecordIterator, McDbEntity, McDbBlockTableRecord>( pTableRec, [](McDbEntity*, HTREEITEM) {}, pTreeTable); }); } //获取层表的一些信息 { McDbLayerTable* pLayerTable = nullptr; pDatabase->getLayerTable(pLayerTable, McDb::kForRead); CommonInitFunc<McDbLayerTableIterator, McDbLayerTableRecord, McDbLayerTable>( pLayerTable, [&](McDbLayerTableRecord *, HTREEITEM) {}); } //获取文字样式的一些信息 { McDbTextStyleTable * pTextStyleTable = nullptr; pDatabase->getTextStyleTable(pTextStyleTable, McDb::kForRead); CommonInitFunc<McDbTextStyleTableIterator, McDbTextStyleTableRecord, McDbTextStyleTable>( pTextStyleTable, [&](McDbTextStyleTableRecord *, HTREEITEM) {}); } //获取线型的一些信息 { McDbLinetypeTable * pLinetypeTable = nullptr; pDatabase->getLinetypeTable(pLinetypeTable, McDb::kForRead); CommonInitFunc< McDbLinetypeTableIterator, McDbLinetypeTableRecord, McDbLinetypeTable>( pLinetypeTable, [&](McDbLinetypeTableRecord *, HTREEITEM) {}); } //获取标注样式的一些信息 { McDbDimStyleTable * pDimStyleTable = nullptr; pDatabase->getDimStyleTable(pDimStyleTable, McDb::kForRead); CommonInitFunc<McDbDimStyleTableIterator, McDbDimStyleTableRecord, McDbDimStyleTable>( pDimStyleTable, [&](McDbDimStyleTableRecord *, HTREEITEM) {}); }
可以看到的是,除了块表,其他的符号表下只包含各自的记录表,而块表下包含块表记录,块表记录下包含了块,块下包含了一些实体,其中也包括块引用。而对于字典,我们使用初始化符号表的特化模板函数进行初始化,该函数实现如下:
template<> inline void CMxDatabaseDlg::CommonInitFunc< McDbDictionaryIterator, McDbObject, McDbDictionary >( McDbDictionary * pDictionary, std::function<void(McDbObject*, HTREEITEM)> func, HTREEITEM pParentNode) { McDbDictionaryIterator * pIterator = nullptr; McDbObjectPointer<McDbObject> spValue; McDbObjectId mValueId; CString sFormatTemp; HTREEITEM pNode = nullptr; HTREEITEM pNextNode = nullptr; //将当前的表挂载至控件 if (pParentNode) pNode = m_DatabaseInfo.InsertItem(pDictionary->isA()->name(), pParentNode); else pNode = m_DatabaseInfo.InsertItem(pDictionary->isA()->name()); pIterator = pDictionary->newIterator(); std::auto_ptr<McDbDictionaryIterator> spIterator(pIterator);//该迭代器的生命周期绑定到智能指针 if (pIterator == NULL) return; for (; !pIterator->done(); pIterator->next()) { mValueId = pIterator->objectId(); spValue.open(mValueId, McDb::kForRead); //获取句柄 TCHAR szHandle[256] = {}; { McDbHandle hTableRechandle; spValue->getAcDbHandle(hTableRechandle); hTableRechandle.getIntoAsciiBuffer(szHandle); } //格式化字符串 sFormatTemp.Format(FORMAT, szHandle, spValue->isA()->name()); //将当前内容挂载到当前数据库下 pNextNode = m_DatabaseInfo.InsertItem(sFormatTemp, pNode); func(spValue.object(), pNextNode); } }
调用函数的代码如下:
//获取字典的一些信息 { std::function<void(McDbObject*, HTREEITEM)> func; func = [&](McDbObject* pMcDbObject, HTREEITEM pTreeTable) { const CString sType = pMcDbObject->isA()->name(); const CString sMcDbDictionary(L"McDbDictionary"); if (sMcDbDictionary == sType) { this->CommonInitFunc<McDbDictionaryIterator, McDbObject, McDbDictionary>( McDbDictionary::cast(pMcDbObject), func, pTreeTable); } }; McDbDictionary * pDictionary = nullptr; pDatabase->getNamedObjectsDictionary(pDictionary, McDb::kForRead); CommonInitFunc<McDbDictionaryIterator, McDbObject, McDbDictionary>( pDictionary, func); }
至此,我们就读取到当前模型空间的所有符号表及字典,而对于如何取到具体的信息,我们在此实例的树形结构图的单击事件下进行读取,代码如下:
void CMxDatabaseDlg::OnTvnSelchangedDatabaseinfoTree(NMHDR *pNMHDR, LRESULT *pResult) { LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR); *pResult = 0; CString strText; // 树节点的标签文本字符串 // 获取当前选中节点的句柄 HTREEITEM hItem = m_DatabaseInfo.GetSelectedItem(); strText = m_DatabaseInfo.GetItemText(hItem); GetObjectAndPring(strText); } void CMxDatabaseDlg::GetObjectAndPring(const CString sHandle) { //在此处我们得到所需的一些信息 McDbObjectPointer<McDbObject> spObject; { McDbObjectId mId; McDbHandle mHandle(GetHandleStr(sHandle)); acdbHostApplicationServices()->workingDatabase()->getAcDbObjectId(mId, false, mHandle); spObject.open(mId, McDb::kForRead); } if (Mcad::eOk == spObject.openStatus()) { CString sTemp; CString sType = spObject->isA()->name(); sTemp.Format(_T("\n类型:%s\t组码名:%s\nID:%d"), spObject->isA()->name(), spObject->isA()->DXF0(), spObject->objectId().asOldId()); Mx::mcutPrompt(sTemp); sTemp.Format(_T("\t句柄:%s"), GetHandleStr(sHandle)); Mx::mcutPrompt(sTemp); // MrxDbgUtils::putEntityInView(spObject->objectId(), 10); //符号表 if (McDbSymbolTableRecord::cast(spObject)) { auto pDisSymUtilInfo = [&](McDbSymbolTableRecord* pMcDbSymbolTable) { CString sName; pMcDbSymbolTable->getNameEx(sName); sTemp.Format(_T("\n符号记录表名:%s"), sName); Mx::mcutPrompt(sTemp); }; const CString sMcDbLayerTableRecord(L"McDbLayerTableRecord"); const CString sMcDbBlockTableRecord(L"McDbBlockTableRecord"); const CString sMcDbTextStyleTableRecord(L"McDbTextStyleTableRecord"); const CString sMcDbLinetypeTableRecord(L"McDbLinetypeTableRecord"); const CString sMcDbDimStyleTableRecord(L"McDbDimStyleTableRecord"); if (sMcDbLayerTableRecord == sType) { auto pEnt = McDbLayerTableRecord::cast(spObject); pDisSymUtilInfo(pEnt); sTemp.Format(_T("\n锁定状态:%s\t关闭状态:%s\n冻结状态:%s"), pEnt->isLocked() ? L"锁定" : L"未锁定", pEnt->isOff() ? L"关闭" : L"未关闭", pEnt->isFrozen() ? L"冻结" : L"未冻结"); Mx::mcutPrompt(sTemp); auto mColor = pEnt->color(); sTemp.Format(_T("\t颜色索引%d"), mColor.colorIndex()); Mx::mcutPrompt(sTemp); } else if (sMcDbTextStyleTableRecord == sType) { auto pEnt = McDbTextStyleTableRecord::cast(spObject); pDisSymUtilInfo(pEnt); LPCTSTR lpFileName; pEnt->fileName(lpFileName); sTemp.Format(_T("\n竖向绘制:%s\t文字高度:%f\t缩放比例:%f\t倾斜弧度%f\t字体文件名:%s"), pEnt->isVertical() ? L"是" : L"否", pEnt->textSize(), pEnt->xScale(), pEnt->obliquingAngle(), lpFileName); Mx::mcutPrompt(sTemp); //...在此处介绍其他的信息 } else if (sMcDbLinetypeTableRecord == sType) { auto pEnt = McDbLinetypeTableRecord::cast(spObject); pDisSymUtilInfo(pEnt); CString sCommentsEx; pEnt->commentsEx(sCommentsEx); sTemp.Format(_T("\n线型说明:%s"), sCommentsEx); Mx::mcutPrompt(sTemp); //...在此处介绍其他的信息 } else if (sMcDbDimStyleTableRecord == sType) { auto pEnt = McDbDimStyleTableRecord::cast(spObject); pDisSymUtilInfo(pEnt); //...在此处介绍其他的信息 } else if (sMcDbBlockTableRecord == sType) { auto pEnt = McDbBlockTableRecord::cast(spObject); pDisSymUtilInfo(pEnt); //...在此处介绍其他的信息 } Mx::mcutPrompt(L"\n"); } else if (auto spEnt = McDbEntity::cast(spObject)) { auto pDisText = [&](McGePoint3d vPt, double dRotation, double dHeight, double dWidth, CString sText, CString sStyle) { const CString sTextInfoFormat(L"\n文字位置:X = %.3lf Y = %.3lf\n旋转弧度%f\t行高%f\t宽度比例%f\n文字内容:%s\n文字样式%s\n"); sTemp.Format(sTextInfoFormat, vPt.x, vPt.y, dRotation, dHeight, dWidth, sText, sStyle); Mx::mcutPrompt(sTemp); }; //基本实体 sTemp.Format(_T("\n层名:%s\t颜色索引:%d"), spEnt->layer(), spEnt->colorIndex()); Mx::mcutPrompt(sTemp); const CString sMcDbLine(L"McDbLine"); const CString sMcDbPolyline(L"McDbPolyline"); const CString sMcDbArc(L"McDbArc"); const CString sMcDbCircle(L"McDbCircle"); const CString sMcDbSpline(L"McDbSpline"); const CString sMcDbEllipse(L"McDbEllipse"); const CString sMcDbPoint(L"McDbPoint"); const CString sMcDbBlockReference(L"McDbBlockReference"); const CString sMcDbAttributeDefinition(L"McDbAttributeDefinition"); const CString sMcDbText(L"McDbText"); const CString sMcDbMText(L"McDbMText"); const CString sMcDbHatch(L"McDbHatch"); const CString sMcDbDimension(L"McDbDimension"); if (sMcDbLine == sType) { auto pEnt = McDbLine::cast(spEnt); auto vPt1 = pEnt->startPoint(); sTemp.Format(_T("\n起始点:X = %.3lf Y = %.3lf"), vPt1.x, vPt1.y); Mx::mcutPrompt(sTemp); auto vPt2 = pEnt->endPoint(); sTemp.Format(_T("\n结束点:X = %.3lf Y = %.3lf"), vPt2.x, vPt2.y); Mx::mcutPrompt(sTemp); sTemp.Format(_T("\n增量:X = %.3lf 增量Y = %.3lf"), vPt2.x - vPt1.x, vPt2.y - vPt1.y); Mx::mcutPrompt(sTemp); } else if (sMcDbPoint == sType) { auto pEnt = McDbPoint::cast(spEnt); auto vPt = pEnt->position(); sTemp.Format(_T("\n点:X = %.3lf Y = %.3lf"), vPt.x, vPt.y); Mx::mcutPrompt(sTemp); } else if (sMcDbPolyline == sType) { auto pEnt = McDbPolyline::cast(spEnt); sTemp.Format(_T("\n是否闭合%s"), pEnt->isClosed() ? L"闭合" : L"不闭合"); Mx::mcutPrompt(sTemp); McGePoint2d vPt; for (UINT i(0); i < pEnt->numVerts(); i++) { pEnt->getPointAt(i, vPt); sTemp.Format(_T("\n点:X = %.3lf Y = %.3lf"), vPt.x, vPt.y); Mx::mcutPrompt(sTemp); } } else if (sMcDbText == sType) { auto pEnt = McDbText::cast(spEnt); pDisText(pEnt->position(), pEnt->rotation(), pEnt->height(), pEnt->widthFactor(), pEnt->textStringConst(), pEnt->textStyleEx()); } else if (sMcDbMText == sType) { auto pEnt = McDbMText::cast(spEnt); pDisText(pEnt->location(), pEnt->rotation(), pEnt->textHeight(), pEnt->width(), pEnt->contents(), pEnt->textStyleEx()); } else if (sMcDbCircle == sType) { auto pEnt = McDbCircle::cast(spEnt); auto vCenter = pEnt->center(); sTemp.Format(_T("\n圆心:X = %.3lf Y = %.3lf"), vCenter.x, vCenter.y); Mx::mcutPrompt(sTemp); auto dRadius = pEnt->radius(); sTemp.Format(_T("\n半径:%f"), dRadius); Mx::mcutPrompt(sTemp); } else if (sMcDbArc == sType) { auto pEnt = McDbArc::cast(spEnt); auto vCenter = pEnt->center(); sTemp.Format(_T("\n圆心:X = %.3lf Y = %.3lf"), vCenter.x, vCenter.y); Mx::mcutPrompt(sTemp); auto dRadius = pEnt->radius(); sTemp.Format(_T("\n半径:%f"), dRadius); Mx::mcutPrompt(sTemp); auto dstartAngle = pEnt->startAngle(); sTemp.Format(_T("\n起始角度:%f"), dstartAngle); Mx::mcutPrompt(sTemp); auto dendAngle = pEnt->endAngle(); sTemp.Format(_T("\n结束角度:%f"), dendAngle); Mx::mcutPrompt(sTemp); } else if (sMcDbEllipse == sType) { auto pEnt = McDbEllipse::cast(spEnt); // auto vCenter = pEnt->center(); sTemp.Format(_T("\n圆心:X = %.3lf Y = %.3lf"), vCenter.x, vCenter.y); Mx::mcutPrompt(sTemp); auto vMajorAxis = pEnt->majorAxis(); sTemp.Format(_T("\n主轴向量:%f"), vMajorAxis.x, vMajorAxis.y); Mx::mcutPrompt(sTemp); auto vMinorAxis = pEnt->minorAxis(); sTemp.Format(_T("\n副轴向量:%f"), vMinorAxis.x, vMinorAxis.y); Mx::mcutPrompt(sTemp); sTemp.Format(_T("\n副轴与主轴长度比值:%f"), pEnt->radiusRatio()); Mx::mcutPrompt(sTemp); sTemp.Format(_T("\n开始角度:%f\t结束角度%f"), pEnt->startAngle(), pEnt->endAngle()); Mx::mcutPrompt(sTemp); } else if (sMcDbBlockReference == sType) { auto pEnt = McDbBlockReference::cast(spEnt); auto sName = pEnt->appName(); sTemp.Format(_T("\n块名:%s"), sName); Mx::mcutPrompt(sTemp); auto vPosition = pEnt->position(); sTemp.Format(_T("\n插入位置:X = %.3lf Y = %.3lf"), vPosition.x, vPosition.y); Mx::mcutPrompt(sTemp); auto dScale = pEnt->scaleFactors(); sTemp.Format(_T("\n缩放比例:%f"), dScale); Mx::mcutPrompt(sTemp); auto drotationAngle = pEnt->rotation(); sTemp.Format(_T("\n旋转角度:%f"), drotationAngle); Mx::mcutPrompt(sTemp); } else if (sMcDbDimension == sType) { //标注类型 } Mx::mcutPrompt(L"\n"); } else { Mx::mcutPrompt(L"未说明的类型\n"); Mx::mcutPrompt(L"\n"); } } }
对于获取实体信息,重点在于获取它的句柄或ID,我们可用通过选择及或构造选择集的方式去过滤,也可以使用与用户交互的方式去选择需要的实体,而获取ID之后,我们使用以下的方式去打开,即可获取它的全部相关信息,如得到它的类型、DXF组码名:
McDbObjectPointer<McDbObject> spObject; { //... spObject.open(mId, McDb::kForRead); } if (Mcad::eOk == spObject.openStatus()) { CString sTemp; CString sType = spObject->isA()->name(); }