Получение и вставка блока из отдельного dwg-файла в текущий dwg файл

Автор Тема: Получение и вставка блока из отдельного dwg-файла в текущий dwg файл  (Прочитано 10050 раз)

0 Пользователей и 2 Гостей просматривают эту тему.

Оффлайн AlexZhurАвтор темы

  • ADN OPEN
  • Сообщений: 42
  • Карма: 0
Добрый вечер. Подскажите плиз порядок действий (какие функции использовать) для реализации следующей задачи:
  есть отдельный dwg-файл и в нем определены разные блоки. Мне необходимо неявно открыть его, найти в нем нужный блок и вставить в текущий dwg файл.
« Последнее редактирование: 24-03-2017, 10:01:07 от AlexZ »

Оффлайн Николай Горлов

  • ADN
  • *
  • Сообщений: 238
  • Карма: 34
ну, если интересует порядок действий :), то:

1. убедиться, что в текущем чертеже нет блока с требуемым именем.

1.1. если всё же такой блок есть - развилка:
  a) вставка из текущего чертежа и выход из команды
  б) удаление блока и всех его вставок в текущем чертеже (ооочень не желательно и сильно геморно, т.к. скорей всего нужно еще запомнить все координаты вставок, повороты и т.п. удаляемых блоков для замены их на новый). в принципе можно просто перезаписать блок в BlockTableRecord и надеяться на чудо, что всё автоматом поменяется, НО, суровая действительность говорит, что не всё так радужно, если блок динамический и в некоторых вставках эту динамику использовали.

2. убедиться что файл с блоками существует

3. убедиться, что в этом файле есть требуемый блок

4. утянуть блок из внешнего файла в БД своего чертежа

5. а теперь можно выполнить пункт 1.1.а, т.к. блок уже есть в нашем текущем чертеже

P.S.:по поводу функций, которые пригодятся. по сути, она одна - wblockCloneObjects

Оффлайн AlexZhurАвтор темы

  • ADN OPEN
  • Сообщений: 42
  • Карма: 0
Спасибо. Может есть примеры кода под эту задачу? Или ссылки полезные?

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
AlexZ,
Как вариант: http://adndevblog.typepad.com/autocad/2013/01/how-to-mimic-the-autocad-insert-command-in-arx-without-acedcommand-call.html
Но это в случае если в качестве блока - пространство модели стороннего dwg-файла. В противном случае, как написал Николай Горлов, нужно использовать  wblockCloneObjects.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
А это пример на .NET: http://adndevblog.typepad.com/autocad/2012/05/insert-block-from-a-different-dwg-using-net-.html
Он пригодится для понимания того, как нужно подготовить данные для WblockCloneObjects
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Николай Горлов

  • ADN
  • *
  • Сообщений: 238
  • Карма: 34
с ссылками помочь не могу, лениво искать. а вот функциями поделюсь :)

эта штука выбирает имена всех блоков из внешнего НЕ ОТКРЫТОГО файла:
Код - C++ [Выбрать]
  1. // pFileName - полное имя файла с набором блоков
  2. // blockNames - выходной массив с именами блоков файла pFileName
  3. void getBlockNamesFromFile(const ACHAR *pFileName, AcArray<CString> &blockNames)
  4. {
  5.         blockNames.removeAll();
  6.         Acad::ErrorStatus es=Acad::eOk;
  7.         AcDbDatabase* pBlockDatabase=new AcDbDatabase(false,true);
  8.         AcAxDocLock docLock(pBlockDatabase);
  9.         es= pBlockDatabase->readDwgFile(pFileName);
  10.         if(es!=Acad::eOk){delete pBlockDatabase;return;}
  11.  
  12.         AcDbBlockTable* pBlockTable;
  13.         es=pBlockDatabase->getSymbolTable(pBlockTable,AcDb::kForRead);
  14.         if(es!=Acad::eOk){delete pBlockDatabase;return;}
  15.  
  16.         AcDbBlockTableIterator *pBlockTableIterator=NULL;
  17.         if (pBlockTable->newIterator(pBlockTableIterator) == Acad::eOk)
  18.         {
  19.                 while (!pBlockTableIterator->done())
  20.                 {
  21.                         AcDbBlockTableRecord *pBlockTableRecord=NULL;
  22.                         if (pBlockTableIterator->getRecord(pBlockTableRecord, AcDb::kForRead)  == Acad::eOk)
  23.                         {
  24.                                 ACHAR *BlockName;
  25.                                 pBlockTableRecord->getName(BlockName); 
  26.                                 // есть блоки, которые начинаются с символа *, например, model_space, paper_space, и др. ерунда,
  27.                                 // которую акад сам определяет как блок (например, таблица)
  28.                                 // также есть мусор в файле , который тоже является блоком. начинается этот мусор с A$. нам это тоже не нада.
  29.                                 if (BlockName[0] != _T('*') && BlockName[1] != _T('$'))
  30.                                         blockNames.apend(BlockName);
  31.                                 acutDelString(BlockName);
  32.                                 pBlockTableRecord->close();
  33.                         }
  34.                         pBlockTableIterator->step();
  35.                 }
  36.         }
  37.         delete pBlockTableIterator;
  38.         pBlockTable->close();
  39.         delete pBlockDatabase;
  40. }
  41.  

