Как удалить параметрику из блоков / вхождений блоков

Автор Тема: Как удалить параметрику из блоков / вхождений блоков  (Прочитано 25623 раз)

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

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

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

  • ADN Club
  • ***
  • Сообщений: 111
  • Карма: 6
Добрый день.
Для вхождений динамических блоков есть прекрасный метод BlockReference.ConvertToStaticBlock, который "удаляет" динамику
У меня задача комбинированная, у меня есть вхождения динамических блоков, у которых присутствует ещё и параметрика
Как преобразовать такие вхождения блоков во вхождения статических, без параметрики и динамики (но с сохранением геометрии).
Например, вначале делаю им ConvertToStaticBlock, что потом можно сделать?
Алексей

Оффлайн Алексей Кулик

  • Administrator
  • *****
  • Сообщений: 1115
  • Карма: 173
ИМХО: потом получить указатель на описание созданного блока, пройтись по всем его подэлементам и удалять параметрические зависимости уже для них. Как это делается в .NET - не представляю (в лиспе как-то решал подобную задачу, но здесь оно вряд ли подойдет).
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Удалить параметрику с примитива можно так: http://adndevblog.typepad.com/autocad/2012/07/associative-framework-how-to-delete-constraints-applied-to-a-specific-entity.html
Это ObjectARX, но думаю что по аналогии сделать на .NET можно.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Вот так это выглядит на C# с использованием AutoCAD .NET API:
Код - C# [Выбрать]
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using System.Reflection;
  4. using Autodesk.AutoCAD.Runtime;
  5. using Autodesk.AutoCAD.ApplicationServices;
  6. using Autodesk.AutoCAD.DatabaseServices;
  7. using Autodesk.AutoCAD.Geometry;
  8. using Autodesk.AutoCAD.EditorInput;
  9. using AcRx = Autodesk.AutoCAD.Runtime;
  10. using AcAp = Autodesk.AutoCAD.ApplicationServices;
  11. using AcDb = Autodesk.AutoCAD.DatabaseServices;
  12. using AcGe = Autodesk.AutoCAD.Geometry;
  13. using AcEd = Autodesk.AutoCAD.EditorInput;
  14.  
  15. [assembly: CommandClass(typeof(Rivilis.RemoveConsAssoc))]
  16.  
  17. namespace Rivilis
  18. {
  19.   public class RemoveConsAssoc
  20.   {
  21.     public void DeleteAllConstraintsOnEntity(ObjectId id)
  22.     {
  23.       using (AcDb.DBObject obj = id.Open(AcDb.OpenMode.ForWrite))
  24.       {
  25.         ObjectIdCollection idsAct = AcDb.AssocAction.GetActionsDependentOnObject(obj, true, true);
  26.         ObjectIdCollection idsDep = AcDb.AssocDependency.GetDependenciesOnObject(obj, true, true);
  27.         for (int i = 0; i < idsAct.Count; i++)
  28.         {
  29.           using (AcDb.Assoc2dConstraintGroup objAct =
  30.             idsAct[i].Open(AcDb.OpenMode.ForWrite) as AcDb.Assoc2dConstraintGroup)
  31.           {
  32.             if (objAct != null)
  33.             {
  34.               for (int j = 0; j < idsDep.Count; j++)
  35.                 objAct.DeleteConstrainedGeometry(idsDep[j]);
  36.             }
  37.           }
  38.         }
  39.       }
  40.     }
  41.     [CommandMethod("RemConsAssoc", CommandFlags.Modal)]
  42.     public void RemConsAssoc()
  43.     {
  44.       AcAp.Document doc = AcAp.Application.DocumentManager.MdiActiveDocument;
  45.       AcDb.Database db = doc.Database;
  46.       AcEd.Editor ed = doc.Editor;
  47.       AcEd.PromptEntityOptions prEnt =
  48.         new AcEd.PromptEntityOptions("\nВыберите примитив для удаления зависимостей: ");
  49.       AcEd.PromptEntityResult resEnt = ed.GetEntity(prEnt);
  50.       if (resEnt.Status != AcEd.PromptStatus.OK)
  51.       {
  52.         ed.WriteMessage("\nНичего не выбрали!");
  53.         return;
  54.       }
  55.       DeleteAllConstraintsOnEntity(resEnt.ObjectId);
  56.     }
  57.   }
  58. }
