第四章 图形数据库操作
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.
页:
[1]