ADN Open CIS
Сообщество программистов Autodesk в СНГ

18/04/2016

Объединение блоков AutoCAD с использованием .NET API

Вопрос: У меня есть два блока с разными атрибутами, которые я хочу объединить в единый блок. При этом я не хочу создавать вложенные блоки. Как это можно осуществить при помощи AutoCAD .NET API?

Ответ: Вот C#-код, который использует метод Database.DeepCloneObjects() для создания нового блока на основе двух других:

Код - C#: [Выделить]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Runtime;
  5. using System.Linq;
  6.  
  7. namespace BlockMerging
  8. {
  9.   public class Commands
  10.   {
  11.     [CommandMethod("MB")]
  12.     public static void MergeBlocks()
  13.     {
  14.       var doc = Application.DocumentManager.MdiActiveDocument;
  15.       if (doc == null)
  16.         return;
  17.       var db = doc.Database;
  18.       var ed = doc.Editor;
  19.       // Спрашиваем имя первого блока
  20.       var pr = ed.GetString("\nИмя первого блока: ");
  21.       if (pr.Status != PromptStatus.OK)
  22.         return;
  23.       string first = pr.StringResult.ToUpper();
  24.  
  25.       using (var tr = doc.TransactionManager.StartTransaction())
  26.       {
  27.         var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
  28.         // Проверяем есть ли такой блок
  29.         if (bt.Has(first))
  30.         {
  31.           // Спрашиваем имя второго блока
  32.           pr = ed.GetString("\nИмя второго блока: ");
  33.           if (pr.Status != PromptStatus.OK)
  34.             return;
  35.           string second = pr.StringResult.ToUpper();
  36.           // Проверяем есть ли такой блок
  37.           if (bt.Has(second))
  38.           {
  39.             // Спрашиваем имя нового блока
  40.             pr = ed.GetString("\nИмя нового блока: ");
  41.             if (pr.Status != PromptStatus.OK)
  42.               return;
  43.  
  44.             string merged = pr.StringResult.ToUpper();
  45.  
  46.             // Убеждаемся, что блока с таким именем еще нет
  47.             if (!bt.Has(merged))
  48.             {
  49.               // Нам нужно объединить содержимое двух блоков
  50.               var ids = new ObjectIdCollection();
  51.               // Открываем оба блока для объединения
  52.               var btr1 = tr.GetObject(bt[first], OpenMode.ForRead) as BlockTableRecord;
  53.               var btr2 = tr.GetObject(bt[second], OpenMode.ForRead) as BlockTableRecord;
  54.  
  55.               // Используем LINQ для получения IEnumerable<ObjectId> из блоков
  56.               var en1 = btr1.Cast<ObjectId>();
  57.               var en2 = btr2.Cast<ObjectId>();
  58.  
  59.               // Добавляем всё содержимое в нашу коллекцию
  60.               // (мы можем применить и фильтрацию, например, не допустить имена атрибутов
  61.               // с одинаковым именем)
  62.               ids.Add(en1.ToArray<ObjectId>());
  63.               ids.Add(en2.ToArray<ObjectId>());
  64.  
  65.               // Создаем новую запись таблицы блоков для нашего объединённого блока
  66.               var btr = new BlockTableRecord();
  67.               btr.Name = merged;
  68.  
  69.               // Добавляем его к таблице блоков и в транзакцию
  70.  
  71.               bt.UpgradeOpen();
  72.               var btrId = bt.Add(btr);
  73.               tr.AddNewlyCreatedDBObject(btr, true);
  74.  
  75.               // Выполняем "глубокое клонирование" двух наших блоков в один новый
  76.  
  77.               var idMap = new IdMapping();
  78.               db.DeepCloneObjects(ids, btrId, idMap, false);
  79.  
  80.               ed.WriteMessage("\nБлок \"{0}\" создан.", merged);
  81.             }
  82.             else
  83.             {
  84.               ed.WriteMessage(
  85.                 "\nВ чертеже уже есть блок с именем \"{0}\".", merged
  86.               );
  87.             }
  88.           }
  89.           else
  90.           {
  91.             ed.WriteMessage("\nБлок \"{0}\" не найден.", second);
  92.           }
  93.         }
  94.         else
  95.         {
  96.           ed.WriteMessage("\nБлок \"{0}\" не найден.", first);
  97.         }
  98.  
  99.         // Всегда подтверждаем транзакцию
  100.         tr.Commit();
  101.       }
  102.     }
  103.   }
  104.   public static class Extensions
  105.   {
  106.     public static void Add(this ObjectIdCollection col, ObjectId[] ids)
  107.     {
  108.       foreach (var id in ids)
  109.       {
  110.         if (!col.Contains(id))
  111.           col.Add(id);
  112.       }
  113.     }
  114.   }
  115. }

Мы можем использовать метод DeepCloneObjects() в данном случае, так как блоки содержатся в одном чертеже. Если мы хотим поместить объединённый блок в новый чертеж, то нам потребуется использовать метод WblockCloneObjects(), а затем метод Insert(). Этот подход гарантирует, что любые "жесткие" ссылки и их содержимое также скопируются, о чем мы не должны беспокоиться при работе внутри одной базы данных.

Вот как команда MB работает с парой простых блоков, содержащих линии и окружности, соответственно:

Она также отлично работает с атрибутами: здесь мы объединяем атрибуты из двух отдельных блоков, которые имеют одинаковые имена. Мы видим, что мы получается комбинированный набор атрибутов - с повторяющимися именами - в полученном блоке:

Мы могли бы, конечно, отфильтровать любые атрибуты, чтобы они не повторялись дважды, что может быть обязательным требованием. Я также никоим образом не беспокоился о расположении примитивов в блоке: вы видите, что я просто поместил точку вставки двух блоков в место, которое помогает нам избежать дублирования. И то и другое оставляю читателю для экспериментов, так как они являются очень специфическими в разных сценариях работы.

По мотивам: http://through-the-interface.typepad.com/through_the_interface/2016/04/merging-autocad-blocks-using-net.html

Автор перевода: Александр Ривилис

Обсуждение: http://adn-cis.org/forum/index.php?topic=7042

Опубликовано 18.04.2016