Тема: Непонятная проблема при работе с референсами блоков

Возникла совсем непонятная проблема:
Мною создан блок "Тройник" у него есть атрибуты.
Всё вроде работало нормально, но на некотором этапе изменения чертежа.
Программа работающая через ObjectARX перестала этот блок видеть, хотя он на чертеже есть, зато стала видеть непонятные блоки типа "*DXX", где ХХ-набор какой-то номер.
Путем различных манипуляций выяснилось, что когда я этот блок копирую на чертеж, одновременно с ним создается блок "*DXX" и все вхождения моего блока записываются, как вхождения этого блока, а у моего вхождений (reference) нет. При этом, что самое смешное, AutoCad все видит нормально. Кто-нить может объяснить, что это за непонятные блоки?

(изменено: Александр Ривилис, 25 февраля 2009г. 01:19:56)

Re: Непонятная проблема при работе с референсами блоков

Блок динамический?

Re: Непонятная проблема при работе с референсами блоков

Обычный стандартный блок с атрибуами, но когда вставляешь его через меню block, то на картинке рядом с ним рисуется молния. Это означает динамический? Я создавал стандартный блок, но потом несколько раз его правил. Возможно, во время одной из правок он стал динамическим. Как не знаю. Знаний по мат.части не хватает.
Меня больше интересует, как через внутреннюю базу автокада распознать, что это один и тот же блок.
Если есть какие-нить ссылки по различию между динамическими блоками и статическими буду премного благодарен, т.к. знания по мат.части надо расширять.

(изменено: Александр Ривилис, 25 февраля 2009г. 13:37:40)

Re: Непонятная проблема при работе с референсами блоков

Владимир пишет:

Обычный стандартный блок с атрибуами, но когда вставляешь его через меню block, то на картинке рядом с ним рисуется молния. Это означает динамический?

Да.

Владимир пишет:

Я создавал стандартный блок, но потом несколько раз его правил. Возможно, во время одной из правок он стал динамическим. Как не знаю. Знаний по мат.части не хватает.

Если он случайно стал динамическим, то лучше его переделать.
Ну а если нужно получить имя блока в независимости от того статический он или динамический:

static void DynTest(void)
{
  ads_name en; ads_point p;
  if (acedEntSel(_T("\nУкажите блок: "),en,p) == RTNORM) {
    AcDbObjectId eId; acdbGetObjectId(eId,en);
    AcDbObjectPointer<AcDbBlockReference> pBlkRef(eId,AcDb::kForRead);
    if (pBlkRef.openStatus() == Acad::eOk) {
      AcDbObjectId idBlkTblRec = pBlkRef->blockTableRecord();
      AcDbDynBlockReference dynBlk(eId);
      if (dynBlk.isDynamicBlock()) {
        AcDbBlockTableRecordPointer pBTR(dynBlk.dynamicBlockTableRecord(),AcDb::kForRead);
        if (pBTR.openStatus() == Acad::eOk){
          const ACHAR *blkName = NULL; pBTR->getName(blkName);
          acutPrintf(_T("\nДинамический блок с именем: \"%s\""), blkName);
        }
      } else {
        AcDbBlockTableRecordPointer pBTR(pBlkRef->blockTableRecord(),AcDb::kForRead);
        const ACHAR *blkName = NULL; pBTR->getName(blkName);
        acutPrintf(_T("\nСтатический блок с именем: \"%s\""), blkName);
      }
    }
  }
}

(изменено: Владимир, 25 февраля 2009г. 14:43:53)

Re: Непонятная проблема при работе с референсами блоков

У меня скорее немного другая проблема.
Обработка чертежа происходит полностью автоматически.
Так что я тыкнуть в блок сразу не могу.
Я обращаюсь к BlockTableRecord считываю из него все блоки:

    //Внесение списка блоков в память
    ACHAR *BlockName;
    unsigned short BlockID;
    CAcadBlock *newBlock;
    for(;!pBlockTableIterator->done();pBlockTableIterator->step())
    {
        pBlockTableIterator->getRecord(pBlockTableRecord,AcDb::kForRead);

        pBlockTableRecord->getName(BlockName);
        {
            BlockID=static_cast<unsigned short>(listBlocks.size())+1;
            newBlock=new CAcadBlock(BlockID, BlockID, Acad2Prog(BlockName));
            listBlocks.push_back(newBlock);
            //sprintf(tempMsg, "Обрабатывем блок %s с ID=%d", newBlock->BlockName, newBlock->ID);
            //DocVars.docData().ToolsPKG.addCommonLogMsg(10, tempMsg);

            this->ReadingBlockReference(listBlockRef, pBlockTableRecord, BlockID);
        }
        acutDelString(BlockName);

        pBlockTableRecord->close();
    }