При желании можно использовать и транзакции.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • ***
  • Сообщений: 111
  • Карма: 6
В процессе работы кода получаю сообщение (скриншот во вложении)
Судя по всему, это происходит тогда, когда удаляются геометрические ограничения, которые используются в формулах.
Попытался получать и удалять AssocVariable как у объектов описания блока, так и у самого описания блока. Не помогает.
Алексей

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

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

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

  • ADN Club
  • ***
  • Сообщений: 111
  • Карма: 6
Образец блока во вложении.
Наколенный быстрый код, написанный на основе вашего, который по запросу вхождения блока должен вычищать описание блока от параметрики. Он выдаёт искомое сообщение, если выбрать вхождение блока в файле во вложении
Код - C# [Выбрать]
  1. [AcRt.CommandMethod("RemConsAssoc", AcRt.CommandFlags.Modal)]
  2. public void RemConsAssoc()
  3. {
  4.     AcAs.Document doc = AcApp.DocumentManager.MdiActiveDocument;
  5.     AcDb.Database db = doc.Database;
  6.     AcEd.Editor ed = doc.Editor;
  7.     AcEd.PromptEntityOptions prEnt = new AcEd.PromptEntityOptions("\nВыберите вхождение блока для удаления зависимостей: ");
  8.     prEnt.SetRejectMessage("Должно быть вхождение блока!");
  9.     prEnt.AddAllowedClass(typeof(BlockReference), true);
  10.     AcEd.PromptEntityResult resEnt = ed.GetEntity(prEnt);
  11.     if (resEnt.Status != AcEd.PromptStatus.OK)
  12.         return;
  13.  
  14.     DeleteAllConstraintsOnEntity(resEnt.ObjectId);
  15. }
  16.  
  17. private void DeleteAllConstraintsOnEntity(AcDb.ObjectId objectId)
  18. {
  19.     using (AcDb.Transaction tr = AcDb.HostApplicationServices.WorkingDatabase.TransactionManager.StartTransaction())
  20.     {
  21.         AcDb.BlockReference bref = tr.GetObject(objectId, AcDb.OpenMode.ForRead) as AcDb.BlockReference;
  22.         AcDb.BlockTableRecord btr = tr.GetObject(bref.DynamicBlockTableRecord, AcDb.OpenMode.ForWrite) as AcDb.BlockTableRecord;
  23.         foreach (DBObject dbo in btr.Cast<AcDb.ObjectId>().Select(id => tr.GetObject(id, AcDb.OpenMode.ForWrite) as AcDb.DBObject))
  24.         {
  25.             ObjectIdCollection idsAct = AssocAction.GetActionsDependentOnObject(dbo, true, true);
  26.             ObjectIdCollection idsDep = AssocDependency.GetDependenciesOnObject(dbo, true, true);
  27.             for (int i = 0; i < idsAct.Count; i++)
  28.             {
  29.                 Assoc2dConstraintGroup objAct = tr.GetObject(idsAct[i], OpenMode.ForWrite) as Assoc2dConstraintGroup;
  30.                 if (objAct != null)
  31.                 {
  32.                     for (int j = 0; j < idsDep.Count; j++)
  33.                     {
  34.                         objAct.DeleteConstrainedGeometry(idsDep[j]);
  35.                     }
  36.                 }
  37.             }
  38.         }
  39.         tr.Commit();
  40.     }
  41. }
Алексей

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

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

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Впрочем, так как тебе не нужна вообще никакая динамика и параметрика, то можно радикально удалить из ExtensionDictionary BlockTableRecord всё:

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

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

  • ADN Club
  • ***
  • Сообщений: 111
  • Карма: 6
