Некорректное разбиение блока

Автор Тема: Некорректное разбиение блока  (Прочитано 16892 раз)

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

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

  • ADN Club
  • ****
  • Сообщений: 421
  • Карма: 16
    • Advanced software for AutoCAD
  • Skype: Debalance
Попался мне один блок (см. вложение), который не получается корректно разбить программным способом. При этом, используя стандартный инструмент в AutoCAD - проблем не возникает. Для разбиения использовал следующий классический кусок кода:
Код - C++ [Выбрать]
  1. int SSret = acedSSGet(L":$:K", promptSS, &KeywordsString.at(0), NULL, ssname1);
  2. if(SSret == RTNORM)
  3. {
  4.         Adesk::Int32 TmpLength;
  5.         acedSSLength(ssname1, &TmpLength);
  6.         if (TmpLength > 0)
  7.         {
  8.                 AcDbObjectId ObjectId;
  9.                 ads_name ename;
  10.                 for (Adesk::Int32 i = 0; i < TmpLength; i++)
  11.                 {
  12.                         acedSSName(ssname1, i, ename);
  13.                         acdbGetObjectId(ObjectId, ename);
  14.                         AcDbObject *pObj;
  15.                         if (acdbOpenObject(pObj, ObjectId, AcDb::kForRead) == Acad::eOk)
  16.                         {
  17.                                 AcDbVoidPtrArray pSet;
  18.                                 Acad::ErrorStatus es;
  19.                                 AcDbEntity *pEnt = AcDbEntity::cast(pObj);
  20.                                 es = pEnt->explode(pSet);
  21.                                 if (es != Acad::eNotApplicable)
  22.                                 {
  23.                                         if (!pSet.isEmpty())
  24.                                         {
  25.                                                 OutputDebugStringW((boost::wformat(L"\npSet Size: %d, es: %d") % pSet.logicalLength() % es).str().c_str());
  26.                                                 for (int i = 0; i < pSet.logicalLength(); i++)
  27.                                                 {
  28.                                                         AcRxObject *TmpObject = static_cast<AcRxObject*>(pSet.at(i));
  29.                                                         if (TmpObject != NULL)
  30.                                                         {
  31.                                                                 OutputDebugStringW((boost::wformat(L"\nObject: %s") % TmpObject->isA()->name()).str().c_str());
  32.                                                         }
  33.                                                 }
  34.                                                 pSet.setLogicalLength(0);
  35.                                         }
  36.                                 }
  37.                                 pObj->close();
  38.                         }
  39.                 }
  40.         }
  41. }
  42.  
В результате работы кода pEnt->explode(pSet) возвращает eCannotScaleNonUniformly. При этом в набор pSet не попадает ни одна из вставок блоков, которые присутствуют внутри исходного блока.
Как "причесать" код, чтобы работал как стандартный инструмент?

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Некорректное разбиение блока
« Ответ #1 : 23-11-2019, 21:39:29 »
Стандартный метод explode не расчленяет блоки, у которых масштабные коэффициенты по X, Y, и Z отличны:



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

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

  • ADN Club
  • ****
  • Сообщений: 421
  • Карма: 16
    • Advanced software for AutoCAD
  • Skype: Debalance
Re: Некорректное разбиение блока
« Ответ #2 : 23-11-2019, 21:40:27 »
Стандартный метод explode не расчленяет блоки, у которых масштабные коэффициенты по X, Y, и Z отличны.
Откуда эта информация? Практика этого примера показывает, что как раз расчленяет. Игнорируются только вставки блоков. Какое в итоге возможно решение?
« Последнее редактирование: 23-11-2019, 22:16:07 от Debalance »

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Некорректное разбиение блока
« Ответ #3 : 23-11-2019, 22:43:59 »
Стандартный метод explode не расчленяет блоки, у которых масштабные коэффициенты по X, Y, и Z отличны.
Откуда эта информация? Практика этого примера показывает, что как раз расчленяет. Игнорируются только вставки блоков. Какое в итоге возможно решение?
Попробуй:
Код - C++ [Выбрать]
  1. static void MyGroupExpl() {
  2.   Acad::ErrorStatus es;
  3.   ads_name en; ads_point p;
  4.   if (acedEntSel(L"\nВыберите вставку блока", en, p) == RTNORM)
  5.   {
  6.  
  7.     AcDbObjectId eid; acdbGetObjectId(eid, en);
  8.     AcDbObjectPointer<AcDbBlockReference> pBref(eid, AcDb::kForRead);
  9.     es = pBref->explodeToOwnerSpace();
  10.     if (es == Acad::eOk)
  11.     {
  12.       if (pBref->upgradeOpen() == Acad::eOk)
  13.         pBref->erase();
  14.  
  15.     } else {
  16.       acutPrintf(L"\npBref->explodeToOwnerSpace()=%s", acadErrorStatusText(es));
  17.     }
  18.   }
  19. }
