Включить\Отключить аннотативность объекта

Автор Тема: Включить\Отключить аннотативность объекта  (Прочитано 16802 раз)

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

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

  • ADN Club
  • ****
  • Сообщений: 270
  • Карма: 24
  • Геодезист
Долга меня мучал этот вопрос, на AutoLISP победить не получилось
Чуть-чуть стал пробовать силы в .NET опираясь на статью https://adn-cis.org/kak-sdelat-obektyi-autocad-annotativnyimi-v-.net.html
Сваял вот такой код

Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.Runtime;
  4. using System;
  5.  
  6. namespace First_Function
  7. {
  8.     public class LispFunctionsExtensions
  9.     {
  10.         [LispFunction(nameof(RemoveAnnotation))]
  11.         public bool RemoveAnnotation(ResultBuffer resBuf)
  12.         {
  13.             var activeDocument = Application.DocumentManager.MdiActiveDocument;
  14.             if (resBuf != null)
  15.             {
  16.                 Array argArray = resBuf.AsArray();
  17.                 var value = argArray.GetValue(0);
  18.                 TypedValue typedValue = (TypedValue)value;
  19.                 if (typedValue.TypeCode == 5006)
  20.                 {
  21.                     ObjectId annObjId = (ObjectId)typedValue.Value;
  22.                     bool flag = false;
  23.                     Transaction tr = activeDocument.TransactionManager.StartTransaction();
  24.                     using (tr)
  25.                     {
  26.                         DBObject obj = tr.GetObject(annObjId, OpenMode.ForRead);
  27.                         if (obj != null && (obj != null && IsObjectAnnotation(obj)))
  28.                         {
  29.                             flag = true;
  30.                             obj.UpgradeOpen();
  31.                             obj.Annotative = AnnotativeStates.False;
  32.                         }
  33.                         tr.Commit();
  34.                         return flag;
  35.                     }
  36.                 }
  37.                 else return false;
  38.             }
  39.             else return false;
  40.         }
  41.         [LispFunction(nameof(AddAnnotation))]
  42.         public static bool AddAnnotation(ResultBuffer resBuf)
  43.         {
  44.             var activeDocument = Application.DocumentManager.MdiActiveDocument;
  45.             if (resBuf != null)
  46.             {
  47.                 Array argArray = resBuf.AsArray();
  48.                 var value = argArray.GetValue(0);
  49.                 TypedValue typedValue = (TypedValue)value;
  50.                 if (typedValue.TypeCode == 5006)
  51.                 {
  52.                     ObjectId annObjId = (ObjectId)typedValue.Value;
  53.                     bool flag = false;
  54.  
  55.                     Transaction tr = activeDocument.TransactionManager.StartTransaction();
  56.                     using (tr)
  57.                     {
  58.                         DBObject obj = tr.GetObject(annObjId, OpenMode.ForRead);
  59.                         if (obj != null && IsObjectAnnotation(obj))
  60.                         {
  61.                             flag = true;
  62.                             obj.UpgradeOpen();
  63.                             obj.Annotative = AnnotativeStates.True;
  64.                         }
  65.                         tr.Commit();
  66.                         return flag;
  67.                     }
  68.                 }
  69.                 else return false;
  70.             }
  71.             else return false;
  72.         }      
  73.         private static bool IsObjectAnnotation(DBObject annObject)
  74.             {
  75.             RXClass rXClass = annObject.GetRXClass();          
  76.             if (rXClass.Equals(RXClass.GetClass(typeof(DBText)))
  77.                             ||
  78.                             rXClass.Equals(RXClass.GetClass(typeof(BlockTableRecord)))
  79.                             ||
  80.                             rXClass.Equals(RXClass.GetClass(typeof(DBText)))
  81.                             ||
  82.                             rXClass.Equals(RXClass.GetClass(typeof(MText)))
  83.                             ||
  84.                             rXClass.Equals(RXClass.GetClass(typeof(Dimension)))
  85.                             ||
  86.                             rXClass.Equals(RXClass.GetClass(typeof(Leader)))
  87.                             ||
  88.                             rXClass.Equals(RXClass.GetClass(typeof(MLeader)))
  89.                             ||
  90.                             rXClass.Equals(RXClass.GetClass(typeof(Hatch)))                          
  91.                 )
  92.                 return true;
  93.             else
  94.                 return false;
  95.         }
  96.     }
  97. }

