天天看點

ObjectARX中擴充記錄和擴充字典

在ObjectARX二次開發中,如果想向圖形的對象追加一些資料,可以使用擴充資料或者擴充記錄,本文詳細介紹這兩種方法。

一 擴充資料

擴充資料(Extended data或者簡稱為xdata)可以添加到任何對象上,由一個結果緩沖區連結清單組成,連結清單的DXF組碼範圍為1000~1071。擴充資料适合給對象添加輕量化資料,資料總容量不能超過16KB.

設定擴充資料的函數為

請注意,結果緩沖區連結清單的第一個組碼必須是1001,其後跟着一個字元串,這個字元串代表注冊函數名稱。因為任何一個應用程式都能将擴充資料附加到實體上,是以所有擴充資料都需要一個唯一的應用程式名稱,該名稱不超過31個字元,使用acdbRegApp函數進行注冊。

以下代碼可以給一個實體添加擴充資料。

void CmdAddEntXData()
{
	ads_name ent;
	AcGePoint3d ptPick;
	if (RTNORM == acedEntSel(_T("\n選擇所要添加擴充資料的實體:"), ent, asDblArray(ptPick)))
	{
		CString appName = _XDATA_APPNAME_;

		// 注冊應用程式名稱
		acdbRegApp(appName);

		// 建立結果緩沖區連結清單
		struct resbuf* rb = acutBuildList(AcDb::kDxfRegAppName, appName,		// 應用程式名稱
			AcDb::kDxfXdAsciiString, TEXT("字元串測試資料"),	// 字元串
			AcDb::kDxfXdInteger32, 2,							// 整數
			AcDb::kDxfXdReal, 3.14,								// 實數
			AcDb::kDxfXdWorldXCoord, asDblArray(ptPick),						// 點坐标值
			RTNONE);

		// 為選擇的實體添加擴充資料
		AcDbEntity* pEnt;
		AcDbObjectId idEnt;
		acdbGetObjectId(idEnt, ent);
		if (Acad::eOk == acdbOpenObject(pEnt, idEnt, AcDb::kForWrite))
		{
			pEnt->setXData(rb);
			pEnt->close();
		}
		acutRelRb(rb);
		acutPrintf(TEXT("\n成功為實體添加了擴充資料."));
	}
}
           

對象的擴充資料是通過AcDbObject::xData函數擷取的

如果regappName為 NULL,傳回所有擴充資料。否則傳回注冊程式名稱對應的擴充資料。

//列印所有擴充資料
void PrintXDataList(struct resbuf* pRb)
{
	int rt, i;
	TCHAR buf[133];

	for (i = 0; pRb != NULL; i++, pRb = pRb->rbnext) {
		if (pRb->restype < 1010) {
			rt = RTSTR;
		}
		else if (pRb->restype < 1040) {
			rt = RT3DPOINT;
		}
		else if (pRb->restype < 1060) {
			rt = RTREAL;
		}
		else if (pRb->restype < 1071) {
			rt = RTSHORT;
		}
		else if (pRb->restype == 1071) {
			rt = RTLONG;
		}
		else {// restype is already RTSHORT, RTSTR,...
			rt = pRb->restype; // or else it is unknown.
		}

		switch (rt) {
		case RTSHORT:
			if (pRb->restype == RTSHORT) {
				acutPrintf(
					_T("RTSHORT : %d\n"), pRb->resval.rint);
			}
			else {
				acutPrintf(_T("(%d . %d)\n"), pRb->restype,
					pRb->resval.rint);
			};
			break;

		case RTREAL:
			if (pRb->restype == RTREAL) {
				acutPrintf(_T("RTREAL : %0.3f\n"),
					pRb->resval.rreal);
			}
			else {
				acutPrintf(_T("(%d . %0.3f)\n"), pRb->restype,
					pRb->resval.rreal);
			};
			break;

		case RTSTR:
			if (pRb->restype == RTSTR) {
				acutPrintf(_T("RTSTR : %s\n"),
					pRb->resval.rstring);
			}
			else {
				acutPrintf(_T("(%d . \"%s\")\n"), pRb->restype,
					pRb->resval.rstring);
			};
			break;

		case RT3DPOINT:
			if (pRb->restype == RT3DPOINT) {
				acutPrintf(
					_T("RT3DPOINT : %0.3f, %0.3f, %0.3f\n"),
					pRb->resval.rpoint[X],
					pRb->resval.rpoint[Y],
					pRb->resval.rpoint[Z]);
			}
			else {
				acutPrintf(_T("(%d %0.3f %0.3f %0.3f)\n"),
					pRb->restype,
					pRb->resval.rpoint[X],
					pRb->resval.rpoint[Y],
					pRb->resval.rpoint[Z]);
			}
			break;

		case RTLONG:
			acutPrintf(_T("RTLONG : %dl\n"), pRb->resval.rlong);
			break;
		}

		if ((i == 23) && (pRb->rbnext != NULL)) {
			i = 0;
			acedGetString(0,
				_T("Press <ENTER> to continue..."), buf);
		}
	}
}

