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

       

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


Типовой код в этой секции - приближение  к заданному по умолчанию поведению deepClone(). Глубокая клонируемая операция имеет две основных стадии:

§         Клонирование (Вы можете перегружать эту стадию)

§         Трансляция (Вы не будете должны повторно осуществить эту стадию; это может управляться тем, что помещено в карту ID)

В течение клонируемой стадии в этом примере, информация относительно старого объекта скопирована к новому объекту, используя определенный тип регистратора, чтобы выписать объект и читать это назад. Регистратор следит за объектами, принадлежащими первичному объекту так, чтобы они могли быть скопированы также.

Закончить клонируемую стадию

1 Создают новый объект того же самого типа как старый.

2 Добавляют новый объект его владельцу.

§          если объект - примитив, его владелец - запись таблицы блоков, и Вы можете использовать appendAcDbEntity().

§          если объект - AcDbObject, его владелец - AcDbDictionary, и Вы можете использовать setAt (), чтобы добавить это к словарю.

Если бы это - не первичный объект, Вы обычно добавили бы это к базе данных, используя addAcDbObject () и затем идентифицировать ее владельца, использующего setOwnerId ().

Чтобы устанавливать монопольное использование, владелец должен регистрировать из ID находящегося в собственности объекта, используя соответствующий тип монопольного использования.

3 Запрос dwgOut () на первоначальном объекте, используя глубокого клонируемого регистратора (AcDbDeepCloneFiler), чтобы выписать объект. (Или, если Вы перегружаете wblockClone () функция, использует AcDbWblockCloneFiler.)

4 Перематывают регистратора и затем вызывают dwgIn () на новом объекте.



5 Запроса setObjectIdsInFlux () на каждом новом объекте прежде, чем Вы добавляете его значение к карте объекта ID. Этот важный шаг используется, чтобы указать, что недавно созданный объект - часть глубокой клонируемой операции, и ее объект ID подчинен, чтобы измениться как часть стадии трансляции. Этот флажок автоматически выключен, когда трансляция полна.


6 Добавляют новую информацию к idMap. IdMap содержит AcDbIdPairs, которые являются парами старого (оригинала) и новых (клонированных) объектных ID. Конструктор для пары ID устанавливает первоначальный объект ID и флажок isPrimary. В этой точке, Вы устанавливаете объект ID для клонированного объекта, устанавливает флажок isCloned в TRUE, и добавляете (назначают) это на idMap.

7 Клонируют находящиеся в собственности объекты. (Этот шаг рекурсивен.)

§          Спрашивают регистратора, если имеются больше находящиеся в собственности объекты. (Для клона wblock, спросите, если имеются больше жесткие объекты.)

§          чтобы клонировать подобъект, получите его ID, и откройте объект для чтения.

§          Вызывают deepClone () на объекте. (Обратите внимание, что isPrimary установлен в FALSE, потому что это - находящийся в собственности объект.) deepClone () функция клонирует объект и устанавливает его владельца. Это также добавляет запись на карту ID.

§          Закрыли бы подобъект, если это было создано в это время.

§           

Следующий типовой код иллюстрирует эти шаги:

Acad::ErrorStatus

AsdkPoly::deepClone(

AcDbObject* 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, we set it here as well.

//

pClonedObject = NULL;

// 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;



// 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: Append the clone to its new owner. In this

// example, the original object is derived from AcDbEntity,

// so the owner is expected to be an AcDbBlockTableRecord,

// unless an ownership relationship is set up with another

// object. In that case, it is important to establish a

// connection to that owner. This sample shows a generic

// method using setOwnerId().

//

AcDbBlockTableRecord *pBTR =

AcDbBlockTableRecord::cast(pOwner);

if (pBTR != NULL) {

pBTR->appendAcDbEntity(pClone);

} else {

if (isPrimary)

return Acad::eInvalidOwnerObject;

// Some form of this code is only necessary if

// anyone has set up an ownership for the object

// other than with an AcDbBlockTableRecord.

//

pOwner->database()->addAcDbObject(pClone);

pClone->setOwnerId(pOwner->objectId());

}

// Step 3: Now contents are copied to the clone. This is done

// using an AcDbDeepCloneFiler. This filer keeps a list of all

// AcDbHardOwnershipIds and AcDbSoftOwnershipIds contained in

// the object and its derived classes. This list is then used

// to know what additional, "owned" objects need to be cloned

// below.

//

AcDbDeepCloneFiler 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 deepClone(). 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.

//

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

idPair.setIsCloned(Adesk::kTrue);

idMap.assign(idPair);

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



// any owned objects.

//

AcDbObjectId id;

while (filer.getNextOwnedObject(id)) {

AcDbObject *pSubObject;

AcDbObject *pClonedSubObject;

// Some object’ s references may be set to NULL,

// so don’t try to clone them.

//

if (id == NULL)

continue;

// Open the object and clone it. 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.

//

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

pClonedSubObject = NULL;

pSubObject->deepClone(pClonedObject,

pClonedSubObject,

idMap, Adesk::kFalse);

// If this is a kDcInsert context, the objects

// may be "cheap" cloned. In this case, they are

// "moved" instead of cloned. The result is that

// pSubObject and pClonedSubObject will point to

// the same object. Therefore, we only want to close

// pSubObject if it really is a different object

// than its clone.

//

if (pSubObject != pClonedSubObject)

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 we have no immediate

// use for it now, we can close the clone.

//

if (pClonedSubObject != NULL)

pClonedSubObject->close();

}

// Leave pClonedObject open for the caller.

//

return Acad::eOk;

}


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