AutoCAD圖形實際上是一系列存放在一個AcDbDatabase類型的數據庫中的AcDb對象。AcDbDatabase數據庫中所有的對象都有一個句柄,在一個圖形(DWG)文件中,對象句柄是唯一的,用來標識對象。AutoCAD圖形實體(AcDbEntity類對象)只是AcDbDatabase數據庫的一種特殊的對象,用戶可以在圖形窗口看到並編輯它。AcDbDatabase數據庫中的對象還有符號表、詞典和其它與AcDb類對象相關的符號。數據庫中所有的圖形實體和對象都可以使用ObjectARX技術,通過程序設計來進行修改和編輯。
AcDbDatabase既然是數據庫,它必然具備數據庫的基本組織結構。它由多個表(Table)和表中的記錄(Record)構成。AcDbDatabase數據庫包括九個符號表和一個命名對象詞典。
AcDbDatabase數據庫
|------AcDb符號表(9個符號表)
| |------塊表(AcDbBlockTable)
| |------尺寸標注樣式表(AcDbDimStyleTable)
| |------層表(AcDbLayerTable)
| |------線型表(AcDbLinetypeTable)
| |------已注冊應用程序表(AcDbRegAppTable)
| |------字體樣式表(AcDbTextStyleTable)
| |------用戶坐標系表(AcDbUCSTable)
| |------視口表(AcDbViewportTable)
| |------視圖表(AcDbViewTable)
|-------命名對象詞典
1.1 新建數據庫、使用已有的數據庫
要使用AcDbDatabase數據庫,與使用其它數據庫一樣,首先要聲明一個數據庫對象。
AcDbDatabase類的聲明,調用類的構造函數:
AcDbDatabase ::AcDbDatabase(bool buildDefaultDrawing = true, bool noDocument = false);
buildDefaultDrawing: 控制是否創建一個包括所有默認數據記錄的數據庫。
該參數的默認值為true,這樣在AcDbDatabase數據庫創建時,將在新建的數據庫中包含一個AutoCAD圖形數據庫必須包含的基本數據要素,這些要素包括九個符號表及其初始記錄(比如0層、STANDARD文字樣式等),命名對象詞典(組詞典和多線樣式詞典)以及必要的系統變量設置。這樣就可以向新建的數據庫中添加各種實體和對象。
若指定該參數為false,AutoCAD將創建一個完全空的AcDbDatabase數據庫。這樣的AcDbDatabase數據庫不能直接向其中添加實體或對象,需讀入一個圖形文件來拓展該圖形數據庫,然后再逐步添加或修改數據庫中的實體或對象。讀入圖形拓展數據庫使用的函數是:
AcadErrorStatus AcDbDatabase::readDwgFile(const char* fileName );<其實,readDwgFile()函數還有兩個參數,分別控制數據庫讀寫權限和內碼轉換>。
若准備新建數據庫並向其中添加實體或對象
AcDbDatabase *pDb= new AcDbDatabase();
若要使用已有的圖形,比如“test.dwg”文件,則使用:
AcDbDatabase *pDb= new AcDbDatabase(Adesk::kFalse);
pDb->readDwgFile(“test.dwg”);
//*********************************************//
AcDbDatabase *pDb=acdbCurDwg();//該函數返回指向當前圖形數據庫的指針
在ACAD 2000以上版本中也可以使用相同的方法,不過建議使用下列函數:
AcDbDatabase *pDb=acdbHostApplicationServices()->workingDatabase();
實際上,在ARX 2000及以上版本中,acdbCurDwg()已經定義為宏,宏擴展后就是上述函數。
//********************************************//
1.2 使用數據庫表和記錄
新建或打開圖形數據庫后,可獲取表和記錄的指針,然后再對記錄進行操作。要獲取AcDbDatabase數據庫記錄指針,大致分為兩個步驟:
首先,獲取數據庫表的指針。為了獲取該指針,須聲明一個類指針,該指針類型決定要使用的數據庫表的類型(或名稱)。
比如說,要使用AcDb的塊表及其記錄,應該這樣聲明指針類:
AcDbBlockTable *pBlkTbl;然后使用AcDbDatabase類的成員函數獲取表指針。獲取塊表指針可使用函數getBlockTable()函數。
Acad::ErrorStatus AcDbDatabase::getBlockTable(AcDbBlockTable*& pBlkTbl,AcDb::OpenMode mode);
該函數的第一個參數是一個指向表引用(或者說地址)的指針。用於函數輸出塊表指針。另一個參數控制使用表的讀寫權限。
從ARX2000開始,在AcDbDatabase類的成員函數中,還有一種方法可獲取數據庫中符號表的指針。即使用getSymbolTable()函數,該函數有九個重載版本,分別對應九個符號表,幾個重載版本之間僅第一個參數的類型不同。
例如,要新建圖層,可以這樣獲取層表指針:
AcDbLayerTable* pLayerTbl;
pDb->getSymbolTable(pLayerTbl,AcDb::kForWrite);//此處pDb指已打開的數據庫指針。
使用數據庫,最終往往要對數據庫表中的記錄進行操作,因此打開表后,就需要獲取記錄指針。所有AcDb符號表記錄指針都可通過調用對應表的getAt()函數來實現。每一個getAt()函數都有兩個重載版本,分別輸出記錄ID或記錄指針。
getAt()函數完整語法:
輸出記錄指針:
Acad::ErrorStatus AcDb##BASE_NAME##Table::getAt(const char* pEntryName,AcDb##BASE_NAME##TableRecord*&pRecord, AcDb::OpenMode mode,Adesk::Boolean openErasedRecord =Adesk::kFalse) const;
輸出記錄ID:Acad::ErrorStatus AcDb##BASE_NAME##Table::getAt(const char* pEntryName,AcDbObjectId& recordId, Adesk::Boolean getErasedRecord =Adesk::kFalse) const;
實際應用時,將##BASE_NAME##替換成九個符號表的實際類型。
在這解釋兩個參數:
char* pEntryName要求輸入符號表記錄名稱,例如塊表中至少有兩條記錄,模型空間(可用宏ACDB_MODEL_SPACE訪問記錄名稱)和圖紙空間即(ACDB_PAPER_SPACE)。
最后,取出數據庫符號表記錄后,若不再使用表對象,應及時關閉,回收系統資源。AcDb##BASE_NAME##Table::close();
1.3 添加、刪除記錄
獲取數據庫記錄指針或記錄ID后,就可以對數據庫記錄進行操作了,這包括在數據庫中添加、刪除記錄,提取記錄中的數據,即查找記錄。
向數據庫中添加記錄,通用的方法是調用符號表類的add()成員函數。
Acad::ErrorStatus AcDb##BASE_NAME##Table ::add(AcDbSymbolTableRecord* pRecord); 或
Acad::ErrorStatus AcDb##BASE_NAME##Table ::add(AcDbObjectId& recordId,AcDbSymbolTableRecord* pRecord); //該函數第一個參數用於輸出新添加的記錄ID在這要說明一下,通常我們向模型空間添加實體不用這些方法。因為模型空間本身就是AcDb塊表中的一條記錄,向其中添加實體僅僅是對該記錄進行操作,不需要向數據庫中添加記錄。
查找記錄,首先聲明遍歷器類對象:
AcDbBlockTableRecordIterator* pIT = NULL;
再用newIterator函數創建一個AcDbBlockTableRecordIterator對象,用於遍歷塊表記錄中的記錄,這個指針pIT 就指向了這個遍歷器。
Acad::eOk != pBTR->newIterator(pIT); // <AcDbBlockTableRecord* pBTR;>
Acad::ErrorStatus AcDbBlockTableRecord::newIterator(AcDbBlockTableRecordIterator*& pIterator,bool atBeginning = true,bool skipDeleted = true);
pIterator:輸入指向新創建的遍歷器的指針
atBeginning:輸入布爾值,表示從塊表記錄的實體的開始或結束處開始遍歷
skipDeleted:輸入布爾值,表示是否忽略刪除的實體
此函數創建一個AcDbBlockTableRecordIterator對象,用於遍歷塊表記錄中的記錄,並設置pIterator指向這個遍歷器。如果atBeginning為true,則遍歷器初始化為指向塊中的第一個實體(否則指向最后一個實體)。如果skipDeleted為true,則遍歷器指向第一個或最后一個未刪除的實體,否則它定位在第一個或最后一個實體,無論實體是否被刪除。
如果成功返回Acad::eOk。如果沒有足夠的內存創建遍歷器,則返回Acad::eOutOfMemory。
若不再使用表記錄對象,應及時關閉,回收系統資源。AcDb##BASE_NAME##Table::close();
遍歷記錄;得到記錄條數
int ncount=0;
for ( ; !pIT->done(); pIT->step())
{
nCount++;
}
AcDbBlockTableRecordIterator::done 函數
bool done() const;
如果遍歷器定位在塊的任一端后則此函數返回true,否則返回false。
AcDbBlockTableRecordIterator::step 函數
void step(bool forward = true,bool skipDeleted = true);
forward : 輸入布爾值,控制移動塊中遍歷器的方向
skipDeleted: 輸入布爾值,表示是否忽略刪除的一個實體
此函數移動塊至塊中的下一個(或上一個)實體。如果forward為true,則遍歷器向塊的結束處遍歷,否則向塊的開始處遍歷。如果skipDeleted為true,則跳過已刪除的塊,否則任何已刪除的塊也將被掃描。
pIT->start();
AcDbBlockTableRecordIterator::start 函數
void start(bool atBeginning = true,bool skipDeleted = true);
atBeginning : 輸入布爾值,控制塊中初始的遍歷器位置
skipDeleted : 輸入布爾值,表示可定位在一個已刪除實體上
此函數將遍歷器的位置定位在塊的開始處或結束處。如果atBeginning為true,則遍歷定位在表的開始處,否則它定位在表的結束處。如果skipDeleted為true,遍歷器定位在第一個或最后一個非刪除的實體,否則它定位在第一個或最后一個實體,無論它是刪除或未刪除的。
AcDbObjectId id;
pIT->getEntityId( id ) //輸出塊中當前實體的實體ID
AcDbEntity *pEnt;
pIT->getEntity(pEnt, AcDb::kForRead); //輸出指向遍歷器當前定位的實體的指針
AcDbBlockTableRecordIterator::getEntity 函數
Acad::ErrorStatus getEntity(AcDbEntity*& pEntity,AcDb::OpenMode openMode,bool openErasedEntity = false) const;
pEntity: 輸出指向遍歷器當前定位的實體的指針
openMode: 輸入打開實體的模式,可能的模式為:
AcDb::kForRead
AcDb::kForWrite
AcDb::kForNotify
openErasedEntity: 輸入布爾值,表示是否打開已刪除的實體
此函數以openMode模式打開遍歷器定位的實體,設置pEntity指向打開的記錄。只在當openErasedEntity為true時,此函數才會打開已刪除的實體。
可能的返回ErrorStatus值為:Acad::eOk, Acad::ePermanentlyErased, Acad::eAtMaxReaders, Acad::eWasOpenForNotify, Acad::eWasNotifying, Acad::eWasOpenForUndo, Acad::eWasOpenForWrite, Acad::eLockViolation,或Acad::eWasOpenForRead.