а это модернизированный вариант утягивания блока из внешнего, опять таки НЕ ОТКРЫТОГО в автокаде файла в свой
Код - C++ [Выбрать]
  1. // pFileName - полное имя файла, где лежит требуемый блок
  2. // pBlockName - имя блока в файле pFileName
  3. // на возврат ID блока (не путать с ID вставки. это - ID AcDbBlockTableRecord-а)
  4. AcDbObjectId importBlockToCurDWGDatabase(const ACHAR *pBlockName, const ACHAR *pFileName)
  5. {
  6.         Acad::ErrorStatus es=Acad::eOk;
  7.         AcDbObjectId idImported  = AcDbObjectId::kNull; // ID нашего нового блока
  8.         AcDbDatabase* pWorkDatabase = acdbHostApplicationServices()->workingDatabase();
  9.         AcAxDocLock docLock(pWorkDatabase);
  10.         AcDbDatabase* pBlockDatabase = new AcDbDatabase(false,true);
  11.         es = pBlockDatabase->readDwgFile(pFileName);
  12.         if(es!=Acad::eOk){delete pBlockDatabase;return NULL;}
  13.        
  14.         try
  15.         {
  16.                 AcDbBlockTable* pBlockTable, *pBlockTable2;
  17.                 es=pBlockDatabase->getSymbolTable(pBlockTable,AcDb::kForRead);
  18.                 if(es!=Acad::eOk){delete pBlockDatabase;return NULL;} // нет символьной таблицы (блоков вооообще)
  19.          
  20.                 AcDbObjectId idInsRecord;      
  21.                 es=pBlockTable->getAt(pBlockName,idInsRecord);
  22.  
  23.                 AcDbObjectIdArray objIds2Copy;
  24.                 objIds2Copy.append(idInsRecord);
  25.                 if(es!=Acad::eOk){pBlockTable->close();delete pBlockDatabase;return NULL;}
  26.                 AcDbIdMapping idMap;
  27.                 es = pBlockDatabase->wblockCloneObjects(objIds2Copy,acdbSymUtil()->blockModelSpaceId(pWorkDatabase),idMap, AcDb::kDrcReplace);
  28.                 if(es == Acad::eOk)
  29.                 {
  30.                         pWorkDatabase->getSymbolTable(pBlockTable2, AcDb::kForRead);
  31.                         pBlockTable2->getAt(pBlockName,idImported,AcDb::kForRead);
  32.  
  33.                         AcDbBlockTableRecord *pSrcBlock = NULL;
  34.                         pBlockTable->getAt(pBlockName,pSrcBlock,AcDb::kForRead);
  35.                         AcDbSortentsTable *pSortTab1 = NULL;
  36.                         pSrcBlock->getSortentsTable(pSortTab1,AcDb::kForRead,true);
  37.                         AcDbObjectIdArray oids;
  38.                         pSortTab1->getFullDrawOrder(oids);
  39.                         pSortTab1->close();
  40.                         pSrcBlock->close();
  41.  
  42.                         AcDbBlockTableRecord *pTargetBlock = NULL;
  43.                         pBlockTable2->getAt(pBlockName,pTargetBlock,AcDb::kForRead);
  44.                         AcDbSortentsTable *pSortTab2 = NULL;
  45.                         pTargetBlock->getSortentsTable(pSortTab2,AcDb::kForWrite,true);
  46.  
  47.                         AcDbObjectIdArray targetIds;
  48.  
  49.                         int len = oids.length();
  50.                         for(int cnt = 0; cnt < len; cnt++)
  51.                         {
  52.                                 AcDbIdPair idPair(oids.at(cnt),AcDbObjectId::kNull,true);
  53.                                 if (idMap.compute (idPair))
  54.                                         targetIds.append(idPair.value());
  55.                         }
  56.                         pSortTab2->setRelativeDrawOrder(targetIds);
  57.                         pSortTab2->close();
  58.                         pTargetBlock->close();
  59.  
  60.                         pBlockTable2->close();
  61.                         pBlockTable->close();
  62.                 }
  63.         }catch(...){delete pBlockDatabase;return NULL;}
  64.  
  65.         delete pBlockDatabase;
  66.         return idImported;
  67. }
  68.  