//指令——檢視實體的擴充資料
void CmdViewEntXData()
{
	ads_name ent;
	AcGePoint3d ptPick;
	if (RTNORM == acedEntSel(_T("\n選擇所要添加擴充資料的實體:"), ent, asDblArray(ptPick)))
	{
		AcDbObjectId idEnt;
		AcDbEntity* pEnt;
		acdbGetObjectId(idEnt, ent);
		if (Acad::eOk == acdbOpenObject(pEnt, idEnt, AcDb::kForWrite))
		{
			CString appName = _XDATA_APPNAME_;

			// 擷取實體的擴充資料
			struct resbuf *pRb = pEnt->xData(appName);
			if (pRb != NULL)
			{
				// 在指令行顯示所有的擴充資料
				struct resbuf *pTemp = pRb;		// 使用臨時的結果緩沖區指針進行周遊,pRb不修改便于釋放
				PrintXDataList(pRb);
				acutRelRb(pRb);
			}
			else
				acutPrintf(_T("\n所選擇的實體不包含任何的擴充資料!"));
			pEnt->close();
		}
	}
}
           

二 擴充記錄

每一個對象(object)可以有一個擴充字典,擴充字典可以包含任意數量的AcDbObject對象。利用這個機制,多個程式可以将資料附加到對象上。擴充字典運作開銷要高于擴充資料,但是它提供了更靈活的附加資料的機制。

實體在預設情況下不包含擴充字典,如果要利用擴充字典儲存與實體關聯的資料,可以使用AcDbObject::createExtensionDictionary函數為實體建立擴充字典。如果實體已經包含擴充字典,則該函數的調用不會産生任何影響。

建立擴充字典之後,就可以使用AcDbObject::extensionDictionary函數獲得實體的擴充字典,AcDbDictionary對象的SetAt函數可以為字典添加一個元素,該元素既可以是AcDbXRecord,也可以是其他類型的對象。如果添加了AcDbXrecord,就可以使用acutBuildList函數建構一個儲存資料的結果緩沖區連結清單,然後使用setFromRbChain函數将結果緩沖區連結清單添加到擴充記錄中,這樣就使用擴充記錄儲存了資料。

如果要通路實體擴充字典中儲存的擴充記錄,則可以使用對象的extensionDictionary函數獲得實體的擴充字典,然後通過字典的getAt函數得到指定的元素(擴充記錄),使用AcDbXrecord類的rbChain函數得到儲存資料的結果緩沖區連結清單,進而可周遊該連結清單的所有資料。

以下代碼給對象添加擴充記錄。

#define _XRECORD_NAME_ _T("XRecord")