Сделал конвертирование в статику (что бы исключить проблемы с остальными вхождениями блока), а затем чистку и удаление ExtensionDictionary. В принципе, всё очищается без доп. уведомлений, но появляется промежуточный странный эффект, блок теряет параметрику, но автокад обновляет эту информацию только после захода в Block Editor: скринкаст, иллюстрирующий эффект
Думаю, в моём случае это не проблема, т.к. блоки будут обрабатываться в базе без создания документа.
Код:
Код - C# [Выбрать]
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. using AcApp = Autodesk.AutoCAD.ApplicationServices.Application;
  7. using AcRt = Autodesk.AutoCAD.Runtime;
  8. using AcAs = Autodesk.AutoCAD.ApplicationServices;
  9. using AcDb = Autodesk.AutoCAD.DatabaseServices;
  10. using AcEd = Autodesk.AutoCAD.EditorInput;
  11.  
  12. [assembly: AcRt.CommandClass(typeof(Bargool.CommandClass))]
  13.  
  14. namespace Bargool
  15. {
  16.     class CommandClass
  17.     {
  18.         [AcRt.CommandMethod("RemConsAssoc", AcRt.CommandFlags.Modal)]
  19.         public void RemConsAssoc()
  20.         {
  21.             AcAs.Document doc = AcApp.DocumentManager.MdiActiveDocument;
  22.             AcDb.Database db = doc.Database;
  23.             AcEd.Editor ed = doc.Editor;
  24.             AcEd.PromptEntityOptions prEnt = new AcEd.PromptEntityOptions("\nВыберите вхождение блока для удаления зависимостей: ");
  25.             prEnt.SetRejectMessage("Должно быть вхождение блока!");
  26.             prEnt.AddAllowedClass(typeof(AcDb.BlockReference), true);
  27.             AcEd.PromptEntityResult resEnt = ed.GetEntity(prEnt);
  28.             if (resEnt.Status != AcEd.PromptStatus.OK)
  29.                 return;
  30.  
  31.             DeleteAllConstraintsOnEntity(resEnt.ObjectId);
  32.         }
  33.  
  34.         private void DeleteAllConstraintsOnEntity(AcDb.ObjectId objectId)
  35.         {
  36.             using (AcDb.Transaction tr = AcDb.HostApplicationServices.WorkingDatabase.TransactionManager.StartTransaction())
  37.             {
  38.                 AcDb.BlockReference bref = tr.GetObject(objectId, AcDb.OpenMode.ForRead) as AcDb.BlockReference;
  39.                 if (!bref.IsDynamicBlock)
  40.                     return;
  41.  
  42.                 // Подбираем имя для статического блока и конвертим динамику в статику
  43.                 int index = 0;
  44.                 string blocknamebase = "ExDyn";
  45.  
  46.                 AcDb.BlockTable bt = (AcDb.BlockTable)tr.GetObject(AcDb.HostApplicationServices.WorkingDatabase.BlockTableId, AcDb.OpenMode.ForRead);
  47.                 while (bt.Has(blocknamebase + index.ToString()))
  48.                     index++;
  49.  
  50.                 string blockname = blocknamebase + index.ToString();
  51.  
  52.                 bref.ConvertToStaticBlock(blockname);
  53.  
  54.                 AcDb.BlockTableRecord btr = tr.GetObject(bt[blockname], AcDb.OpenMode.ForWrite) as AcDb.BlockTableRecord;
  55.                 if (btr.ExtensionDictionary.IsNull)
  56.                     return;
  57.  
  58.                 AcDb.DBDictionary extDic = tr.GetObject(btr.ExtensionDictionary, AcDb.OpenMode.ForWrite) as AcDb.DBDictionary;
  59.                 foreach (AcDb.DBDictionaryEntry entry in extDic)
  60.                 {
  61.                     extDic.Remove(entry.Key);
  62.                 }
  63.                 btr.ReleaseExtensionDictionary();
  64.                
  65.                 tr.Commit();
  66.             }
  67.         }
  68.     }
  69. }
  70.  
Блок всё тот же, что приложен к сообщению выше
Алексей

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Первое, что мне приходило на ум - это после ConvertToStaticBlock - "пробежаться" по всем примитивам блока и "перекопировать" их в тот-же блок с удалением оригинала примитива - не знаю поможет-ли - но что-то мне подсказывает что данный способ будет более "брутален" по части непредвиденных эффектов автокада.

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

  • ADN Club
  • ***
  • Сообщений: 111
  • Карма: 6
Всё ещё веселее. При удалении extension dictionary блока при работе с базой без открытия документа геометрические ограничения не удаляются. Я заметил, что у примитивов в блоке остаются реакторы,  которые, видимо, отвечают за геометрические ограничения
Дима_, честно говоря да, сомневаюсь, что из этого что-то нормальное получится.
Алексей

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

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

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

  • ADN Club
  • ***
  • Сообщений: 111
  • Карма: 6
WorkingDatabase переключаю. Первый вариант кода всё также выдает то самое сообщение.
Алексей

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

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