ну а так можно сделать вставку блока в чертеж по заданным в ПСК координатам. поддерживается обработка атрибутов, если они есть
Код - C++ [Выбрать]
  1. // blockId - ObjectId блока для вставки (получить можно, например, в результате работы функции importBlockToCurDWGDatabase)
  2. // basePointUCS - точка вставки блока в пользовательской системе координат
  3. // scale - масштаб для текущей вставки
  4. // на возврат ID вставки блока из БД чертежа
  5. AcDbObjectId addBlockToCurDWG (AcDbObjectId blockId, AcGePoint3d basePointUCS, double scale)
  6. {
  7.         bool haveToDel = false;
  8.         Acad::ErrorStatus es;
  9.         AcDbObjectId newEntId;  newEntId.setNull();
  10.         AcDbBlockReference *pBlkRef =new AcDbBlockReference(basePointUCS,blockId) ;
  11.         pBlkRef->setRotation(0.0);
  12.         pBlkRef->setNormal(AcGeVector3d (0.0, 0.0, 1.0));
  13.         pBlkRef->setScaleFactors(AcGeScale3d(scale));
  14.         newEntId = postToDb(pBlkRef);
  15.  
  16.         AcDbObjectPointer<AcDbBlockReference> pAddedEnt(newEntId,AcDb::kForWrite);
  17.         if (pAddedEnt.openStatus () != Acad::eOk) return NULL;
  18.         AcDbBlockTableRecord * pBlockDef;
  19.         acdbOpenObject(pBlockDef, blockId, AcDb::kForRead);
  20.         AcDbBlockTableRecordIterator * pIterator;
  21.         pBlockDef->newIterator(pIterator);
  22.         AcDbEntity * pEnt;
  23.         AcDbAttributeDefinition * pAttdef;
  24.         for ( pIterator->start(); !pIterator->done(); pIterator->step() )
  25.         {
  26.                 pIterator->getEntity(pEnt, AcDb::kForRead);
  27.                 pAttdef =AcDbAttributeDefinition::cast(pEnt);
  28.                 if ( pAttdef != NULL && !pAttdef->isConstant () )
  29.                 {
  30.                         AcDbAttribute * pAtt = new AcDbAttribute;
  31.                         es = pAtt->setAttributeFromBlock(pAttdef,pBlkRef->blockTransform());
  32.                         ACHAR *pStr = pAttdef->tag();
  33.                         pAtt->setTag(pStr);
  34.                         pAtt->setFieldLength(pAttdef->fieldLength());
  35.                         ACHAR *pPrompt = pAttdef->prompt();
  36.                         CString pDefValue = pAttdef->textStringConst();
  37.                         ACHAR promptStr[255]; _tcsncpy(promptStr,_T("\0"),255);
  38.                         _tcscpy(promptStr,_T("\n"));
  39.                         _tcscat(promptStr,pPrompt);
  40.                         if (!pDefValue.IsEmpty())
  41.                         {
  42.                                 _tcscat(promptStr,_T(" <"));
  43.                                 _tcscat(promptStr,pDefValue.GetString());
  44.                                 _tcscat(promptStr,_T(">"));
  45.                         }
  46.                         _tcscat(promptStr,_T(": "));
  47.  
  48.                         ACHAR txtStr[255];
  49.                         int ret = acedGetString(TRUE,promptStr, txtStr);
  50.                         if (RTNORM == ret)
  51.                         {
  52.                                 if (_tcslen(txtStr) > 0)
  53.                                         pAtt->setTextString(txtStr);
  54.                                 else
  55.                                         pAtt->setTextString(pDefValue.GetString());
  56.                         }
  57.                         else if (RTNONE == ret)
  58.                                 pAtt->setTextString(pDefValue.GetString());
  59.                         else haveToDel = true;
  60.  
  61.                         delete pStr;
  62.                         delete pPrompt;
  63.                         AcDbObjectId attId;
  64.                         pAddedEnt->appendAttribute(attId, pAtt);
  65.                         pAtt->close();
  66.  
  67.                 }    
  68.                 pEnt->close();
  69.         }
  70.         delete pIterator;
  71.         pBlockDef->close();
  72.         AcGeMatrix3d matUcs;
  73.         acedGetCurrentUCS(matUcs);
  74.         pAddedEnt->transformBy(matUcs);
  75.         pAddedEnt->downgradeOpen();
  76.         pAddedEnt->close();
  77.  
  78.         if (haveToDel)
  79.         {
  80.                 deleteEntities(newEntId);
  81.                 newEntId.setNull();
  82.         }
  83.         return newEntId;
  84. }
  85.  