Вроде даже работает, но верю что не всю тут по ООП-ешному. Хотел бы выслушать ваши замечания, мне стыдно за свои LISP коды, хочу на C# сразу учится писать по человечески.


Вот такая запись норм?
Код - C# [Выбрать]
  1. (
  2. rXClass.Equals(RXClass.GetClass(typeof(DBText)))
  3. ||
  4. rXClass.Equals(RXClass.GetClass(typeof(BlockTableRecord)))
  5. ||
  6. rXClass.Equals(RXClass.GetClass(typeof(DBText)))
  7. ||
  8. rXClass.Equals(RXClass.GetClass(typeof(MText)))
  9. ||
  10. rXClass.Equals(RXClass.GetClass(typeof(Dimension)))
  11. ||
  12. rXClass.Equals(RXClass.GetClass(typeof(Leader)))
  13. ||
  14. rXClass.Equals(RXClass.GetClass(typeof(MLeader)))
  15. ||
  16. rXClass.Equals(RXClass.GetClass(typeof(Hatch)))                          
  17. )
Или можно как-то прогнать в цикле подставляя только список типов, а не писать кучу однотипных строк?

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

  • Administrator
  • *****
  • Сообщений: 13886
  • Карма: 1788
  • Рыцарь ObjectARX
  • Skype: rivilis
Есть одна, но существенная ошибка. Вместо:
Код - C# [Выбрать]
  1. rXClass.Equals(RXClass.GetClass(typeof(BlockTableRecord)))
должно быть
Код - C# [Выбрать]
  1. rXClass.Equals(RXClass.GetClass(typeof(BlockReference)))
Т.е. не описание блока, а вставка блока.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • ****
  • Сообщений: 270
  • Карма: 24
  • Геодезист
Есть одна, но существенная ошибка. Вместо:
Код - C# [Выбрать]
  1. rXClass.Equals(RXClass.GetClass(typeof(BlockTableRecord)))
должно быть
Код - C# [Выбрать]
  1. rXClass.Equals(RXClass.GetClass(typeof(BlockReference)))
Т.е. не описание блока, а вставка блока.

Не, тут всё верно, я создаю блоки программно на AutoLISP, и по умолчанию они создаются не аннотативными, и мне нужно включить им аннотативность. Причём при первом создании из AutoLISP можно задать аннотативнсоть, а вот сменить(иногда этот выбор даю пользователю, не все любят и умеют работать с аннотативными объектами) при редактировании описания блока, уже не получится, а эта функция позволяет теперь менять это свойство когда угодно .

А вот для вхождения поменять аннотативность как раз и нельзя.

Оффлайн trir

  • ADN Club
  • ****
  • Сообщений: 475
  • Карма: 63
можно сделать список типов и проверять наличие через any
Код - C# [Выбрать]
  1.             var list = new List<Type>
  2.             {
  3.                 typeof(string),
  4.                 typeof(int),
  5.                 typeof(double)
  6.             };
  7.             var t1 = 1;
  8.             float t2 = 1.1f;
  9.             var b1 = list.Any(t => t.Equals(t1.GetType()));
  10.             var b2 = list.Any(t => t.Equals(t2.GetType()));
думай функционально

и у тебя код повторяется - можно вынести в функцию
« Последнее редактирование: 16-04-2021, 07:52:47 от trir »

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 738
Записал видео с разбором кода:

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

  • ADN Club
  • ****
  • Сообщений: 270
  • Карма: 24
  • Геодезист
Записал видео с разбором кода:
Спасибо большое!

Зачем мы сначала получаем объект для чтения, а потом ещё раз для записи?