AcDbObjectId AddObjXRecord(AcDbObjectId idObj, const TCHAR* pszRecKey, const struct resbuf* pRb)
{
	if (!pRb)
		return AcDbObjectId::kNull;

	AcDbObjectId idDict;
	AcDbObject* pEnt;
	if (Acad::eOk == acdbOpenObject(pEnt, idObj, AcDb::kForWrite))
	{		
		pEnt->createExtensionDictionary();		//向實體添加擴充字典
		idDict = pEnt->extensionDictionary();
		pEnt->close();
	}
	else
		return AcDbObjectId::kNull;

	//建立擴充記錄實體
	AcDbXrecord* pXRec = new AcDbXrecord;

	//向擴充字典中添加一條記錄
	AcDbObjectId idXRecord = AcDbObjectId::kNull;
	AcDbDictionary* pDict = NULL;
	if (Acad::eOk == acdbOpenObject(pDict, idDict, AcDb::kForWrite))
	{
		pDict->setAt(pszRecKey, pXRec, idXRecord);
		pDict->close();
	}

	//設定擴充記錄的内容
	pXRec->setFromRbChain(*pRb);
	pXRec->close();

	return idXRecord;
}

void CmdAddEntXRecord()
{
	//提示使用者選擇一個實體
	ads_name ent;
	AcGePoint3d ptPick;
	if (RTNORM != acedEntSel(_T("\n請選擇一個實體"), ent, asDblArray(ptPick)))
		return;

	AcDbObjectId id;
	if (Acad::eOk == acdbGetObjectId(id, ent))
	{
		AcGePoint3d ptPick;
		struct resbuf* pRb = acutBuildList(AcDb::kDxfText, _T("測試字元串資料"),
			AcDb::kDxfInt32, 12,
			AcDb::kDxfReal, 3.14,
			AcDb::kDxfXCoord, asDblArray(ptPick),
			RTNONE);
		AddObjXRecord(id, _XRECORD_NAME_, pRb);
		acutRelRb(pRb);
	}
}
           

以下代碼讀取實體的擴充記錄

//列印擴充記錄連結清單
void printXRecordList(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;
}

//擷取實體擴充記錄連結清單
BOOL GetObjXRecord(AcDbObjectId id, const TCHAR* pszRecKey, struct resbuf*& pRb)
{
	BOOL bRet = FALSE;
	AcDbObject* pEnt;
	if (Acad::eOk == acdbOpenObject(pEnt, id, AcDb::kForRead))
	{
		AcDbObjectId idExtensionDict = pEnt->extensionDictionary();
		pEnt->close();
		if (!idExtensionDict)
			return bRet;

		//打開擴充字典,獲得與關鍵字pszRecKey關聯的擴充記錄
		AcDbDictionary* pDict = NULL;
		AcDbXrecord* pXRec = NULL;
		if (Acad::eOk == acdbOpenObject(pDict, idExtensionDict, AcDb::kForRead))
		{
			if (Acad::eOk == pDict->getAt(pszRecKey, (AcDbObject*&)pXRec, AcDb::kForRead))
			{
				pXRec->rbChain(&pRb);
				pXRec->close();
				bRet = TRUE;
			}
			pDict->close();
		}
	}
	return bRet;
}

void CmdViewEntXRecord()
{
	//提示使用者選擇一個實體
	ads_name ent;
	AcGePoint3d ptPick;
	if (RTNORM != acedEntSel(_T("\n請選擇索要檢視擴充記錄的實體"), ent, asDblArray(ptPick)))
		return;

	//獲得實體的擴充字典
	AcDbObjectId id;
	AcDbEntity* pEnt;
	acdbGetObjectId(id, ent);

	struct resbuf* pRb = NULL;
	if (GetObjXRecord(id, _XRECORD_NAME_, pRb))
	{
		printXRecordList(pRb);
		acutRelRb(pRb);
	}
	else
	{
		acutPrintf(_T("\n所選擇實體不包含該擴充記錄"));
	}
}
           

繼續閱讀