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

06/09/2015

Запуск команды ССЫЛРЕД (REFEDIT) с выбранным примитивом средствами .NET

Действительно интересная проблема возникла в ходе внутренней дискуссии на этой неделе: кому-то понадобилось запустить команду REFEDIT для выбранной внешней ссылки с предварительно выбранным примитивом. И этот примитив должен быть частью выбранной внешней ссылки.

Это оказалось весьма непростым делом, но мы нашли способ, решающий её в несколько строк кода. Хитростью было найти правильный примитив в наборе и соответствующий ему примитив во внешней ссылке.

Вот подход, который я в конечном итоге использовал:

  1. Попросить пользователя выбрать вложенный примитив
  2. Получить первый примитив, содержащийся в списке контейнеров внешней ссылки
    • Нам понадобится примитив верхнего уровня, который может быть выбран во внешней ссылке: это может быть сам выбранный объект
  3. Добавляем обработчик, соответствующий событию “check out” менеджера длинных транзакций
    • Этот обработчик будет проверять «отображение глубокого клонирования» для данной длинной транзакции
    • Если он найдёт исходный примитив (примитив, определённый на шаге 2) тогда получим целевой примитив и добавим его в набор предварительного выбора (pickfirst)
  4. Вызываем команду ССЫЛРЕД (_REFEDIT), передавая ей точку указанную пользователем при выборе примитива
  5. Удаляем обработчик события

Так как нам нужно будет модифицировать набор предварительного выбора (pickfirst) нам понадобится установить команде флаг “redraw”.

Вот C#-код определяющий команду RS (RefeditSelect):

Код - C#: [Выделить]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Runtime;
  5.  
  6. namespace RefeditSelected
  7. {
  8.   public static class Extensions
  9.   {
  10.     ///<summary>
  11.     /// Получаем вложенный примитив из первой внешней ссылки в выборе.
  12.     ///</summary>
  13.     ///<returns>ObjectId объекта верхнего уровня из внешней ссылки.</returns>
  14.  
  15.     public static ObjectId GetFirstXrefChild(this PromptNestedEntityResult res)
  16.     {
  17.       var retId = ObjectId.Null;
  18.  
  19.       var selId = res.ObjectId;
  20.       var conts = res.GetContainers();
  21.       var db = selId.Database;
  22.  
  23.       // Используем транзакцию типа «open-close» в вспомогательной функции
  24.  
  25.       using (var tr = db.TransactionManager.StartOpenCloseTransaction())
  26.       {
  27.         // Проходим от конца к началу в контейнере и ищем внешнюю ссылку
  28.  
  29.         for (int i = conts.Length-1; i >= 0; i--)
  30.         {
  31.           var br = tr.GetObject(conts[i], OpenMode.ForRead) as BlockReference;
  32.           if (br != null)
  33.           {
  34.             var btr =
  35.               (BlockTableRecord)tr.GetObject(
  36.                 br.BlockTableRecord, OpenMode.ForRead
  37.               );
  38.  
  39.             // Если это внешняя ссылка мы вернём следующий контейнер
  40.             // или выбранный примитив, если это самый внутренний контейнер
  41.  
  42.             if (btr.IsFromExternalReference)
  43.             {
  44.               retId = i > 0 ? conts[i-1] : selId;
  45.               break;
  46.             }
  47.           }
  48.         }
  49.         tr.Commit();
  50.       }
  51.       return retId;
  52.     }
  53.   }
  54.  
  55.   public class Commands
  56.   {
  57.     [CommandMethod("RS", CommandFlags.Redraw)]
  58.     public void RefeditSelected()
  59.     {
  60.       var doc = Application.DocumentManager.MdiActiveDocument;
  61.       if (doc == null) return;
  62.       var db = doc.Database;
  63.       var ed = doc.Editor;
  64.  
  65.       // Выбираем примитив внутри внешней ссылки
  66.  
  67.       var pner = ed.GetNestedEntity("\nВыберите примитив во внешней ссылке ");
  68.       if (pner.Status != PromptStatus.OK)
  69.         return;
  70.  
  71.       // Получаем ID примитива, который мы хотим выбрать во внешней ссылке
  72.       // (это первый примитив во внешней ссылке)
  73.  
  74.       var selId = pner.GetFirstXrefChild();
  75.  
  76.       // Обрабатываем только если что-то есть подходящее
  77.  
  78.       if (selId != ObjectId.Null)
  79.       {
  80.         // Определяем наш обработчик события
  81.  
  82.         LongTransactionEventHandler func = (s, e) =>
  83.         {
  84.           // Получаем «отображение глубокого клонирования» для длинной транзакции
  85.  
  86.           var map = e.Transaction.ActiveIdMap;
  87.  
  88.           // Если есть отображение для выбранного нами объекта...
  89.  
  90.           if (map.Contains(selId))
  91.           {
  92.             // ... добавляем его к набору предварительного выбора
  93.  
  94.             ed.SetImpliedSelection(new ObjectId[] { map[selId].Value });
  95.             ed.WriteMessage("\nSelected one entity.");
  96.           }
  97.         };
  98.  
  99.         // Добавляем наш обработчик, вызываем _REFEDIT и удаляем его
  100.  
  101.         Application.LongTransactionManager.CheckedOut += func;
  102.  
  103.         ed.Command("_.-REFEDIT", pner.PickedPoint, "_O", "_A", "_N");
  104.  
  105.         Application.LongTransactionManager.CheckedOut -= func;
  106.       }
  107.     }
  108.   }
  109. }

 

Вот что происходит, когда мы запускаем команду RS и выбираем объекты, принадлежащие внешней ссылке:

 

Важно отметить, что не все примитивы, выбранные выше на одном уровне в иерархии чертежа: когда мы выбираем дверь, к примеру, процесс выбора вложенного примитива на самом деле находит полилинию, входящую в наш дверной блок. Мы должны найти объект в иерархии, который соответствует примитиву верхнего уровня во внешней ссылке - в данном вставку блока двери - и выбрать его: если примитив не существует в внешней ссылке, то мы получим ошибку eInvalidInput, когда мы вызовем Editor.SetImpliedSelection().

Источник: http://through-the-interface.typepad.com/through_the_interface/2015/09/launching-autocads-refedit-command-with-an-entity-selected-using-net.html

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

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

Опубликовано 06.09.2015
Отредактировано 06.09.2015 в 12:38:05