ну и мало ли, вдруг пригодится, функция добавление объекта в БД чертежа
Код - C++ [Выбрать]
  1. // функция добавления объекта в бд чертежа
  2. // pEnt - созданый объект, который нужно добавить в чертеж
  3. // на возврат ID добавленного объекта уже из БД чертежа
  4. AcDbObjectId postToDb(AcDbEntity* pEnt)
  5. {
  6.         AcDbObjectId objID;
  7.         objID.setNull();
  8.         AcDbBlockTableRecordPointer curSpace(curDoc()->database()->currentSpaceId(), AcDb::kForWrite);
  9.         if (curSpace.openStatus() == Acad::eOk)
  10.         {
  11.                 curSpace->appendAcDbEntity(objID, pEnt);
  12.                 pEnt->close();
  13.                 curSpace->close();
  14.  
  15.                 AcDbObjectPointer<AcDbEntity> pAddedEnt(objID,AcDb::kForRead);
  16.                 if (pAddedEnt.openStatus () == Acad::eOk)
  17.                 {
  18.                         pAddedEnt->draw();
  19.                         pAddedEnt->close();
  20.                 }
  21.         }
  22.         return objID;
  23. }
  24.  

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Николай Горлов,
Я тебе сейчас замечаний накидаю, а ты подумай.
1. Функция getBlockNamesFromFile
1) Это не нужно, т.к. блокировать можно и нужно только базу, которая открыта в редакторе AutoCAD и имеет свой документ (AcApDocument):
Код - C++ [Выбрать]
  1. AcAxDocLock docLock(pBlockDatabase);
2) Нужно пропустить все Xref (т.е. AcDbBlockTableRecord::isFromExternalReference() == true)
2. Функция postToDb
1) Не нужны:
Код - C++ [Выбрать]
  1. curSpace->close();
  2. pAddedEnt->close();

И это я только по диагонали посмотрел... ;)
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Николай Горлов

  • ADN
  • *
  • Сообщений: 238
  • Карма: 34
Александр Ривилис, замечания это хорошо :):):)
1.1 ну работает же :)
1.2 эт да, обязательно добавлю, хотя наши пользователи xref-ами не пользуются
2. :) есть у меня такая привычка, закрывать руками то, что должно закрыться само по окончании функции или куска функции. в оправдание могу сказать, что pEnt закрывал специально, т.к. он же переоткрывается для чтения, чтоб прошла перерисовка. а функция downgradeOpen иногда вызывает ошибку (ну и чтоб не мучиться над вопросом а почему так происходит, легче было его переоткрыть). вот принудительно и закрыл.



Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
1.1 ну работает же :)
А оно просто ничего не делает, т.к. не находит для этого AcDbDatabase соответствующего AcApDocument.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн AlexZhurАвтор темы

  • ADN OPEN
  • Сообщений: 42
  • Карма: 0
Ого!Ребята, спасибо огромное. Столько полезной информации предоставили!!!  :)