Вот как-раз при получении списка блоков и объявились блоки начинающиеся на *.
Пока не до конца понял как сопоставить настоящее имя динамического блоки и нескольких блоков начинающихся на *. Из-за того что как раз эти блоки и имеют reference, а родителький динамический блок не имеет

(изменено: Александр Ривилис, 25 февраля 2009г. 14:48:43)

Re: Непонятная проблема при работе с референсами блоков

Вместо того чтобы приводить свой код сформулируй вопрос. Что у тебя есть и что тебе нужно получить? Например: есть имя анонимного блока (начинающегося на *), нужно получить имя "родительского" динамического блока. Да и версии AutoCAD и ObjectARX нужны - там есть особенности.

(изменено: Владимир, 25 февраля 2009г. 14:59:46)

Re: Непонятная проблема при работе с референсами блоков

Да, надо именно это.
Теперь понял как эти блоки называются.
Если точнее есть Record из BlockTableRecord указывающий на анонимный блок. Надо определить к какому динамическому блоку он относится. А дальше уже в программе я сам сопоставлю анонимные блоки к динамическому.
И ещё хотел узнать где возможно более подробно почитать про динамические блоки (как они связаны с анонимными и т.д.)

(изменено: Александр Ривилис, 25 февраля 2009г. 15:01:40)

Re: Непонятная проблема при работе с референсами блоков

Версия AutoCAD и ObjectARX?

Владимир пишет:

И ещё хотел узнать где возможно более подробно почитать про динамические блоки (как они связаны с анонимными и т.д.)

Нигде. Только отрывочно в ObjectARX Docs.

Re: Непонятная проблема при работе с референсами блоков

2008, но программа написан так, что будет работать и в 2006.

Re: Непонятная проблема при работе с референсами блоков

Вот в том-то и проблема, что документации кот наплакал. По докам и разбирался. Что-то по вашим материалам разбирал, ещё с форума на autocad.
Из-за чего и привел в начале весь код, что может покритикуете исходя из собственного опыта.
Например заметил, что бы больше используете ссылки на не напрямую работу с объектами. С чем это связано?

Re: Непонятная проблема при работе с референсами блоков

Владимир пишет:

Из-за чего и привел в начале весь код, что может покритикуете исходя из собственного опыта.

Критиковать не буду, т.к. разбираться нет времени.
Лучше поразбирайся с таким кодом:

static void GetDynName(void)
{
  ACHAR blkName[512]=_T("");
  if (acedGetString(TRUE,_T("\nУкажите имя блока для получения имени динамического блока: "),blkName) == RTNORM) {
    AcDbBlockTableRecordPointer pBTR(blkName,acdbCurDwg(),AcDb::kForRead);
    if (pBTR.openStatus() == Acad::eOk) {
      const ACHAR *dynBlkName = NULL;
      resbuf *rb = pBTR->xData(_T("AcDbBlockRepBTag")), *rbb =  rb;
      if (rbb) {
        while (rb && rb->restype != 1005) rb = rb->rbnext;
        if (rb) {
          AcDbHandle h(rb->resval.rstring); 
          AcDbObjectId idDynBlk; 
          if (acdbCurDwg()->getAcDbObjectId(idDynBlk,false,h) == Acad::eOk) {
            AcDbBlockTableRecordPointer pDynBTR(idDynBlk,AcDb::kForRead);
            if (pDynBTR.openStatus() == Acad::eOk) {
              pDynBTR->getName(dynBlkName);            
            }
          }
        }
        acutRelRb(rbb);
      } else {
        pBTR->getName(dynBlkName);
      }
      acutPrintf(_T("\nИмя динамического блока: \"%s\""), dynBlkName);  
    }
  }
}

Вроде бы он делает именно то, что тебе нужно, т.е. по имени блока находит "оригинальное" имя блока.

Re: Непонятная проблема при работе с референсами блоков

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

(изменено: Александр Ривилис, 25 февраля 2009г. 17:57:06)

Re: Непонятная проблема при работе с референсами блоков

Если ты имеешь в виду getBlockReferenceIds, то эта функция тебе не поможет. Только начиная с AutoCAD 2009 есть класс AcDbDynBlockTableRecord и у него метод AcDbDynBlockTableRecord::getAnonymousBlockIds()

Re: Непонятная проблема при работе с референсами блоков

