1 說明
在ObjectARX中,除了Xdata以外,還有一種擴充資料——Xrecord。
AcDbXrecord是一種資料存儲類,與Xdata類似,但其資料存儲量和資料存儲類型更多,每個AcDbXrecord對象最多可存儲2GB的資料。Xrecord對象的DXF組碼範圍為1~369。Xrecord存儲在一種特殊實體——擴充字典中,而擴充字典可以屬于一個實體,這樣這個實體就擁有了自定義的擴充資料。
上面提到了擴充字典,為了了解擴充字典,需要讨論字典的生成,這裡也涉及到有名對象字典。字典(AcDbDictionary類)與符号表非常類似,相當于是對象的指針的集合,并通唯一的字元串關鍵字索引(char* text )和對象ID(32-bit )号檢索對象。在字典中的對象設計上是指一個對象ID号的關鍵字字元串。字典中能夠包含任意數量的關鍵字字元串。對象的ID号可能是任何的AcDbObject類或由AcDbObject類派生的類。一個對象隻能屬于一個擴充字典,但是該擴充字典能夠由任何應用程式通路。當一個實體被删除,其擴充字典也将被删除。
2 相關函數
2.1 AcDbObject類
實體AcDbObject類中與擴充字典相關的函數主要有:
createExtensionDictionary()
- 建立一個AcDbDictionary對象,并将其設定為AcDbObject的擴充字典。如果成功,則傳回Acad :: eOk。如果擴充字典已經存在,則傳回Acad :: eAlreadyInDb。
extensionDictionary()
- 傳回實體擁有的擴充字典的objectId, 如果沒有,則将傳回的objectId設定為AcDbObjectId :: kNull。
releaseExtensionDictionary()
- 如果實體有擴充字典,且不含任何資料,則删除該擴充字典。如果成功,則傳回Acad :: eOk;如果擴充字典不為空,則此函數失敗并傳回Acad :: eContainerNotEmpty。
2.2 AcDbDictionary類
字典AcDbDictionary類中常用函數主要有:
getAt()
- 定義:
Acad::ErrorStatus getAt(
const ACHAR* entryName,
AcDbObject*& entryObj,
AcDb::OpenMode mode
) const;
Acad::ErrorStatus getAt(
const ACHAR* entryName,
AcDbObjectId& entryObj
) const;
-
參數:
entryName —— 要查找的關鍵字索引;
entryObj —— 傳回指向對象的指針;
OpenMode mode——打開對象的模式;有三個可能值,AcDb :: kForRead,AcDb :: kForWrite和AcDb :: kForNotify。
- 作用:在字典中根據關鍵字索引搜尋對象。找到後,指針entryObj指向對象,搜尋不區分大小寫。
- 傳回值:如果成功,則傳回Acad :: eOk;如果entryName == NULL或entryName不是有效的關鍵字索引,則傳回Acad :: eInvalidKey; 如果找不到比對的條目,則傳回Acad :: eKeyNotFound。
setAt()
- 定義:
Acad::ErrorStatus setAt(
const ACHAR* srchKey,
AcDbObject* newValue,
AcDbObjectId& retObjId
-
參數:
srchKey —— 要添加到字典中的指向對象的關鍵字索引;
newValue —— 指向要添加到字典中的對象的指針;
retObjId —— 傳回被添加到字典中的對象ID。
- 作用:向字典中添加對象。如果srchKey在字典中不存在,此函數将newValue指定的對象添加到字典中。 如果srchKey已存在,則将原來的對象删除,newValue指向的新對象添加到字典中。
- 傳回值:如果成功,則傳回Acad :: eOk; 如果srchKey == NULL,傳回Acad :: eInvalidKey; 如果newValue == NULL,則為Acad :: eNullEntityPointer。
remove ()
- 定義:
Acad::ErrorStatus remove( AcDbObjectId objId );
Acad::ErrorStatus remove( const ACHAR * key );
Acad::ErrorStatus remove( const ACHAR * key, AcDbObjectId& returnId );
-
參數:
key —— 要從字典中删除的對象的關鍵字索引;
objId —— 要從字典中删除的對象的ID;
returnId —— 傳回字典中被删除的對象的ID。
- 作用:根據關鍵字索引或對象ID從字典中删除對象。被删除的對象仍在資料庫中。
- 傳回值:如果成功,則傳回Acad :: eOk;如果key == NULL,則傳回Acad :: eInvalidKey;如果在字典中找不到key或objId,則傳回Acad :: eKeyNotFound。
2.2 AcDbXrecord類
擴充記錄AcDbXrecord類中常用函數主要有:
rbChain()
- 定義:
Acad::ErrorStatus rbChain(
resbuf** ppRb,
AcDbDatabase* auxDb = NULL
) const;
-
參數:
ppRb —— 要添加的資料連結清單的指針的位址;
- 作用:擷取擴充記錄的resbuf資料連結清單。
- 傳回值:如果成功,則傳回Acad :: eOk;如果沒有足夠的記憶體來建立完整的resbuf資料連結清單,則傳回Acad :: eOutOfMemory。
setFromRbChain()
- 定義:
Acad::ErrorStatus setFromRbChain(
const resbuf& pRb,
AcDbDatabase* auxDb = NULL
);
-
參數:
pRb —— 包含擴充記錄的resbuf資料連結清單;
- 作用:将resbuf資料連結清單添加到擴充記錄中,資料連結清單中的内容由DXF組碼指定的資料類型,及對應的資料組成。以下是DXF組代碼範圍及其代表的資料類型的清單,其中DXF碼330~369用于指定對象ID(ads_name)。
DXF碼(起) | DXF碼(止) | 資料類型 |
---|---|---|
1 | 4 | text |
6 | 9 | text |
10 | 17 | point or vector (3 reals) |
38 | 59 | real |
60 | 79 | 16-bit integer |
90 | 99 | 32-bit integer |
100 | 100 | subclass data marker |
102 | 102 | text |
140 | 149 | real |
170 | 179 | 16-bit integer |
210 | 219 | 3 reals |
270 | 279 | 16-bit integer |
280 | 289 | 8-bit integer |
300 | 309 | text |
310 | 319 | binary chunk |
320 | 329 | handle |
330 | 339 | soft pointer ID |
340 | 349 | hard pointer ID |
350 | 359 | soft owner ID |
360 | 369 | hard owner ID |
- 傳回值:如果操作成功,則傳回Acad :: eOk;如果資料連結清單中的對象ID無效,則傳回Acad :: eInvalidAdsName。
3 思路
3.1 添加擴充記錄
在預設的情況下,實體是沒有擴充字典的。是以,要利用擴充字典儲存擴充記錄,可以按以下步驟:
- 使用createExtensionDictionary()函數為實體建立擴充字典;
- 使用extensionDictionary()函數擷取實體的擴充字典;
- 使用setAt()函數為擴充字典添加一個對象,用于存儲擴充記錄(也可以存儲其他類型的對象);
- 使用acutBuildList()函數建立一個資料連結清單;
- 使用setFromRbChain()函數将建立的資料連結清單添加到擴充記錄中。
這樣就完成了為實體添加擴充記錄的工作。
3.2 檢視擴充記錄
檢視實體的擴充記錄的步驟為:
- 使用extensionDictionary()函數擷取實體的擴充字典;
- 然後通過getAt()函數擷取指定名稱的擴充記錄;
- 使用rbChain()函數擷取擴充記錄對應的資料連結清單;
- 按照一定的方式輸出資料連結清單中的資料。
這樣就完成了檢視實體的擴充記錄中的資料。
3.3 删除擴充記錄
删除實體的擴充記錄的步驟為:
- 使用extensionDictionary()函數擷取實體的擴充字典;
- 使用remove()函數删除指定名稱的擴充資料。
這樣就完成了删除實體的擴充記錄。
4 步驟
建立擴充記錄Xrecord源代碼:
//為實體添加Xrecord
static void MyGroupcreateXrecord()
{
//提示使用者選擇實體
AcDbObject* pObj = NULL;
if ((pObj = selectObject(AcDb::kForWrite)) == NULL)
{
return;
}
//提示使用者輸入要添加的資料
TCHAR xrecName[200], resString[200];
xrecName[0] = resString[0] = _T('\0');
acedGetString(NULL, _T("Enter Xrecord name: "), xrecName);
acedGetString(NULL, _T("Enter string to be added: "), resString);
//為實體建立擴充字典
pObj -> createExtensionDictionary();
//擷取實體的擴充字典
AcDbObjectId dictObjId = pObj -> extensionDictionary();
pObj -> close();
//向擴充字典中添加Xrecord
AcDbDictionary* pDict = NULL;
AcDbXrecord* pXrec = new AcDbXrecord;
AcDbObjectId xrecObjId;
if (acdbOpenObject(pDict, dictObjId, AcDb::kForWrite) == Acad::eOk)
{
pDict->setAt(xrecName, pXrec, xrecObjId);
pDict->close();
}
//建立資料連結清單
struct resbuf* pRb = acutBuildList(AcDb::kDxfText, resString, RTNONE);
//将資料連結清單添加到擴充記錄中
pXrec -> setFromRbChain(*pRb);
pXrec -> close();
acutRelRb(pRb);
}
檢視擴充記錄Xrecord源代碼:
//輸出實體的Xrecord
static void MyGrouplistXrecord()
{
//提示使用者選擇實體
AcDbObject* pObj = NULL;
if ((pObj = selectObject(AcDb::kForRead)) == NULL)
{
return;
}
//擷取實體的擴充字典
AcDbObjectId dictObjId = NULL;
dictObjId = pObj->extensionDictionary();
pObj -> close();
if (dictObjId == AcDbObjectId::kNull)
{
acutPrintf(_T("\nNo Extension Dictionary found!"));
return;
}
//提示使用者輸入要查找的Xrecord
TCHAR xrecName[200];
xrecName[0] = _T('\0');
acedGetString(NULL, _T("Enter Xrecord to be listed: "), xrecName);
//擷取擴充記錄
AcDbDictionary *pDict = NULL;
AcDbXrecord *pXrec = NULL;
if (acdbOpenObject(pDict, dictObjId, AcDb::kForRead) == Acad::eOk)
{
pDict -> getAt(xrecName, (AcDbObject*&)pXrec, AcDb::kForRead);
pDict -> close();
}
//擷取擴充記錄的資料連結清單
struct resbuf* pRb;
pXrec -> rbChain(&pRb);
pXrec -> close();
//在指令視窗中輸出資料
printList(pRb);
acutRelRb(pRb);
}
删除擴充記錄Xrecord源代碼:
//删除實體的Xrecord
static void MyGroupdeleteXrecord()
{
//提示使用者選擇實體
AcDbObject* pObj = NULL;
if ((pObj = selectObject(AcDb::kForWrite)) == NULL)
{
return;
}
//擷取實體的擴充字典
AcDbObjectId dictObjId = pObj -> extensionDictionary();
pObj -> close();
if (dictObjId != AcDbObjectId::kNull)
{
//提示使用者輸入要删除的資料
TCHAR xrecName[200];
xrecName[0] = _T('\0');
acedGetString(NULL, _T("Enter Xrecord name: "), xrecName);
//删除擴充字典中的Xrecord
AcDbDictionary* pDict = NULL;
if (acdbOpenObject(pDict, dictObjId, AcDb::kForWrite) == Acad::eOk)
{
if (pDict -> has(xrecName))
{
pDict -> remove(xrecName);
acutPrintf(_T("\n已删除Xrecord %s!"), xrecName);
}
else
{
acutPrintf(_T("\nXrecord %s do not exists!"), xrecName);
}
pDict->close();
}
}
else
{
acutPrintf(_T("\nNo Extension Dictionary exists!"));
return;
}
}
還需要添加兩個函數,printList()用于在指令視窗中列印Xdata資訊;selectObject()用于提示使用者選擇實體。代碼如下:
//在指令視窗中輸出Xrecord資訊
static void printList(struct resbuf* pBuf)
{
int rt, i;
TCHAR buf[133];
for (i = 0;pBuf != NULL;i++, pBuf = pBuf->rbnext) {
if (pBuf->restype < 0)
rt = pBuf->restype;
else if (pBuf->restype < 10)
rt = RTSTR;
else if (pBuf->restype < 38)
rt = RT3DPOINT;
else if (pBuf->restype < 60)
rt = RTREAL;
else if (pBuf->restype < 80)
rt = RTSHORT;
else if (pBuf->restype < 100)
rt = RTLONG;
else if (pBuf->restype < 106)
rt = RTSTR;
else if (pBuf->restype < 148)
rt = RTREAL;
else if (pBuf->restype < 290)
rt = RTSHORT;
else if (pBuf->restype < 330)
rt = RTSTR;
else if (pBuf->restype < 370)
rt = RTENAME;
else if (pBuf->restype < 999)
rt = RT3DPOINT;
else
rt = pBuf->restype;
switch (rt)
{
case RTSHORT:
if (pBuf->restype == RTSHORT)
acutPrintf(_T("RTSHORT : %d\n"), pBuf->resval.rint);
else
acutPrintf(_T("(%d . %d)\n"), pBuf->restype, pBuf->resval.rint);
break;
case RTREAL:
if (pBuf->restype == RTREAL)
acutPrintf(_T("RTREAL : %0.3f\n"), pBuf->resval.rreal);
else
acutPrintf(_T("(%d . %0.3f)\n"), pBuf->restype, pBuf->resval.rreal);
break;
case RTSTR:
if (pBuf->restype == RTSTR)
acutPrintf(_T("RTSTR : %s\n"), pBuf->resval.rstring);
else
acutPrintf(_T("(%d . \"%s\")\n"), pBuf->restype, pBuf->resval.rstring);
break;
case RT3DPOINT:
if (pBuf->restype == RT3DPOINT)
acutPrintf(_T("RT3DPOINT : %0.3f, %0.3f, %0.3f\n"),
pBuf->resval.rpoint[X],
pBuf->resval.rpoint[Y],
pBuf->resval.rpoint[Z]);
else
acutPrintf(_T("(%d %0.3f %0.3f %0.3f)\n"),
pBuf->restype,
pBuf->resval.rpoint[X],
pBuf->resval.rpoint[Y],
pBuf->resval.rpoint[Z]);
break;
case RTLONG:
acutPrintf(_T("RTLONG : %dl\n"), pBuf->resval.rlong);
break;
case -1:
case RTENAME:
acutPrintf(_T("(%d . <Entity name: %8lx>)\n"),
pBuf->restype, pBuf->resval.rlname[0]);
break;
case -3:
acutPrintf(_T("(-3)\n"));
}
if ((i == 23) && (pBuf->rbnext != NULL))
{
i = 0;
acedGetString(0, _T("Press <ENTER> to continue..."), buf);
}
}
return;
}
//提示使用者選擇實體
static AcDbObject* selectObject(AcDb::OpenMode openMode)
{
int ss;
ads_name en;
ads_point pt;
acedInitGet(RSG_OTHER, _T("Handle _Handle"));
ss = acedEntSel(_T("\nSelect an Entity or enter")_T(" 'H' to enter its handle: "), en, pt);
TCHAR handleStr[132];
AcDbObjectId eId;
switch (ss)
{
case RTNORM:
break;
case RTKWORD:
if ((acedGetString(Adesk::kFalse,
_T("Enter Valid Object Handle: "),
handleStr) == RTNORM)
&& (acdbHandEnt(handleStr, en) == RTNORM))
{
break;
}
default:
acutPrintf(_T("Nothing Selected, Return Code==%d\n"),ss);
return NULL;
}
Acad::ErrorStatus retStat;
retStat = acdbGetObjectId(eId, en);
if (retStat != Acad::eOk) {
acutPrintf(_T("\nacdbGetObjectId failed"));
acutPrintf(_T("\nen==(%lx,%lx), retStat==%d\n"),
en[0], en[1], eId);
return NULL;
}
AcDbObject* obj;
if ((retStat = acdbOpenObject(obj, eId, openMode))
!= Acad::eOk)
{
acutPrintf(_T("acdbOpenEntity failed: ename:(%lx,%lx),")
_T(" mode:%d retStat:%d"), en[0], en[1],
openMode, retStat);
return NULL;
}
return obj;
}
5 效果
如下圖所示,實體中原本不含任何擴充資料。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIwczX0xiRGZkRGZ0Xy9GbvNGL2EzXlpXazxSP9EVTzUlaOJTTq1EM4wmYwhGWhxGZzwEMW1mY1RzRapnTtxkb5ckYplTeMZTTINGMShUYfRHelRHLwEzX39GZhh2css2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xyayFWbyVGdhd3LcV2Zh1Wa9M3clN2byBXLzN3btg3Pn5GcuIDN0ETNykTM5EjMwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
通過程式可為實體添加一個名為“xrecord”的擴充記錄,存儲了一個字元串“這是一個測試字元串”,如下圖所示。
使用删除指令之後,實體的擴充字典中不在有任何Xrecord對象,如下圖所示。
相比于Xdata,Xrecord存儲的資料量更大,資料類型更多。Xrecord使用了标準的AutoCAD标準組碼,這使得Xrecord可以存儲所有類型的對象,甚至是另一個Xrecord。
同時,AutoCAD中其他的.arx和AutoLISP程式都可以直接通路Xrecord資料。如果資料安全不是問題,那麼xrecords是一個很好的資料存儲方案。 如果資料安全是一個問題,那麼自定義資料存儲類是更好的選擇。
6 源代碼
源代碼:xrecord
提取碼:2bis
參考文檔
[1]:Autodesk ObjectARX for AutoCAD 2015: Developer Guide.