Тема: Как решить проблему с обработкой блоков ?

У меня такая проблема. Мне необходимо над примитивами в блоке выполнить команду через acedCommand. Я перебираю все блоки, а в каждом блоке перебираю примитивы и пытаюсь создать из них selection set, а затем его передать acedCommand.
В процессе выполнения selection set создаётся только для model_space, а из примитивов в блоках его создать не получается.
Как можно решить такую проблему? Может блок надо вначале взорвать, а потом заново собрать? Если да, то как это сделать, а то у меня не получается.
Заранее спасибо.

Re: Как решить проблему с обработкой блоков ?

Примитив, находящийся внутри блока не может быть включен в Selection Set. Подумай лучше как заменить команду, которую ты вызываешь при помощи acedCommand(), на что-то свое с использованием возможностей ObjectARX. В 99%-ах случаев это можно сделать.
Второй вариант - расчленять блоки. А точнее получить расчлененную копию блока и работать с полученными примитивами. Ну а по окончании работы, если они не нужны - удалить их.

Re: Как решить проблему с обработкой блоков ?

В моём случае можно обойтись только вторым вариантом. Я использую функцию explodeToOwnerSpace() чтобы разбить блок на части, затем я обрабатываю получившиеся части, а потом необходимо опять записать их в тот же блок, т.к. они немного меняются. Для этого я использую функцию assumeOwnershipOf(). Но тут возникает проблема. Когда я добавляю их в блок они почему-то смещаются и поварачиваются, причём это происходит даже если я их не обрабатываю. Из-за чего такое может происходить, и как такого можно избежать?

Re: Как решить проблему с обработкой блоков ?

> Lord
Нужно выполнить обратное преобразование координат (transformBy) с учетом системы координат блока.

Re: Как решить проблему с обработкой блоков ?

P.S.: Еще один существенный момент. У тебя только один AcDbBlockReference соответствующий AcDbBlockTableRecord? Если нет, то у тебя получится полная ерунда, т.к. если ты изменишь AcDbBlockTableRecord, то это отразится на всех AcDbBlockReference.
Если не секрет, то объясни какую команду ты вызываешь при помощи acedCommand. И вообще, что ты пытаешься делать с примитивами в блоке. Может у меня появятся идеи получше. :)

Re: Как решить проблему с обработкой блоков ?

P.S.S: Ну а это непосредственный ответ на твой вопрос:

static Acad::ErrorStatus MoveToBlockDefinition(AcDbObjectId idBlockRef, AcDbObjectIdArray &ids)
{
  Acad::ErrorStatus es;
  AcDbObjectPointer<AcDbBlockReference> pRef(idBlockRef,AcDb::kForRead);
  if ((es = pRef.openStatus()) != Acad::eOk) return es;
  // Матрица преобразования Block Reference OCS -> WCS
  AcGeMatrix3d xform = pRef->blockTransform ();
  pRef->close(); // Чтобы не мешалась
  AcDbBlockTableRecordPointer pBtr(pRef->blockTableRecord(),AcDb::kForRead);
  if ((es = pBtr.openStatus()) != Acad::eOk) return es;
  AcGePoint3d pt3dBlkOrigin = pBtr->origin();
  // Учитываем возможность ненулевой базовой точки блока (Block Definition)
  if (pt3dBlkOrigin != AcGePoint3d::kOrigin) {
    AcGeVector3d xformOrigin = xform.translation();
    AcGeVector3d vectorOrigin(pt3dBlkOrigin.x,pt3dBlkOrigin.y,pt3dBlkOrigin.x);
    vectorOrigin.transformBy(xform);
    xformOrigin -= vectorOrigin;
    xform.setTranslation(xformOrigin);
  }
  // Инвертируем матрицу преобразования, чтобы преобразовывать
  // из WCS в систему координат блока
  xform.invert();
  if ((es = pBtr->upgradeOpen()) != Acad::eOk) return es;
  // Перебрасываем все примитивы в блок
  if ((es = pBtr->assumeOwnershipOf(ids)) != Acad::eOk) return es;
  // Теперь выполним трансформацию всех примитивов по матрице xform
  for (int i=0; i < ids.length(); i++) {
    AcDbObjectPointer<AcDbEntity> pEnt(ids[i],AcDb::kForWrite);
    if (pEnt.openStatus() == Acad::eOk) {
      pEnt->transformBy(xform);
    }
  }
  // Обновим все вставки этого блока
  AcDbObjectIdArray idRefs;
  pBtr->getBlockReferenceIds(idRefs);
  pBtr->close();
  for (int i=0; i < idRefs.length(); i++) {
    AcDbObjectPointer<AcDbEntity> pEnt(idRefs[i],AcDb::kForWrite);
    if (pEnt.openStatus() == Acad::eOk) {
      pEnt->recordGraphicsModified();
    }
  }
  return es;
}
//------------------------------
//    Команда MoveToBlock
//------------------------------
static void MoveToBlock(void)
{
  Acad::ErrorStatus es;
  ads_name en,ss;
  ads_point p;
  if (acedEntSel("\nУкажите блок: ",en,p) != RTNORM) return;
  acutPrintf("\nВыберите примитивы для добавления в блок: ");
  if (acedSSGet(NULL,NULL,NULL,NULL,ss) != RTNORM) return;
  AcDbObjectIdArray ids;
  AcDbObjectId idBlk,id;  acdbGetObjectId(idBlk,en);
  long nEnt = 0; acedSSLength(ss,&nEnt);
  if (!nEnt) return;
  ids.setLogicalLength(nEnt);
  for (int i=0; i < nEnt; i++) {
    acedSSName(ss,i,en);
    acdbGetObjectId(id,en);
    ids[i] = id;
  }
  if ((es = MoveToBlockDefinition(idBlk,ids)) != Acad::eOk) {
    acutPrintf("\nMoveToBlockDefinition(idBlk,ids)=%s",acadErrorStatusText(es));
  }
}

Re: Как решить проблему с обработкой блоков ?

Спасибо за помощь. Буду пробовать.
Я работаю с ShipConstructor, надстройка над автокадом. Там есть специальная команда SCCOONV (3d to 2d), она все объекты кладёт в одну плоскость (проицирует их на неё).
Её надо применять к объектам в блоке, открывать по одному блоку и применять команду долго, особенно если в чертеже много блоков. Вот меня и попросили автоматизировать этот процесс.

Re: Как решить проблему с обработкой блоков ?

У меня опечатка, команда SCCONV

Re: Как решить проблему с обработкой блоков ?

Большое спасибо.
Теперь у меня всё получилось благодаря функции MoveToBlockDefinition(), самому написать такую функцию знаний бы мне не хватило.

Re: Как решить проблему с обработкой блоков ?

> Lord
Ну и хорошо! Следующий шаг - переписать SCCONV. :)

Re: Как решить проблему с обработкой блоков ?

А в чем такая необходимость разбивать блок? Примитивы лежат в своем TableRecord-у и их можно без проблем модифицировать.

Re: Как решить проблему с обработкой блоков ?

> Exhumer
Не внимательно прочитал вопрос - Lord'у нужно на вход команде (которую писал не он) подать набор примитивов.

Re: Как решить проблему с обработкой блоков ?

Не внимательно прочитал вопрос — Lord'у нужно на вход команде (которую писал не он) подать набор примитивов.

Да, из вопроса это было не совсем ясно.