ObjectARX, AutoCAD. Среда программирования библиотеки C++

Перегрузка wblockClone () Функция


Когда операция клона wblock выполнена, AutoCAD создает имеющую силу базу данных для нового рисунка, который содержит словарь имен объектов, все таблицы идентификаторов, и полный набор переменных заголовка. Следующий код приближает заданное по умолчанию выполнение wblockClone (). Перечисленные шаги соответствуют, те перечисляли в секции “ Перегрузка deepClone () Функцию ” на странице 484.

WblockClone () функция использует регистратора класса AcDbWblockCloneFiler, который возвращает список жесткого указателя и жестких связей владельца первичного объекта. Прежде, чем Вы вызываете wblockClone () на этих подобъектах, Вы должны проверить владельца подобъекта. В этой точке, вы будете делать одну из двух вещей:

N, если Вы - владелец объекта, заставляет владельца подобъекта быть клоном вас непосредственно.

N, если Вы - не владелец объекта, проход в базе данных клона как pOwner параметр в wBlockClone () функциональный запрос. В это время, объект добавлен в конец к новой базе данных, получает объект ID, и помещен в карту ID. Вход карты ID для этого объекта определит FALSE для isOwnerTranslated поля.

Если pOwner установлен в базу данных, wblockClone () должен установить владельца клонированного объекта тому же самому владельцу как таковой первоначального объекта. Тогда, когда ссылки оттранслированы в соответствии с AutoCAD, это модифицирует ссылку владельца к клонированному объекту в новой базе данных.

Важно гарантировать, что все объекты обладания клонировались. AutoCAD всегда клонирует таблицы идентификаторов, словарь имен объектов, пространство модели, и пространство листа (для клонируемых контекстов других чем AcDb:: kDcXrefBind) в течение клона wblock. Приложения с обладанием объектов ответствены за обеспечение, чтобы эти объекты клонировались{*имитировались*} в случае необходимости. Если объект обладания не клонировался и не найден в карте ID, wblock клонируемыми аварийными прекращениями работы с AcDb:: eOwnerNotSet.

Вы должны пройти в базе данных как владелец объекта, когда Вы копируете примитив, которых ссылок таблица идентификаторов делает запись. Например, предположите, что Вы вызываете wblockClone () на объекте сферы. Запись таблицы блоков - жесткий владелец этого объекта сферы. Объект сферы содержит жесткую ссылку к таблице уровня.


Сначала, в beginDeepClone () стадия, новая база данных создана и основывать с заданными по умолчанию элементами. Следующий рисунок показывает запись таблицы блоков пространства модели и таблицу уровня, потому что они уместны этому разделу. Клонирование, которое происходит в этой стадии всегда, случается в течение wblock операции.

В beginWblock () стадия, набор выборов клонировался, как показано в следующем рисунке. В этом примере, сфера клонировался.



Поскольку сфера содержит жесткий указатель на Уровень 1, Уровень 1 клонирован.







Затем, указатели должны быть оттранслированы, чтобы отнесится к клонированным объектам, как показано в следующем рисунке. BeginDeepCloneXlation() уведомление указывает начало этой стадии.



Карта ID предыдущего рисунка



KEY



VALUE



isCloned



isPrimary



isOwnerXlated



BTR1



BTR2



TRUE



FALSE



TRUE



SPH1



SPH2



TRUE



TRUE



TRUE



LT1



LT2



TRUE



FALSE



*



LTR1



LTR2



TRUE



FALSE



FALSE†

* Владелец таблицы уровня - база данных непосредственно, так что этот вход бессмысленен.

† В течение трансляции, эта установка указывает, что уровень транслирует его владельца от LayerTable 1 к LayerTable 2.

Процесс клона wblock используется для таблицы перекрестных ссылок, связывают также как wblock. Потребности оба очень похожи, но там - несколько различий, которые требуют специального внимания при перегрузке wblockClone ().

Wblock клонирует все отобранные примитивы. Однако, таблица перекрестных ссылок связывает, никогда не клонирует примитивы, которые находятся в пространстве листа. Это оставляет две вещи рассмотреть при создании объектов или примитивов, и использования AcDbHardPointerIds. Сначала, в начале wblockClone любого AcDbEntity (), выясните, если клонируемый контекст - AcDb:: kDcXrefBind и, если так, клонируется ли примитив в пространстве листа. Если это, то никакое клонирование не должно быть сделано, и wblockClone () должен возвратить Acad:: eOk.

Если ваш класс пользователя имеет любой AcDbHardPointerIds, который может указывать на примитивы (типа, мы делаем с AcDbGroup), то примитивы могли бы быть в пространстве листа и не будут поэтому клонироваться. В таком случае, AcDbHardPointerIds будет установлен в NULL.



Wblock не следует за жесткими ссылками указателя поперек баз данных. Однако, таблица перекрестных ссылок связывает, делает это все время. Например, примитив в рисунке таблицы перекрестных ссылок может быть на VISRETAIN уровне в ведущем рисунке. Так, если Вы осуществляете, ваш wblockClone () с циклом, чтобы проверить подобъекты, и базу данных подобъекта - не тот же самый как таковой клонируемого объекта, Вы должны пропустить подобъект, если клонируемый контекст - не AcDb:: kDcXrefBind. Например:

if(pSubObject->database() != database() && idMap.deepCloneContext() != AcDb::kDcXrefBind)

{

pSubObject->close();

continue;

}

Следующие показы кода, перегружающие wblockClone () чтобы осуществить это для заказного примитива (AsdkPoly). Эта функция вызвана с кодом, показанным в “ Редактор Функции Уведомления Реактора ” на странице 504.

Acad::ErrorStatus

AsdkPoly::wblockClone(AcRxObject* pOwner,

AcDbObject*& pClonedObject,

AcDbIdMapping& idMap,

Adesk::Boolean isPrimary) const

{

// You should always pass back pClonedObject == NULL

// if, for any reason, you do not actually clone it

// during this call. The caller should pass it in

// as NULL, but to be safe, it is set here as well.

//

pClonedObject = NULL;

// If this is a fast wblock operation, no cloning

// should take place, so we simply call the base class’s

// wblockClone() and return whatever it returns.

//

// For fast wblock, the source and destination databases

// are the same, so we can use that as the test to see

// if a fast wblock is in progress.

//

AcDbDatabase *pDest, *pOrig;

idMap.destDb(pDest);

idMap.origDb(pOrig);

if (pDest == pOrig)

return AcDbCurve::wblockClone(pOwner, pClonedObject, idMap, isPrimary);

// If this is an xref bind operation and this AsdkPoly

// entity is in paper space, then we don’t want to

// clone because xref bind doesn’t support cloning

// entities in paper space. Simply return Acad::eOk.

//

static AcDbObjectId pspace = AcDbObjectId::kNull;



if (pspace == AcDbObjectId::kNull) {

AcDbBlockTable *pTable;

database()->getSymbolTable(pTable, AcDb::kForRead);

pTable->getAt(ACDB_PAPER_SPACE, pspace);

pTable->close();

}

if ( idMap.deepCloneContext() == AcDb::kDcXrefBind && ownerId() == pspace)

return Acad::eOk;

// If this object is in the idMap and is already

// cloned, then return.

//

bool isPrim = false;

if (isPrimary)

isPrim = true;

AcDbIdPair idPair(objectId(), (AcDbObjectId)NULL, false, isPrim);

if (idMap.compute(idPair) && (idPair.value() != NULL))

return Acad::eOk;

// The owner object can be either an AcDbObject or an

// AcDbDatabase. AcDbDatabase is used if the caller is

// not the owner of the object being cloned (because it

// is being cloned as part of an AcDbHardPointerId

// reference). In this case, the correct ownership

// will be set during reference translation. If

// the owner is an AcDbDatabase, then pOwn will be left

// NULL here, and is used as a "flag" later.

//

AcDbObject *pOwn = AcDbObject::cast(pOwner);

AcDbDatabase *pDb = AcDbDatabase::cast(pOwner);

if (pDb == NULL)

pDb = pOwn->database();

// Step 1: Create the clone.

//

AsdkPoly *pClone = (AsdkPoly*)isA()->create();

if (pClone != NULL)

pClonedObject = pClone; // Set the return value.

else

return Acad::eOutOfMemory;

// Step 2: If the owner is an AcDbBlockTableRecord, go ahead

// and append the clone. If not, but we know who the

// owner is, set the clone’s ownerId to it. Otherwise,

// we set the clone’s ownerId to our own ownerId (in

// other words, the original ownerId). This ID will

// then be used later, in reference translation, as

// a key to finding who the new owner should be. This

// means that the original owner must also be cloned at

// some point during the wblock operation.

// EndDeepClone’s reference translation aborts if the

// owner is not found in the ID map.

//

// The most common situation where this happens is

// AcDbEntity references to symbol table records, such



// as the layer an entity is on. This is when you will

// have to pass in the destination database as the owner

// of the layer table record. Since all symbol tables

// are always cloned in wblock, you do not need to make

// sure that symbol table record owners are cloned.

//

// However, if the owner is one of your own classes,

// then it is up to you to make sure that it gets

// cloned. This is probably easiest to do at the end

// of this function. Otherwise you may have problems

// with recursion when the owner, in turn, attempts

// to clone this object as one of its subobjects.

//

AcDbBlockTableRecord *pBTR = NULL;

if (pOwn != NULL)

pBTR = AcDbBlockTableRecord::cast(pOwn);

if (pBTR != NULL) {

pBTR->appendAcDbEntity(pClone);

} else {

pDb->addAcDbObject(pClonedObject);

pClone->setOwnerId( (pOwn != NULL) ? pOwn->objectId() : ownerId());

}

// Step 3: The AcDbWblockCloneFiler makes a list of

// AcDbHardOwnershipIds and AcDbHardPointerIds. These

// are the references that must be cloned during a

// wblock operation.

//

AcDbWblockCloneFiler filer;

dwgOut(&filer);

// Step 4: Rewind the filer and read the data into the clone.

//

filer.seek(0L, AcDb::kSeekFromStart);

pClone->dwgIn(&filer);

// Step 5:

// This must be called for all newly created objects

// in wblockClone. It is turned off by endDeepClone()

// after it has translated the references to their

// new values.

//

pClone->setAcDbObjectIdsInFlux();

// Step 6: Add the new information to the ID map. We can use

// the ID pair started above. We must also let the

// idMap entry know whether the clone’s owner is

// correct, or needs to be translated later.

//

idPair.setIsOwnerXlated((Adesk::Boolean)(pOwn != NULL));

idPair.setValue(pClonedObject->objectId());

idPair.setIsCloned(Adesk::kTrue);

idMap.assign(idPair);

// Step 7: Using the filer list created above, find and clone

// any hard references.

//

AcDbObjectId id;

while (filer.getNextHardObject(id)) {



AcDbObject *pSubObject;

AcDbObject *pClonedSubObject;

// Some object references may be set to NULL,

// so don’t try to clone them.

//

if (id == NULL)

continue;

// If the referenced object is from a different

// database, such as an xref, do not clone it.

//

acdbOpenAcDbObject(pSubObject, id, AcDb::kForRead);

if (pSubObject->database() != database()) {

pSubObject->close();

continue;

}

// To find out if this is an AcDbHardPointerId

// versus an AcDbHardOwnershipId, check if we are the

// owner of the pSubObject. If we are not,

// then we cannot pass our clone in as the owner

// for the pSubObject’s clone. In that case, we

// pass in our clone’s database (the destination

// database).

//

// Note that "isPrimary" is set to kFalse here

// because the object is being cloned, not as part

// of the primary set, but because it is owned by

// something in the primary set.

//

pClonedSubObject = NULL;

if (pSubObject->ownerId() == objectId()) {

pSubObject->wblockClone(pClone,

pClonedSubObject,

idMap, Adesk::kFalse);

} else {

pSubObject->wblockClone(

pClone->database(),

pClonedSubObject,

idMap, Adesk::kFalse);

}

pSubObject->close();

// The pSubObject may either already have been

// cloned, or for some reason has chosen not to be

// cloned. In that case, the returned pointer will

// be NULL. Otherwise, since there is no immediate

// use for it now, the clone can be closed.

//

if (pClonedSubObject != NULL)

pClonedSubObject->close();

}

// Leave pClonedObject open for the caller.

//

return Acad::eOk;

}

ПРИМЕЧАНИЕ Помните, что, когда wblock () функция находится в процессе выполнения, ссылки указателя в базе данных адресата еще не были оттранслированы. Следующий код не работает правильно, потому что, хотя это пробует открывать запись таблицы блоков пространства модели базы данных адресата, запись таблицы блоков пространства модели исходной базы данных открыта вместо этого. Неоттранслированная ссылка в таблице блоков базы данных адресата - все еще что касается пространства модели исходной базы данных.



void

AsdkWblockReactor::otherWblock(

AcDbDatabase* pDestDb,

AcDbIdMapping& idMap,

AcDbDatabase* pSrcDb)

{

AcDbBlockTable *pDestBlockTable;

AcDbBlockTableRecord *pDestBTR;

pDestDb->getSymbolTable(pDestBlockTable, AcDb::kForRead);

pDestBlockTable->getAt(ACDB_MODEL_SPACE, pDestBTR, AcDb::kForRead);

pDestBlockTable->close();

// Now pDestBTR is pointing to pSrcDb database’s model

// space, not to the destination database’s model space!

// The code above is not correct!

}

Чтобы находить пространство модели адресата, Вы должны смотреть это в карте ID:

void

AsdkWblockReactor::otherWblock(

AcDbDatabase* pDestDb,

AcDbIdMapping& idMap,

AcDbDatabase* pSrcDb)

{

// To find the destination model space, you must look

// it up in the ID map:

AcDbBlockTable *pSrcBlockTable;

pSrcDb->getSymbolTable(pSrcBlockTable, AcDb::kForRead);

AcDbObjectId srcModelSpaceId;

pSrcBlockTable->getAt(ACDB_MODEL_SPACE, srcModelSpaceId);

pSrcBlockTable->close();

AcDbIdPair idPair;

idPair.setKey(srcModelSpaceId);

idMap.compute(idPair);

AcDbBlockTableRecord *pDestBTR;

acdbOpenAcDbObject((AcDbObject*&)pDestBTR,

idPair.value(), AcDb::kForRead, Adesk::kTrue);

}


Содержание раздела