Создание блока из элементов чертежа

Автор Тема: Создание блока из элементов чертежа  (Прочитано 4002 раз)

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

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

  • ADN OPEN
  • Сообщений: 40
  • Карма: 1
Добрый  день!
Не нашел пример как создать блок из уже существующих элементов чертежа.
Здесь в примере создается блок http://adn-cis.org/forum/index.php?topic=2643.msg8940#msg8940
и записывается в базу данных чертежа, а если элементы уже там находятся ?
pBlockRecord->appendAcDbEntity не подходит.
Спасибо заранее

Отмечено как Решение alsh 20-11-2018, 08:56:10

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Не нашел пример как создать блок из уже существующих элементов чертежа.
Есть как минимум три варианта, как можно добавить существующие примитивы в новый блок:
1. Использовать метод AcDbBlockTableRecord::assumeOwnershipOf, передав ему массив AcDbObjectId примитивов, которые должны войти в блок. Но это будет не копирование, а перемещение из пространства модели/листа в блок.
2. Использовать метод  AcDbDatabase::deepCloneObjects,  передав ему массив AcDbObjectId примитивов, которые должны войти в блок. и указав в качестве AcDbObjectId блок, в который примитивы должны быть скопированы.
3. Можно для каждого из примитивов выполнить метод clone() и получить копии, и уже эти копии поместить в блок при помощи pBlockRecord->appendAcDbEntity
В этом варианте возможны проблемы с составными примитивами.
Если очень нужно, то какой-нибудь из примеров я могу сделать, но мне кажется я достаточно подробно описал.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Сделал пример с минимальным количество проверок на ошибки. Просто, чтобы было понятно как это можно сделать:

Код - C++ [Выбрать]
  1. //-----------------------------------------------------------------------------
  2. //----- acrxEntryPoint.cpp
  3. //-----------------------------------------------------------------------------
  4. #include "StdAfx.h"
  5. #include "resource.h"
  6.  
  7. //-----------------------------------------------------------------------------
  8. #define szRDS _RXST("")
  9.  
  10. void ads_regen();
  11.  
  12. //-----------------------------------------------------------------------------
  13. //----- ObjectARX EntryPoint
  14. class CCreateBlockApp : public AcRxArxApp {
  15.  
  16. public:
  17.   CCreateBlockApp() : AcRxArxApp() {}
  18.  
  19.   virtual AcRx::AppRetCode On_kInitAppMsg(void *pkt) {
  20.     AcRx::AppRetCode retCode = AcRxArxApp::On_kInitAppMsg(pkt);
  21.     return (retCode);
  22.   }
  23.  
  24.   virtual AcRx::AppRetCode On_kUnloadAppMsg(void *pkt) {
  25.     AcRx::AppRetCode retCode = AcRxArxApp::On_kUnloadAppMsg(pkt);
  26.     return (retCode);
  27.   }
  28.  
  29.   virtual void RegisterServerComponents() {     }
  30.  
  31.   //////////////////////////////////////////////////////////////////////////
  32.   //  Вариант с  AcDbBlockTableRecord::assumeOwnershipOf
  33.   //////////////////////////////////////////////////////////////////////////
  34.   static void RivilisCreateBlk1()
  35.   {
  36.     AcDbObjectIdArray ids;
  37.     AcString blockName = GetBlockName();
  38.     if (blockName.isEmpty())
  39.       return;
  40.     if (SelectObjects(ids) == 0)
  41.       return;
  42.     AcDbObjectId idBtr = GetOrCreateBlockDef(blockName);
  43.     if (idBtr.isNull())
  44.       return;
  45.     {
  46.       AcDbBlockTableRecordPointer pBtr(idBtr, AcDb::kForWrite);
  47.       pBtr->assumeOwnershipOf(ids); // <- Меняем владельца примитивов
  48.     }
  49.     InsertBlockRef(idBtr);
  50.     ads_regen();
  51.   }
  52.  
  53.   //////////////////////////////////////////////////////////////////////////
  54.   //  Вариант с  AcDbDatabase::deepCloneObjects
  55.   //////////////////////////////////////////////////////////////////////////
  56.   static void RivilisCreateBlk2()
  57.   {
  58.     AcDbObjectIdArray ids;
  59.     AcString blockName = GetBlockName();
  60.     if (blockName.isEmpty())
  61.       return;
  62.     if (SelectObjects(ids) == 0)
  63.       return;
  64.     AcDbObjectId idBtr = GetOrCreateBlockDef(blockName);
  65.     if (idBtr.isNull())
  66.       return;
  67.     AcDbIdMapping mapping;
  68.     // Клонируем выбранные примитивы в блок
  69.     acdbCurDwg()->deepCloneObjects(ids, idBtr, mapping);
  70.     InsertBlockRef(idBtr);
  71.     ads_regen();
  72.   }
  73.  
  74.   //////////////////////////////////////////////////////////////////////////
  75.   //            Вариант с  AcDbEntity::clone()
  76.   //////////////////////////////////////////////////////////////////////////
  77.   static void RivilisCreateBlk3()
  78.   {
  79.     AcDbObjectIdArray ids;
  80.     AcString blockName = GetBlockName();
  81.     if (blockName.isEmpty())
  82.       return;
  83.     if (SelectObjects(ids) == 0)
  84.       return;
  85.     AcDbObjectId idBtr = GetOrCreateBlockDef(blockName);
  86.     if (idBtr.isNull())
  87.       return;
  88.     {
  89.       AcDbBlockTableRecordPointer pBtr(idBtr, AcDb::kForWrite);
  90.       if (pBtr.openStatus() == Acad::eOk)
  91.       {
  92.         for (int i = 0; i < ids.length(); i++)
  93.         {
  94.           AcDbEntityPointer pEnt(ids[i], AcDb::kForRead);
  95.           if (pEnt.openStatus() != Acad::eOk)
  96.             continue;
  97.           // Создаём клоны выбранных примитивов и добавляем их в блок
  98.           AcDbEntity *pClone = AcDbEntity::cast(pEnt->clone());
  99.           if (pClone)
  100.           {
  101.             pBtr->appendAcDbEntity(pClone);
  102.             pClone->close();
  103.           }
  104.         }
  105.       }
  106.     }
  107.     InsertBlockRef(idBtr);
  108.     ads_regen();
  109.   }
  110.   //////////////////////////////////////////////////////////////////////////
  111.   // Функция возвращает количество выбранных примитивов и заполняет
  112.   // ими массив AcDbObjectId
  113.   //////////////////////////////////////////////////////////////////////////
  114.   static Adesk::Int32 SelectObjects(AcDbObjectIdArray &ids)
  115.   {
  116.     Adesk::Int32 len = 0;
  117.     ads_name ss;
  118.     if (acedSSGet(NULL, NULL, NULL, NULL, ss) == RTNORM)
  119.     {
  120.       acedSSLength(ss, &len);
  121.       if (len > 0)
  122.       {
  123.         ids.setLogicalLength(len);
  124.         for (Adesk::Int32 i = 0; i < len; i++)
  125.         {
  126.           ads_name en; acedSSName(ss, i, en);
  127.           AcDbObjectId id; acdbGetObjectId(id, en);
  128.           ids[i] = id;
  129.         }
  130.       }
  131.     }
  132.     return len;
  133.   }
  134.   //////////////////////////////////////////////////////////////////////////
  135.   // Функция возвращает AcDbObjectId определения блока, заданного именем
  136.   // Если блока с таким именем еще не было, то функция его создаёт
  137.   //////////////////////////////////////////////////////////////////////////
  138.   static AcDbObjectId GetOrCreateBlockDef(AcString name)
  139.   {
  140.     AcDbBlockTablePointer pTbl(acdbCurDwg(), AcDb::kForRead);
  141.     if (pTbl.openStatus() != Acad::eOk)
  142.       return AcDbObjectId::kNull;
  143.     AcDbObjectId idBtr;
  144.     if (pTbl->getAt(name, idBtr) == Acad::eOk)
  145.       return idBtr;
  146.     if (pTbl->upgradeOpen() == Acad::eOk)
  147.     {
  148.       AcDbBlockTableRecordPointer pBtr; pBtr.create();
  149.       pBtr->setName(name);
  150.       pBtr->setExplodable(true);
  151.       pBtr->setOrigin(AcGePoint3d::kOrigin);
  152.       pTbl->add(idBtr, pBtr);
  153.     }
  154.     return idBtr;
  155.   }
  156.  
  157.   //////////////////////////////////////////////////////////////////////////
  158.   // Функция создаёт вставку блока по заданному AcDbObjectId
  159.   // определения блока, запрашивая у пользователя точку вставки
  160.   //////////////////////////////////////////////////////////////////////////
  161.   static void InsertBlockRef(AcDbObjectId idBtr)
  162.   {
  163.     ads_point p;
  164.     if (acedGetPoint(NULL, ACRX_T("\nУкажите точку вставки блока: "), p) == RTNORM)
  165.     {
  166.       AcDbBlockTableRecordPointer pSpace(acdbCurDwg()->currentSpaceId(), AcDb::kForWrite);
  167.       if (pSpace.openStatus() != Acad::eOk)
  168.         return;
  169.       AcDbBlockReference *pRef = new AcDbBlockReference(asPnt3d(p), idBtr);
  170.       pRef->setDatabaseDefaults(acdbCurDwg());
  171.       pSpace->appendAcDbEntity(pRef);
  172.       pRef->close();
  173.     }
  174.   }
  175.   //////////////////////////////////////////////////////////////////////////
  176.   // Запрашиваем у пользователя имя блока и возвращаем только допустимое
  177.   // имя или пустую строку
  178.   //////////////////////////////////////////////////////////////////////////
  179.   static AcString GetBlockName()
  180.   {
  181.     AcString blockName;
  182.     acedGetString(TRUE, ACRX_T("\nУкажите имя блока: "), blockName);
  183.     if (acdbSNValid(blockName, FALSE) != RTNORM)
  184.     {
  185.       acutPrintf(ACRX_T("\nБлока с таким именем быть не может"));
  186.       blockName = ACRX_T("");
  187.     }
  188.     return blockName;
  189.   }
  190.  
  191.  
  192. };
  193.  
  194. //-----------------------------------------------------------------------------
  195. IMPLEMENT_ARX_ENTRYPOINT(CCreateBlockApp)
  196.  
  197. ACED_ARXCOMMAND_ENTRY_AUTO(CCreateBlockApp, Rivilis, CreateBlk1, CreateBlk1, ACRX_CMD_MODAL, NULL)
  198. ACED_ARXCOMMAND_ENTRY_AUTO(CCreateBlockApp, Rivilis, CreateBlk2, CreateBlk2, ACRX_CMD_MODAL, NULL)
  199. ACED_ARXCOMMAND_ENTRY_AUTO(CCreateBlockApp, Rivilis, CreateBlk3, CreateBlk3, ACRX_CMD_MODAL, NULL)
  200.  
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN OPEN
  • Сообщений: 40
  • Карма: 1
Большое спасибо Александр! Вы на высоте как всегда.

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

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

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

  • ADN OPEN
  • Сообщений: 40
  • Карма: 1
 Проверил первые два. Подходит больше первый, потому что во втором элементы остаются в чертеже, т.е.
копируются, а думал что будет как в Автокаде, когда происходит перемещение их в блок. Ну а в первом все равно надо вставлять
блок в чертеж. Спасибо! :)