Значит придется переходить на AutoCad 2009 :(
А так проблема такова я знаю, что блок динамический, но у него нет ни одного Reference-а (Если просто запросить AcDbBlockTableRecord::getBlockReferenceIds, то массив оказывается пуст.)
Но при этом у AcDbDynBlockReference есть anonymousBlockTableRecord, но основная проблема выходит когда мне надо получить из AcDbBlockTableRecord, которая указывает на динамический блок, AcDbDynBlockReference этого блока. Возможно ли как-то это сделать?
Если нет, то как раз и окажется, что надо переходить на AutoCad 2009.

(изменено: Александр Ривилис, 25 февраля 2009г. 21:06:16)

Re: Непонятная проблема при работе с референсами блоков

Владимир пишет:

...но основная проблема выходит когда мне надо получить из AcDbBlockTableRecord, которая указывает на динамический блок, AcDbDynBlockReference этого блока. Возможно ли как-то это сделать?

Возможно и не очень сложно. Фактически здесь есть все, что для этого нужно. Если сам не догадаешься - завтра выложу код. Но вот зачем тебе именно AcDbDynBlockReference я не пойму. Снова ты запутываешь задачу. Я думаю что тебе будет достаточно по AcDbBlockTableRecord динамического блока найти все его AcDbBlockReference'ы, т.е. сделать замену для getBlockReferenceIds так, чтобы она находила ВСЕ его AcDbBlockReference.

Re: Непонятная проблема при работе с референсами блоков

Вот аналог getBlockReferenceIds для динамического блока:

static void DynBlockTestGetDynBlkRefs(void)
{
  ACHAR blkName[512]=_T("");
  if (acedGetString(TRUE,_T("\nУкажите имя динамического блока: "),blkName) == RTNORM) {
    AcDbObjectIdArray ids;
    getDynamicBlockReferenceIds(blkName, ids);
    acutPrintf(_T("\nВсего блоков с именем \"%s\" %d штук"), blkName, ids.length());  
  }
}
static AcDbObjectId getTableRecordId(ACHAR *blockName)
{
  AcDbBlockTableRecordPointer pBTR(blockName,acdbCurDwg(),AcDb::kForRead);
  if (pBTR.openStatus() == Acad::eOk) return pBTR->objectId();
  else return AcDbObjectId::kNull;
}
static Acad::ErrorStatus getDynamicBlockReferenceIds(AcDbObjectId eId, AcDbObjectIdArray &ids)
{
  Acad::ErrorStatus es = Acad::eOk;
  AcDbBlockTableRecordPointer pMainBTR(eId,AcDb::kForRead);
  if ((es = pMainBTR.openStatus()) != Acad::eOk) return es;
  // Получаем все вхождения немодифицированного блока
  pMainBTR->getBlockReferenceIds(ids); 
  // Получаем метку (handle) оригинального BTR 
  AcDbHandle hMainBTR;  pMainBTR->getAcDbHandle(hMainBTR);
  // Теперь найдем все анонимные блоки, которые ссылаются на немодифицированный блок
  AcDbBlockTablePointer pBT(acdbCurDwg(),AcDb::kForRead);
  if ((es = pBT.openStatus()) != Acad::eOk) return es;
  AcDbBlockTableIterator *pIter = NULL;
  if ((es = pBT->newIterator(pIter)) != Acad::eOk) return es;
  // Проходимся итератором по всем блокам
  for (pIter->start(); !pIter->done(); pIter->step()) {
    AcDbObjectId idBTR;   
    if ((es = pIter->getRecordId(idBTR)) != Acad::eOk) { delete pIter; return es; }
    AcDbBlockTableRecordPointer pAnonimus(idBTR,AcDb::kForRead);
    if ((es = pAnonimus.openStatus()) != Acad::eOk)  { delete pIter; return es; }
    // Пропускаем неанонимные блоки
    if (!pAnonimus->isAnonymous()) continue;
    resbuf *rb = pAnonimus->xData(_T("AcDbBlockRepBTag")), *rbb =  rb;
    if (rb == NULL) continue; // Пропускаем нединамические блоки
    while (rb && rb->restype != 1005) rb = rb->rbnext;
    if (!rb) continue; 
    AcDbHandle hAnonimus(rb->resval.rstring); acutRelRb(rbb);
    if (hAnonimus == hMainBTR) {
      // Это анонимный блок, полученный из нашего динамического блока
      if ((es = pAnonimus->getBlockReferenceIds(ids)) != Acad::eOk) { delete pIter; return es; }
    }
  }
  delete pIter;
  return Acad::eOk;
}
static Acad::ErrorStatus getDynamicBlockReferenceIds(ACHAR *blockName, AcDbObjectIdArray &ids)
{
  AcDbObjectId idBTR = getTableRecordId(blockName);
  if (!idBTR.isNull()) return getDynamicBlockReferenceIds(idBTR,ids);
  else return Acad::eInvalidInput;
}