第四章 图形数据库操作

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.

posted @ 2012-09-02 18:35  IT.笨笨  阅读(3893)  评论(2编辑  收藏  举报