Тема: Копирование примитива

Правильно ли я понимаю, что имея

AcDbEntity* pEnt 

(открытый для записи), я могу сделать с него копию и поместить на слой LayerId с помощью:

AcDbEntity* pEntCopy = (AcDbEntity*)(pEnt->clone());
pEntCopy->setLayer(LayerId);
pEntCopy->close();

Т.е. clone() создает объект, готовый для работы с ним. Или необходимо сделать с ним перед этим еще что-то?

Re: Копирование примитива

Понимаешь неправильно :( Таким образом ты создаешь не резидентный (т.е. не принадлежащий чертежу) примитив. Его следует еще и добавить в чертеж:

AcDbObjectId DupEntityOnOtherLayer(AcDbEntity *pEnt, AcDbObjectId layerId)
{
  AcDbObjectId id = AcDbObjectId::kNull;
  AcDbEntity *pEntCopy = (AcDbEntity *)pEnt->clone();
  if (pEntCopy) {
    pEntCopy->setLayer(layerId);
    AcDbBlockTableRecordPointer pBTR(pEnt->ownerId(),AcDb::kForWrite);
    if (pBTR.openStatus() == Acad::eOk) {
      pBTR->appendAcDbEntity(id,pEntCopy);
      pEntCopy->close();
    }
  }
  return id;
}

Но это все будет работать, только если примитив простой. Для сложных примитивов необходимо deepClone(), а еще лучше AcDbDatabase::deepCloneObjects с последующим открытием каждого из примитивов в AcDbIdMapping и установкой ему слоя.

Re: Копирование примитива

В общем случае приблизительно так:

   static Acad::ErrorStatus DupComplexEntityOnLayer(AcDbObjectId orgId, AcDbObjectId layerid)
  {
    Acad::ErrorStatus es = Acad::eOk;
    AcDbObjectPointer<AcDbEntity> ent(orgId,AcDb::kForRead);
    if ((es = ent.openStatus()) != Acad::eOk) return es;
    AcDbDatabase *db = orgId.database();
    AcDbObjectIdArray arId; arId.append(orgId);
    AcDbIdMapping mapId;
    if ((es = db->deepCloneObjects(arId,ent->ownerId(),mapId)) != Acad::eOk) return es;
    AcDbIdMappingIter mapIdIter(mapId);
    for (mapIdIter.start(); !mapIdIter.done(); mapIdIter.next()) {
      AcDbIdPair pair; mapIdIter.getMap(pair);
      AcDbObjectPointer<AcDbEntity> pCopy(pair.value(),AcDb::kForWrite);
      if ((es = pCopy.openStatus()) != Acad::eOk) return es;
      pCopy->setLayer(layerid);
    }
    return es;
  }
  //
  // Тестовая команда
  //
  static void DuplicateEntityCopyOnLayer(void)
  {
    Acad::ErrorStatus es;
    ads_name en; ads_point p;
    if (acedEntSel("\nВыберите примитив: ",en,p) == RTNORM) {
      char layername[256];
      if (acedGetString(TRUE,"\nУкажите имя слоя: ",layername)) {
        AcDbLayerTableRecordPointer ltr(layername,acdbCurDwg(),AcDb::kForRead);
        if (ltr.openStatus() != Acad::eOk) {
          acutPrintf("\nТакого слоя нет или он не может быть открыт для чтения!");
          return;
        }
        AcDbObjectId layerId = ltr->objectId();
        AcDbObjectId eId; acdbGetObjectId(eId,en);
        if ((es = DupComplexEntityOnLayer(eId,layerId)) != Acad::eOk) {
          acutPrintf("\nОшибка клонирования примитива: %s",acadErrorStatusText(es));
        }
      }
    }
  }

Re: Копирование примитива

Большое спасибо. Все работает.
Правда не все понятно с куском кода по deepCloneObjects()

Re: Копирование примитива

> Alexey
Правда не все понятно с куском кода по deepCloneObjects()
Есть объекты, которые как свою часть включают другой объект через ссылку (AcDbHardPointer(Ownership)Id), когда ты просто делаешь clone(), то копируется только сам объект. В результате и оригинал и копия ссылаются только на один общий объект... допустим ты удаляешь один из них... он убивает того на которого ссылается и... второй остается сломанным.
В таких случаях надо использовать deepCloneObjects. deepClone() - лучше самому ручками не звать т.к. это метод который должен зваться автоматически при выполнении deepCloneObjects.
Если использовать deepCloneObjects - то будет создана глубокая копия объекта т.е. его ссылки если они обладаемы клонируемым объектом так же будут отклонированы.

Re: Копирование примитива

> KonstantinM
Все очень точно объяснил. :)

> Alexey
От добавлю, что если использовать метод clone() для AcDb2dPolyline или AcDb3dPolyline, то создается копия только главного примитива, но не вершин полилинии. Аналогично для AcDbBlockReference не будут создаваться аттрибуты блока. Так что без deepClone не обойтись.
Немного подправил код. В определнных случаях слой мог присваиваться не всем субпримитивам основного примитива. Это в случае, если основной примитив ссылается не только на примитивы (AcDbEntity) , но и на объекты (AcDbObject):

  static Acad::ErrorStatus DupComplexEntityOnLayer(AcDbObjectId orgId, AcDbObjectId layerid)
  {
    Acad::ErrorStatus es = Acad::eOk;
    AcDbObjectPointer<AcDbObject> ent(orgId,AcDb::kForRead);
    if ((es = ent.openStatus()) != Acad::eOk) return es;
    AcDbDatabase *db = orgId.database();
    AcDbObjectIdArray arId; arId.append(orgId);
    AcDbIdMapping mapId;
    if ((es = db->deepCloneObjects(arId,ent->ownerId(),mapId)) != Acad::eOk) {
      return es;
    }
    AcDbIdMappingIter mapIdIter(mapId);
    for (mapIdIter.start(); !mapIdIter.done(); mapIdIter.next()) {
      AcDbIdPair pair; mapIdIter.getMap(pair);
      AcDbObjectPointer<AcDbEntity> pCopy(pair.value(),AcDb::kForWrite);
      if ((es = pCopy.openStatus()) == Acad::eOk) {
        pCopy->setLayer(layerid);
      }
    }
    return Acad::eOk;
  }

Re: Копирование примитива

Спасибо за комментарии.

Re: Копирование примитива

Всё вроде здорово, но почему-то после отработки или во время  DupComplexEntityOnLayer вылетает весь autocad :(
Может нужно какие-то переменные очистить? которые были открыты для записи?

Re: Копирование примитива

> wolka
Проверь, что ты не открыл примитивы, которые этой функцией пытаешься комаровать. Вот тестовая команда для проверки:

static void CopyOnLayer(void)
{
    Acad::ErrorStatus es;
    ads_name en; ads_point p;
    if (acedEntSel("\nВыберите примитив: ",en,p) == RTNORM) {
      char layername[256];
      if (acedGetString(TRUE,"\nУкажите имя слоя: ",layername)) {
        AcDbLayerTableRecordPointer ltr(layername,acdbCurDwg(),AcDb::kForRead);
        if (ltr.openStatus() != Acad::eOk) {
          acutPrintf("\nТакого слоя нет или он не может быть открыт для чтения!");
          return;
        }
        AcDbObjectId layerId = ltr->objectId();
        AcDbObjectId eId; acdbGetObjectId(eId,en);
        if ((es = DupComplexEntityOnLayer(eId,layerId)) != Acad::eOk) {
          acutPrintf("\nОшибка клонирования примитива: %s",acadErrorStatusText(es));
        }
      }
  }
}