Код - C# [Выбрать]
  1. using (var tr = activeDocument.TransactionManager.StartTransaction())
  2.                     {
  3.                         var obj = tr.GetObject(annObjId, OpenMode.ForRead, false, true);
  4.                         if (obj != null && IsObjectAnnotation(obj))
  5.                         {
  6.                             flag = true;
  7.                             var objForWrite = tr.GetObject(annObjId, OpenMode.ForWrite, false, true);
  8.                             if (objForWrite != null)
  9.                             {
  10.                                 objForWrite.Annotative = add ? AnnotativeStates.False : AnnotativeStates.False;
  11.                             }
  12.                         }
  13.                         tr.Commit();                        
  14.                     }

Нельзя сразу открыть его на запись? Или типа когда на запись, то читать нельзя, можно только писать? Проверил только с ForWrite вроде работает

Код - C# [Выбрать]
  1. using (var tr = activeDocument.TransactionManager.StartTransaction())
  2.                     {
  3.                         var obj = tr.GetObject(annObjId, OpenMode.ForWrite, false, true);
  4.                         if (obj != null && IsObjectAnnotation(obj))
  5.                         {
  6.                             flag = true;                          
  7.                             obj.Annotative = add ? AnnotativeStates.False : AnnotativeStates.False;                            
  8.                         }
  9.                         tr.Commit();                        
  10.                     }

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 738
Зачем мы сначала получаем объект для чтения, а потом ещё раз для записи?
Ну, типа не открываем объект на запись без необходимости. На чтение быстрее открывается, при этом объект не блокируется для других "читателей". Но это уже тонкости, конечно.
Нельзя сразу открыть его на запись?
Можно и так, конечно. Но надо понимать, что если объект неподходящего типа, то было избыточное открытие его на запись. В 99% случаев, это, скорее всего, не приведёт ни к каким последствиям, кроме ухудшения быстродействия.
Или типа когда на запись, то читать нельзя, можно только писать?
Можно и писать и читать.

P.S. Если уж совсем по уму, то можно проверить тип объекта, не открывая его, по Id. Вот там как раз пригодятся RXClass и сравнение по ним. И тогда можно будет проверить тип объекта, и если он подходящий - сразу открывать на запись и изменять. Это было бы красивое решение, ятд.

P.P.S И ещё, в видео забыл сказать. Если у нас есть ObjectId, то из него мы можем получить Database и открыть транзакцию через неё. Не надо получать активный документ.

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

  • Administrator
  • *****
  • Сообщений: 13886
  • Карма: 1788
  • Рыцарь ObjectARX
  • Skype: rivilis
BearDyugin,
obj.Annotative = add ? AnnotativeStates.False : AnnotativeStates.False;   
???
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • ****
  • Сообщений: 270
  • Карма: 24
  • Геодезист
BearDyugin,
obj.Annotative = add ? AnnotativeStates.False : AnnotativeStates.False;   
???
Да там уже другой код, из видео Дмитрия, это его фрагмент, add это новый bool аргумент, чтоб один метод по нему либо добавлял либо удалял аннотатвиность.
Такая укороченная запись IF мне пока совсем не привычна, но для кратких записей очень удобно.

А ещё по последним Диминым замечаниям правки не внёс, как внесу опубликую полный текст нового кода.

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

  • Administrator
  • *****
  • Сообщений: 13886
  • Карма: 1788
  • Рыцарь ObjectARX
  • Skype: rivilis
BearDyugin,
Ты видимо не понял меня. Эта запись вне зависимости от значения add эквивалентна:
Код - C# [Выбрать]
  1. obj.Annotative = AnnotativeStates.False;
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • ****
  • Сообщений: 270
  • Карма: 24
  • Геодезист
BearDyugin,
Ты видимо не понял меня. Эта запись вне зависимости от значения add эквивалентна:
Код - C# [Выбрать]
  1. obj.Annotative = AnnotativeStates.False;

Да, точно опечатка, два раза false, я его пока не дописал и не тестировал больше.

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

  • ADN Club
  • ****
  • Сообщений: 270
  • Карма: 24
  • Геодезист
