Объединение блоков AutoCAD с использованием .NET API
Вопрос: У меня есть два блока с разными атрибутами, которые я хочу объединить в единый блок. При этом я не хочу создавать вложенные блоки. Как это можно осуществить при помощи AutoCAD .NET API?
Ответ: Вот C#-код, который использует метод Database.DeepCloneObjects() для создания нового блока на основе двух других:
- using Autodesk.AutoCAD.ApplicationServices;
- using Autodesk.AutoCAD.DatabaseServices;
- using Autodesk.AutoCAD.EditorInput;
- using Autodesk.AutoCAD.Runtime;
- using System.Linq;
- namespace BlockMerging
- {
- public class Commands
- {
- [CommandMethod("MB")]
- public static void MergeBlocks()
- {
- var doc = Application.DocumentManager.MdiActiveDocument;
- if (doc == null)
- return;
- var db = doc.Database;
- var ed = doc.Editor;
- // Спрашиваем имя первого блока
- var pr = ed.GetString("\nИмя первого блока: ");
- if (pr.Status != PromptStatus.OK)
- return;
- string first = pr.StringResult.ToUpper();
- using (var tr = doc.TransactionManager.StartTransaction())
- {
- var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
- // Проверяем есть ли такой блок
- if (bt.Has(first))
- {
- // Спрашиваем имя второго блока
- pr = ed.GetString("\nИмя второго блока: ");
- if (pr.Status != PromptStatus.OK)
- return;
- string second = pr.StringResult.ToUpper();
- // Проверяем есть ли такой блок
- if (bt.Has(second))
- {
- // Спрашиваем имя нового блока
- pr = ed.GetString("\nИмя нового блока: ");
- if (pr.Status != PromptStatus.OK)
- return;
- string merged = pr.StringResult.ToUpper();
- // Убеждаемся, что блока с таким именем еще нет
- if (!bt.Has(merged))
- {
- // Нам нужно объединить содержимое двух блоков
- var ids = new ObjectIdCollection();
- // Открываем оба блока для объединения
- var btr1 = tr.GetObject(bt[first], OpenMode.ForRead) as BlockTableRecord;
- var btr2 = tr.GetObject(bt[second], OpenMode.ForRead) as BlockTableRecord;
- // Используем LINQ для получения IEnumerable<ObjectId> из блоков
- var en1 = btr1.Cast<ObjectId>();
- var en2 = btr2.Cast<ObjectId>();
- // Добавляем всё содержимое в нашу коллекцию
- // (мы можем применить и фильтрацию, например, не допустить имена атрибутов
- // с одинаковым именем)
- ids.Add(en1.ToArray<ObjectId>());
- ids.Add(en2.ToArray<ObjectId>());
- // Создаем новую запись таблицы блоков для нашего объединённого блока
- var btr = new BlockTableRecord();
- btr.Name = merged;
- // Добавляем его к таблице блоков и в транзакцию
- bt.UpgradeOpen();
- var btrId = bt.Add(btr);
- tr.AddNewlyCreatedDBObject(btr, true);
- // Выполняем "глубокое клонирование" двух наших блоков в один новый
- var idMap = new IdMapping();
- db.DeepCloneObjects(ids, btrId, idMap, false);
- ed.WriteMessage("\nБлок \"{0}\" создан.", merged);
- }
- else
- {
- ed.WriteMessage(
- "\nВ чертеже уже есть блок с именем \"{0}\".", merged
- );
- }
- }
- else
- {
- ed.WriteMessage("\nБлок \"{0}\" не найден.", second);
- }
- }
- else
- {
- ed.WriteMessage("\nБлок \"{0}\" не найден.", first);
- }
- // Всегда подтверждаем транзакцию
- tr.Commit();
- }
- }
- }
- public static class Extensions
- {
- public static void Add(this ObjectIdCollection col, ObjectId[] ids)
- {
- foreach (var id in ids)
- {
- if (!col.Contains(id))
- col.Add(id);
- }
- }
- }
- }
Мы можем использовать метод 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