сопоставление листов и динамических блоков

Автор Тема: сопоставление листов и динамических блоков  (Прочитано 7119 раз)

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

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

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

  • ADN OPEN
  • Сообщений: 32
  • Карма: 1
Здравствуйте, уважаемые форумчане! Подскажите, как можно сопоставить динамический блок. который вставлен на различных листах? необходимо корректировать информацию у динамического блока "Осн. надпись". который вставлен на различных листах


ищем вставки блоков в чертеже
Код - C# [Выбрать]
  1.  using (DocumentLock docLock = doc.LockDocument())
  2.             {
  3.                 using (Transaction tr = db.TransactionManager.StartTransaction())
  4.                 {
  5.                     //Алгоритм для отбора динамических вставок блока в т.ч. и их аннонимных копий
  6.                     //Алгоритм для определения координат атрибутов определения блока                                        
  7.  
  8.                     ObjectIdCollection dynBlockRefsFull = new ObjectIdCollection();
  9.  
  10.                     // получаем таблицу блоков и проходим по всем записям таблицы блоков
  11.                     BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
  12.                     foreach (ObjectId btrId in bt)
  13.                     {
  14.                         // получаем запись таблицы блоков и смотри анонимная ли она
  15.                         BlockTableRecord btr = (BlockTableRecord)tr.GetObject(btrId, OpenMode.ForRead);
  16.                         if ((btr.IsDynamicBlock) && (btr.Name.Contains("Осн. надпись") == true))
  17.                         {
  18.                             // получаем все анонимные блоки динамического блока
  19.                             ObjectIdCollection anonymousIds = btr.GetAnonymousBlockIds();
  20.  
  21.                             // получаем все прямые вставки динамического блока
  22.  
  23.                             //foreach (ObjectId id in btr.GetBlockReferenceIds(true, true))
  24.                            // {
  25.                            //     dynBlockRefsFull.Add(id);
  26.                            // }
  27.  
  28.                             foreach (ObjectId anonymousBtrId in anonymousIds)
  29.                             {
  30.                                 // получаем анонимный блок
  31.                                 BlockTableRecord anonymousBtr = (BlockTableRecord)tr.GetObject(anonymousBtrId, OpenMode.ForRead);
  32.                                 // получаем все вставки этого блока
  33.                                 ObjectIdCollection blockRefIds = anonymousBtr.GetBlockReferenceIds(true, true);
  34.  
  35.                                 foreach (ObjectId id in blockRefIds)
  36.                                 {
  37.                                     dynBlockRefsFull.Add(id);
  38.                                 }
  39.  
  40.                             }
  41.                         }
  42.                     }

далее есть кусок кода, который корректирует информацию в атрибутах блока

Код - C# [Выбрать]
  1. foreach (ObjectId id in dynBlockRefsFull)
  2.                     {
  3.                         BlockReference br = (BlockReference)tr.GetObject(id, OpenMode.ForWrite);
  4.                         BlockTableRecord btr = tr.GetObject(br.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;
  5.                         AttributeDefinition[] atr_def = new AttributeDefinition[100];
  6.  
  7.  
  8.                         int i = 0;
  9.                         foreach (var idEnt in btr)
  10.                         {
  11.                             Entity en = tr.GetObject(idEnt, OpenMode.ForRead) as Entity;
  12.                             if (en.GetType() == typeof(AttributeDefinition))
  13.                             {
  14.                                 AttributeDefinition atr = tr.GetObject(idEnt, OpenMode.ForRead) as AttributeDefinition;
  15.                                 atr_def[i] = atr;
  16.                                 i++;
  17.                             }
  18.                         }
  19.  
  20.  
  21.                         bool shet_na_polnotu = false;
  22.  
  23.  
  24. //проверяю что в выбранной основной надписи тег "номер проекта" - не пустой
  25.                         foreach (ObjectId idAtrRef in br.AttributeCollection)
  26.                         {
  27.                             AttributeReference atr_ref = tr.GetObject(idAtrRef, OpenMode.ForWrite, false, true) as AttributeReference;
  28.                             if ((atr_ref.TextString != "####") && (atr_ref.Tag == "НОМЕР-ПРОЕКТА"))
  29.                                 shet_na_polnotu = true;
  30.                         }
  31.  
  32.  
  33.                         if (shet_na_polnotu == true)
  34.                         {
  35.                             int i_atr = 0;
  36.                             foreach (ObjectId idAtrRef in br.AttributeCollection)
  37.                             {
  38.                                 AttributeReference atr_ref = tr.GetObject(idAtrRef, OpenMode.ForWrite, false, true) as AttributeReference;
  39. //
  40. //
  41. //!! Вносим по необходимости в нужный атрибут нужную инфу
  42. //
  43. //
  44.  
  45.  
  46.                                     i_atr++;
  47.                             }
  48.                         }
  49.  
  50.                     }
  51.  
  52.                     tr.Commit();
  53.  
  54.                 }
  55.             }
  56.  


как рассматривать отдельные основные надписи расположенные на конкретных листах?
например в чертеже листы "1", "2", "3"

нужно получить наименования этих листов, и при выборе в форме к примеру листа "2"  написать условие что-то вроде

if блок который мы рассматриваем находится на листе с наименованием "2", то правим атрибуты

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 822
  • Карма: 166
    • Мои плагины к Автокаду
У любого объекта в пространстве бумаги BlockId указывает на пространство этого листа. По этому id можно найти layout с таким же BlockTableRecordId. А у лейоута уже берите имя или TabOrder и записывайте в ваш атрибут.
p.s. Даже на первый взгляд в коде много неоптимального. Например
Код - C# [Выбрать]
  1.                             if (en.GetType() == typeof(AttributeDefinition))
  2.                             {
  3.                                 AttributeDefinition atr = tr.GetObject(idEnt, OpenMode.ForRead) as AttributeDefinition;
  4.                                 ...
  5.  
Можно заменить на
Код - C# [Выбрать]
  1. if (en is AttributeDefinition atr) { ...

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

  • ADN OPEN
  • Сообщений: 32
  • Карма: 1
У любого объекта в пространстве бумаги BlockId указывает на пространство этого листа. По этому id можно найти layout с таким же BlockTableRecordId. А у лейоута уже берите имя или TabOrder и записывайте в ваш атрибут.

avc, Можно чуточку подробнее? Какие методы необходимо использовать? вот допустим есть btrId, как получить имя листа? и как обратиться к пространству листов и получить наименования листов в чертеже?

а по поводу оптимизации кода - согласен, буду оптимизировать, но пожалуй когда плагин будет рабочий)

Отмечено как Решение bert 14-09-2018, 12:50:26

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 822
  • Карма: 166
    • Мои плагины к Автокаду
если у вас есть любой Entity ent, то можно так:
Код - C# [Выбрать]
  1.       DBDictionary loDict = tr.GetObject(ent.Database.LayoutDictionaryId, OpenMode.ForRead) as DBDictionary;
  2.       foreach (DBDictionaryEntry entry in loDict) // перебор всех листов включая модель
  3.        {
  4.           Layout lo = tr.GetObject(entry.Value, OpenMode.ForRead) as Layout;
  5.           if (lo.BlockTableRecordId == ent.BlockId) // нашли лист с этим объектов
  6.           {
  7.               // тут можно использовать lo.LayoutName и lo.TabOrder как вам угодно
  8.  
  9.  
  10.               break;
  11.           }
  12.        }

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 822
  • Карма: 166
    • Мои плагины к Автокаду
и как обратиться к пространству листов и получить наименования листов в чертеже?
вот код для списка листов.
Правда, я когда это писал использовал using для объектов транзакции. Говорят, что это не нужно. Но работает и так.
И для перобразования Dictionary в List можно использовать Linq
Манипуляции с использованием TopTransaction можете выкинуть
Код - C# [Выбрать]
  1.     /// <summary>
  2.     /// Имена всех лейаутов в порядке TabOrder
  3.     /// </summary>
  4.     public static List<string> Collect(Database db, bool andModel = true)
  5.     {
  6.       if (db == null || db.IsDisposed) return new List<string>();
  7.       bool newTrans = db.TransactionManager.TopTransaction == null;
  8.       Transaction tr = (newTrans) ? db.TransactionManager.StartTransaction() : db.TransactionManager.TopTransaction;
  9.       try
  10.       {
  11.         using (DBDictionary dict = tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead) as DBDictionary)
  12.         {
  13.           SortedDictionary<int, string> sd = new SortedDictionary<int, string>();
  14.           if (dict == null) return new List<string>();
  15.           foreach (DictionaryEntry ID in dict)
  16.           {
  17.             ObjectId id = (ObjectId)ID.Value;
  18.             using (Layout lo = tr.GetObject(id, OpenMode.ForRead) as Layout)
  19.               if (lo != null)
  20.               {
  21.                 if (!andModel && lo.LayoutName == "Model") continue;
  22.                 sd.Add(lo.TabOrder, lo.LayoutName);
  23.               }
  24.           }
  25.           List<string> ret = new List<string>(sd.Count);
  26.           foreach (string name in sd.Values)
  27.             ret.Add(name);
  28.           return ret;
  29.         }
  30.       }
  31.       finally
  32.       {
  33.         if (newTrans)
  34.         {
  35.           tr.Commit(); tr.Dispose();
  36.         }
  37.       }
  38.     }

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
вот допустим есть btrId, как получить имя листа?
Чей btrId? BlockTableRecord листа?
Код - C# [Выбрать]
  1. using System;
  2. using Autodesk.AutoCAD.Runtime;
  3. using Autodesk.AutoCAD.ApplicationServices;
  4. using Autodesk.AutoCAD.DatabaseServices;
  5. using Autodesk.AutoCAD.Geometry;
  6. using Autodesk.AutoCAD.EditorInput;
  7.  
  8. #pragma warning disable 0618
  9.  
  10. // This line is not mandatory, but improves loading performances
  11. [assembly: CommandClass(typeof(GetLayoutName.MyCommands))]
  12.  
  13. namespace GetLayoutName
  14. {
  15.  
  16.   public class MyCommands
  17.   {
  18.     /// <summary>
  19.     /// Функция по ObjectId блока (BlockTableRecord) листа возвращает имя листа
  20.     /// </summary>
  21.     /// <param name="btrId"></param>
  22.     /// <returns></returns>
  23.     static public string GetLayoutNameWithBtrId(ObjectId btrId)
  24.     {
  25.       using (DBDictionary dict = btrId.Database.LayoutDictionaryId.Open(OpenMode.ForRead) as DBDictionary)
  26.       {
  27.         foreach (DBDictionaryEntry entr in dict)
  28.         {
  29.           using (Layout layout = entr.Value.Open(OpenMode.ForRead) as Layout)
  30.           {
  31.             if (btrId == layout.BlockTableRecordId)
  32.               return layout.LayoutName;
  33.           }
  34.         }
  35.  
  36.       }
  37.       return null;
  38.     }
  39.  
  40.     [CommandMethod("GetLayName")]
  41.     public void MyCommand() // This method can have any name
  42.     {
  43.       Document doc = Application.DocumentManager.MdiActiveDocument;
  44.       if (doc == null) return;
  45.       Editor ed = doc.Editor;
  46.       PromptEntityResult rsRes = ed.GetEntity("Выберите любой примитив: ");
  47.       if (rsRes.Status != PromptStatus.OK) return;
  48.       using (Entity en = rsRes.ObjectId.Open(OpenMode.ForRead) as Entity)
  49.       {
  50.         ed.WriteMessage("\nLayoutName = {0}", GetLayoutNameWithBtrId(en.BlockId));
  51.       }
  52.     }
  53.  
  54.   }
  55. }
  56.  
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN OPEN
  • Сообщений: 32
  • Карма: 1
avc, спасибо большое! очень помогли!
Александр Ривилис, тоже благодарю, что обратили внимание, обязательно изучу Ваш вариант!

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 822
  • Карма: 166
    • Мои плагины к Автокаду
обязательно изучу Ваш вариант
Обратите внимания, что у Александра не используются транзакции. Это принципиально другой подход. Олдскульный :) И тут уже using строго необходим.

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Олдскульный
Не, точнее так: адванседовый ;)