Вроде все замечания учёл, как избавится от flag не придумал
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.DatabaseServices;
  2. using Autodesk.AutoCAD.Runtime;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6.  
  7. namespace BD_Function
  8. {
  9.     public class LispFunctionsExtensions
  10.     {
  11.         [LispFunction(nameof(RemoveAnnotation))]
  12.         public bool RemoveAnnotation(ResultBuffer resBuf)
  13.         {
  14.             return SetAnnotation(resBuf, false);
  15.         }
  16.  
  17.         [LispFunction(nameof(AddAnnotation))]
  18.         public static bool AddAnnotation(ResultBuffer resBuf)
  19.         {
  20.             return SetAnnotation(resBuf, true);
  21.         }
  22.  
  23.         private static bool SetAnnotation(ResultBuffer resBuf, bool add)
  24.         {
  25.             if (resBuf == null)
  26.             {
  27.                 return false;
  28.             }
  29.  
  30.             var argArray = resBuf.AsArray();
  31.             var typedValue = argArray[0];
  32.  
  33.             if (typedValue.TypeCode != (short)LispDataType.ObjectId)
  34.             {
  35.                 return false;
  36.             }
  37.  
  38.             var annObjId = (ObjectId)typedValue.Value;
  39.  
  40.             if (IsObjectAnnotation(annObjId) == false)
  41.             {
  42.                 return false;
  43.             }
  44.            
  45.             bool flag;
  46.  
  47.             using (var tr = annObjId.Database.TransactionManager.StartTransaction())
  48.             {
  49.                 var obj = tr.GetObject(annObjId, OpenMode.ForWrite, false, true);
  50.                 if (flag = (obj != null))
  51.                 {
  52.                     obj.Annotative = add ? AnnotativeStates.True : AnnotativeStates.False;
  53.                 }
  54.                 tr.Commit();
  55.             }
  56.  
  57.             return flag;
  58.         }
  59.        
  60.         private static bool IsObjectAnnotation(ObjectId annObjId)
  61.         {
  62.             var list = new List<Type>
  63.             {
  64.                 typeof(DBText),
  65.                 typeof(BlockTableRecord),
  66.                 typeof(MText),
  67.                 typeof(Dimension),
  68.                 typeof(Leader),
  69.                 typeof(MLeader),
  70.                 typeof(Hatch)
  71.             };
  72.             return list.Any(t => annObjId.ObjectClass.Equals(RXObject.GetClass(t)));
  73.         }
  74.    
  75.     }
  76. }

Ещё в коде из статьи было добавление объекту текущего масштаба аннотации
Код - C# [Выбрать]
  1. // Добавляем текущий масштаб
  2.             string cannoscale = Application.GetSystemVariable("CANNOSCALE") as string;
  3.             obj.AddContext(occ.GetContext(cannoscale));

Проверил работает и без этого, при включении аннотативности, автоматом добавляется текущий масштаб. Может в старых версиях AutoCAD так не работало?

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

  • Administrator
  • *****
  • Сообщений: 13886
  • Карма: 1788
  • Рыцарь ObjectARX
  • Skype: rivilis
Не очень понятна эта проверка:
Код - C# [Выбрать]
  1.  if (flag = (obj != null))
obj не может стать равным null. Если предыдущая строка не сработает по каким-либо причинам, то возникнет исключение и дальнейший код выполняться не будет.
Может в старых версиях AutoCAD так не работало?
Точно не работало. И еще зависит от ANNOALLVISIBLE - если равно 0, то объекты, которые не поддерживают данный масштаб просто не будут видны.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • ****
  • Сообщений: 270
  • Карма: 24
  • Геодезист
Не очень понятна эта проверка:
Код - C# [Выбрать]
  1.  if (flag = (obj != null))
obj не может стать равным null. Если предыдущая строка не сработает по каким-либо причинам, то возникнет исключение и дальнейший код выполняться не будет.
Были такие мысли, спасибо, тогда нам и flag не нужен, после транзакции возвращаем true.

Может в старых версиях AutoCAD так не работало?
Точно не работало.
Получается для всех объектов кроме BlockTableRecord надо добавить текущий масштаб, а для BlockTableRecord найти уже все BlockReference и добавить масштаб им?

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 738
obj не может стать равным null
Вроде, если объект будет удалён, то вернёт null. Хотя, вероятность того, что в лисп-функцию прилетит удалённый объект, крайне мала.