Работает с NUS-блоками, которые не содержат 3D-тела.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • ****
  • Сообщений: 421
  • Карма: 16
    • Advanced software for AutoCAD
  • Skype: Debalance
Re: Некорректное разбиение блока
« Ответ #4 : 24-11-2019, 12:21:37 »
es = pBref->explodeToOwnerSpace();
Я так понимаю, что этот метод добавляет объекты в базу. А мне бы этого не хотелось, т.к. полученные примитивы используются для временных вычислений, при этом сам взорванный блок должен сохраниться. Такое решение возможно?

Кстати в описании к методу написано:
Цитировать
The AcDbBlockReference must be in a database and must be uniformly scaled.
Подходит ли это для нашего случая?

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

  • ADN Club
  • ****
  • Сообщений: 421
  • Карма: 16
    • Advanced software for AutoCAD
  • Skype: Debalance
Re: Некорректное разбиение блока
« Ответ #5 : 24-11-2019, 13:24:44 »
Попробуй:
Но надо признать - код работает. Хотя это не совсем то, что нужно мне...

Возможен, конечно следующий подход, с использованием данного кода:
1. Копирование вставки блока в другую запись.
2. Расчленение.
3. Получение всех примитивов во временной записи.
4. Необходимые математические вычисления.
5. Удаление объектов и самой временной записи.
Но как-то всё это через ЗДЦ.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Некорректное разбиение блока
« Ответ #6 : 24-11-2019, 13:25:20 »
Кстати в описании к методу написано:
Цитировать

    The AcDbBlockReference must be in a database and must be uniformly scaled.

Подходит ли это для нашего случая?
На твоём блоке работает прекрасно.
Я так понимаю, что этот метод добавляет объекты в базу. А мне бы этого не хотелось, т.к. полученные примитивы используются для временных вычислений, при этом сам взорванный блок должен сохраниться. Такое решение возможно?
Ну если ты сам перепишешь метод explode(), чтобы он работал так как тебе нужно, то - да. Иначе пользуйся тем что есть. Потом можешь удалить добавленные в базу примитивы.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • ****
  • Сообщений: 421
  • Карма: 16
    • Advanced software for AutoCAD
  • Skype: Debalance
Re: Некорректное разбиение блока
« Ответ #7 : 24-11-2019, 13:33:42 »
Потом можешь удалить добавленные в базу примитивы...
... и добавить клон первоначальной вставки.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Некорректное разбиение блока
« Ответ #8 : 24-11-2019, 13:34:34 »
... и добавить клон первоначальной вставки.
Зачем? Оригинал никуда не девается. Я его в своём коде удалил для наглядности.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • ****
  • Сообщений: 421
  • Карма: 16
    • Advanced software for AutoCAD
  • Skype: Debalance
Re: Некорректное разбиение блока
« Ответ #9 : 24-11-2019, 13:35:51 »
Я его в своём коде удалил.
Ок, пропустил... :)

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Некорректное разбиение блока
« Ответ #10 : 25-11-2019, 17:11:14 »
А вот тебе вариант (очень упрощенный, но с твоим блоком работает) расчленение блока без добавления в базу:

Код - C++ [Выбрать]
  1. static AcDbVoidPtrArray ExplodeNusBlockReference(AcDbBlockReference *pBref)
  2. {
  3.   AcDbVoidPtrArray ents;
  4.   Acad::ErrorStatus es = pBref->explode(ents);
  5.   if (es == Acad::eCannotScaleNonUniformly)
  6.   {
  7.     AcDbBlockTableRecordPointer pBtr(pBref->blockTableRecord(), AcDb::kForRead);
  8.     AcGeMatrix3d mat = pBref->blockTransform();
  9.     AcGeScale3d scale3d = pBref->scaleFactors();
  10.     AcDbBlockTableRecordIterator *pIter = NULL;   pBtr->newIterator(pIter);
  11.     if (pIter)
  12.     {
  13.       for (pIter->start(); !pIter->done(); pIter->step())
  14.       {
  15.         AcDbObjectId eid;
  16.         if (pIter->getEntityId(eid) == Acad::eOk && eid.objectClass() == AcDbBlockReference::desc())
  17.         {
  18.           AcDbObjectPointer<AcDbBlockReference> pBrefSub(eid, AcDb::kForRead);
  19.           AcDbBlockReference * pBrefSubClone = (AcDbBlockReference *)pBrefSub->clone();
  20.           // Переносим
  21.           AcGePoint3d p = pBrefSubClone->position();
  22.           pBrefSubClone->setPosition(p.transformBy(mat));
  23.           // Масштабируем
  24.           AcGeScale3d scale3dSub = pBrefSubClone->scaleFactors();
  25.           scale3dSub.postMultBy(scale3d);
  26.           pBrefSubClone->setScaleFactors(scale3dSub);
  27.           // Поворачиваем
  28.           pBrefSubClone->setRotation(pBrefSubClone->rotation() + pBref->rotation());
  29.           ents.append(pBrefSubClone);
  30.         }
  31.       }
  32.       delete pIter;
  33.     }
  34.   }
  35.   return ents;
  36. }

Для проверки кода:

Код - C++ [Выбрать]
  1. static void MyGroupExpl1() {
  2.   ads_name en; ads_point p;
  3.   if (acedEntSel(L"\nВыберите вставку блока: ", en, p) == RTNORM)
  4.   {
  5.     AcDbObjectId eid; acdbGetObjectId(eid, en);
  6.     AcDbObjectPointer<AcDbBlockReference> pBref(eid, AcDb::kForRead);
  7.     if (pBref.openStatus() == Acad::eWrongObjectType)
  8.       return;
  9.     AcDbVoidPtrArray ents = ExplodeNusBlockReference(pBref);
  10.     if (pBref->upgradeOpen() == Acad::eOk)
  11.       pBref->erase(); // Удаляем оригинал вставки блока
  12.     for (int i = 0; i < ents.length(); i++)
  13.     {
  14.       postToDwgAndClose((AcDbEntity *)(ents[i]));
  15.     }
  16.   }
  17. }
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • ****
  • Сообщений: 421
  • Карма: 16
    • Advanced software for AutoCAD
  • Skype: Debalance
Re: Некорректное разбиение блока
« Ответ #11 : 25-11-2019, 23:43:31 »
А вот тебе вариант (очень упрощенный, но с твоим блоком работает) расчленение блока без добавления в базу:
Спасибо. Идею понял. А какие возможны "подводные камни" на прочих блоках при использовании данного упрощённого варианта?

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Некорректное разбиение блока
« Ответ #12 : 25-11-2019, 23:46:22 »
А какие возможны "подводные камни" на прочих блоках при использовании данного упрощённого варианта?
1. С 3Dsolid внутри блоков работать не будет, точнее будет их пропускать.
2. С масштабированием и перемещением вроде всё в порядке, а вот с вращением я не уверен на 100%.
3. Если у вложенного блока есть атрибуты, то они будут игнорироваться.
4. И т.д.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • ****
  • Сообщений: 421
  • Карма: 16
    • Advanced software for AutoCAD
  • Skype: Debalance
Re: Некорректное разбиение блока
« Ответ #13 : 05-11-2020, 15:08:30 »
Успешно использовал метод explodeToOwnerSpace для последовательного разбиения родительского блока и вложенного в него блоков, пока не столкнулся с блоками, созданными на основе ассоциативных массивов. Именно вложенные ассоциативные массивы разбиваются некорректно - (перемещаются и поворачиваются в процессе разбивки). Как исправить данную ситуацию?

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Некорректное разбиение блока
« Ответ #14 : 05-11-2020, 15:11:49 »
Как исправить данную ситуацию?
Ответ очевиден - или не пользоваться этим методом или лезть в начинку этих блоков и перемещать и поворачивать их как нужно.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение