Как добавить Inspection для dimension'а в .net

Автор Тема: Как добавить Inspection для dimension'а в .net  (Прочитано 7863 раз)

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

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

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

  • ADN OPEN
  • Сообщений: 39
  • Карма: 0
Добрый день.
На dwg.ru порекомендовали написать сюда.
Возникла необходимость программно создать Aligned Dimension, у которого добавить Inspection с некоторой информацией как показано во вложении. Сделать это нужно из проекта написанного на C#. В интернете есть статья на эту тему ( http://through-the-interface.typepad.com/through_the_interface/2008/09/more-quiet-comm.html ), но там предлагается делать это с помощью команд. Такой подход не устраивает. Как можно сделать это без использования команд?

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Как добавить Inspection для dimension'а в .net
« Ответ #1 : 14-11-2014, 13:06:59 »
но там предлагается делать это с помощью команд. Такой подход не устраивает.
Можно уточнить почему не устраивает?
У меня появилась пара идей, которые не реализованы в виде кода, но кажется позволят избавится от командных методов.
P.S.: Приветствую на форуме!  :)

Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN OPEN
  • Сообщений: 39
  • Карма: 0
Re: Как добавить Inspection для dimension'а в .net
« Ответ #2 : 14-11-2014, 13:14:45 »
Не устраивает в основном из-за того, что указанный в статье метод устанавливает 3 секции для dimension'а, а нужно именно 2 секции (как на рисунке). Если указать вместо него пустую строку, он выставляется по умолчанию в значение "100%", а если опустить вовсе, то будет ошибка в синтаксисе команды.
Второе что смущает - скорость, а таких dimension'ов надо будет генерировать не менее сотни, а то и больше, и с помощью команд это будет явно дольше чем с помощью API. И третий момент в том, что остаётся куча команд,  что мешает если нужно сделать undo. Т.е. если dimnesion'ов было 100, то если что-то было сделано не так до их генерации, то теоретически отменять 100 действий, но с этим вопросом не разбирался как следует, т.к. первые два фактора намного важнее.
:)
Спасибо за помощь

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Как добавить Inspection для dimension'а в .net
« Ответ #3 : 14-11-2014, 13:58:00 »
Я тоже поигрался с командой -DIMINSPECT и мне не удалось задать такое значение, чтобы было только две секции. Будем считать, что ты меня убедил и перейдем к некомандным методам.
В AutoCAD .NET API так и не появилось методов для работы с DIMINSPECT, о чем Киан писал у себя в блоге. Поэтому возможны три варианта:
1) Написать это на чистом ObjectARX - там есть такая возможность. Если нужно будет описание - помогу.
2) Попытаться вызвать методы ObjectARX при помощи P/Invoke из .NET - не уверен, что это будет просто и не уверен, что эти методы не виртуальные и тогда добраться до них будет совсем не просто и уж явно зависеть от версии и разрядности AutoCAD.
3) Обратить внимание на то, что DIMINSPECT работает с расширенными данными размера:
 
Ну и начать плясать от этого. Возможно последний способ будет самым простым. Нужно только разобраться со структурой расширенных данных приложения ACAD_DSTYLE_DIMINSPECT
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Отмечено как Решение MikhailTAP 15-11-2014, 05:37:44

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Как добавить Inspection для dimension'а в .net
« Ответ #4 : 14-11-2014, 18:42:32 »
В результате получился вот такой код. И как ни странно - работает. :)
Код - 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. using AcRx = Autodesk.AutoCAD.Runtime;
  8. using AcAp = Autodesk.AutoCAD.ApplicationServices;
  9. using AcDb = Autodesk.AutoCAD.DatabaseServices;
  10. using AcGe = Autodesk.AutoCAD.Geometry;
  11. using AcEd = Autodesk.AutoCAD.EditorInput;
  12.  
  13. [assembly: CommandClass(typeof(DimInspect.Utils))]
  14.  
  15. namespace DimInspect
  16. {
  17.   public class Utils
  18.   {
  19.     [CommandMethod("AddInspect", CommandFlags.Modal)]
  20.     public void AddInspect()
  21.     {
  22.       AcAp.Document doc = AcAp.Application.DocumentManager.MdiActiveDocument;
  23.       if (doc == null) return;
  24.       AcEd.Editor ed = doc.Editor;
  25.       AcDb.Database db = doc.Database;
  26.       // Сначала убедимся, что есть имя приложения ACAD_DSTYLE_DIMINSPECT
  27.       // Если его нет, то его нужно создать и добавить в Таблицу приложений
  28.       using (AcDb.RegAppTable regTab = db.RegAppTableId.Open(AcDb.OpenMode.ForRead) as AcDb.RegAppTable)
  29.       {
  30.         if (!regTab.Has("ACAD_DSTYLE_DIMINSPECT"))
  31.         {
  32.           using (AcDb.RegAppTableRecord regInsp = new AcDb.RegAppTableRecord())
  33.           {
  34.             regInsp.Name = "ACAD_DSTYLE_DIMINSPECT";
  35.             regTab.UpgradeOpen();
  36.             regTab.Add(regInsp);
  37.           }
  38.         }
  39.       }
  40.       while (true)
  41.       {
  42.         // Запрашиваем имя примитива размера
  43.         AcEd.PromptEntityOptions prEnt =
  44.           new AcEd.PromptEntityOptions("\nУкажите размер (ENTER - завершение): ");
  45.         prEnt.SetRejectMessage("\nЭто не размер!");
  46.         prEnt.AddAllowedClass(typeof(AcDb.Dimension), false);
  47.         prEnt.AllowNone = true;
  48.         AcEd.PromptEntityResult resEnt = ed.GetEntity(prEnt);
  49.         if (resEnt.Status != AcEd.PromptStatus.OK)
  50.           break;
  51.         // Запрашиваем Метку контроля
  52.         AcEd.PromptStringOptions prStr =
  53.           new AcEd.PromptStringOptions("\nУкажите метку контроля: ");
  54.         AcEd.PromptResult resStr = ed.GetString(prStr);
  55.         if (resStr.Status != AcEd.PromptStatus.OK)
  56.           break;
  57.         // Запрашиваем Процент контроля
  58.         AcEd.PromptIntegerOptions prCtl =
  59.           new AcEd.PromptIntegerOptions("\nУкажите процент контроля (-1 - без процента контроля) <-1>: ");
  60.         prCtl.DefaultValue = -1;
  61.         prCtl.AllowNone = true;
  62.         AcEd.PromptIntegerResult resCtl = ed.GetInteger(prCtl);
  63.         if (resCtl.Status != AcEd.PromptStatus.OK && resCtl.Status != AcEd.PromptStatus.None)
  64.           break;
  65.         string prcCtl = (resCtl.Value == -1) ? "" : (Math.Abs(resCtl.Value) % 100).ToString() + "%";
  66.         // Теперь разберёмся с Размером
  67.         using (AcDb.Dimension dim = resEnt.ObjectId.Open(AcDb.OpenMode.ForWrite) as AcDb.Dimension)
  68.         {
  69.           AcDb.ResultBuffer xdataInspect = new AcDb.ResultBuffer(
  70.             new AcDb.TypedValue((int)AcDb.DxfCode.ExtendedDataRegAppName, "ACAD_DSTYLE_DIMINSPECT"),
  71.             // Главный флаг DIMINSPECT
  72.             new AcDb.TypedValue((int)AcDb.DxfCode.ExtendedDataInteger16, 393),
  73.             // 0 - нет Inspect, 1 - есть Inspect
  74.             new AcDb.TypedValue((int)AcDb.DxfCode.ExtendedDataInteger16, 1),
  75.             // Это общие флаги DIMINSPECT
  76.             new AcDb.TypedValue((int)AcDb.DxfCode.ExtendedDataInteger16, 394),
  77.             // Это флаги - нужно расшифровывать:
  78.             //  1 - Круглая рамка
  79.             //  2 - Угловая рамка
  80.             //  4 - Без рамки
  81.             // 16 - Метка контроля есть
  82.             // 32 - Процент контроля есть
  83.             new AcDb.TypedValue((int)AcDb.DxfCode.ExtendedDataInteger16,
  84.               1 + // Всегда овальная рамка
  85.               (resStr.StringResult.Length == 0 ? 0 : 16) + // Флаг метки контроля
  86.               (prcCtl.Length == 0 ? 0 : 32) // Флаг процента контроля
  87.             ),
  88.             // Это Метка контроля
  89.             new AcDb.TypedValue((int)AcDb.DxfCode.ExtendedDataInteger16, 395),
  90.             new AcDb.TypedValue((int)AcDb.DxfCode.ExtendedDataAsciiString, resStr.StringResult),
  91.             // Это Процент контроля
  92.             new AcDb.TypedValue((int)AcDb.DxfCode.ExtendedDataInteger16, 396),
  93.             new AcDb.TypedValue((int)AcDb.DxfCode.ExtendedDataAsciiString, prcCtl)
  94.           );
  95.           dim.XData = xdataInspect;
  96.         }
  97.       }
  98.     }
  99.   }
  100. }
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN OPEN
  • Сообщений: 39
  • Карма: 0
Re: Как добавить Inspection для dimension'а в .net
« Ответ #5 : 15-11-2014, 05:39:27 »
Александр, спасибо огромное за помощь, всё работает. А можно подробнее у Вас узнать по первым двум способам. Хотя бы в общих чертах?
PS
Поделитесь пожалуйста опытом, как Вы сделали что бы в Debug'е отображался текст? Давно мучаюсь с этой проблемой:)
« Последнее редактирование: 15-11-2014, 08:44:23 от MikhailTAP »

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Как добавить Inspection для dimension'а в .net
« Ответ #6 : 15-11-2014, 11:31:46 »
Александр, спасибо огромное за помощь, всё работает.
Отлично!
А можно подробнее у Вас узнать по первым двум способам. Хотя бы в общих чертах?
Можно.

Первый способ - это чистый ObjectARX (т.е. C++). Заглядываем в файл inc\dbdim.h из состава ObjectARX SDK и видим следующие методы класса AcDbDimension (перевод и добавление комментариев моё):
 
Код - C++ [Выбрать]
  1.    enum DimInspect {
  2.         kShapeRemove  = 0,     // Not displayed - не показывать
  3.         kShapeRound   = 1,     // Rounded end (default) - круглая рамка
  4.         kShapeAngular = 2,     // Angular end - угловая рамка
  5.         kShapeNone    = 4,     // No bounding shape - без рамки
  6.         kShapeLabel   = 0x10,  // Label separator and alpha field displayed - показывать отдельно метку
  7.         kShapeRate    = 0x20,  // Shape separator and alpha field displayed - показывать отдельно проценты
  8.     };
  9.     bool inspection() const; // Включено Inspect?
  10.     Acad::ErrorStatus setInspection(bool val); // Включить/выключить Inspect
  11.  
  12.     int inspectionFrame() const; // Вид рамки
  13.     Acad::ErrorStatus setInspectionFrame(int frame); // Установить вид рамки
  14.  
  15.     const ACHAR* inspectionLabel() const; // Метка
  16.     Acad::ErrorStatus setInspectionLabel(const ACHAR* label); // Установить метку
  17.  
  18.     const ACHAR* inspectionRate() const; // Процент
  19.     Acad::ErrorStatus setInspectionRate(const ACHAR* label); // Установить процент
Как я догадываюсь все эти методы в конечном итоге тоже работают с расширенными данными по аналогии с тем, что я написал.
Второй способ, это вызвать эти же методы из .NET при помощи P/Invoke. Примеры использования P/Invoke в AutoCAD: http://adn-cis.org/search.html?query=DllImport
Например для вызова метода AcDbDimension::setInspection нужно записать что-то типа (за точность не ручаюсь - не проверял):
Код - C# [Выбрать]
  1. // Для AutoCAD 2013 и 2014 - "acdb19.dll", для AutoCAD 2015 - "acdb20.dll"
  2. [DllImport("acdb20.dll", CallingConvention = CallingConvention.ThisCall,
  3. CharSet = CharSet.Unicode,
  4. EntryPoint = "?setInspection@AcDbDimension@@QEAA?AW4ErrorStatus@Acad@@_N@Z")]
  5. private static extern int setInspection64(IntPtr ths, bool bInspection);
И если dim - экземпляр класса Dimension, то
Код - C# [Выбрать]
  1. setInspection64(dim.UnmanagedObject, true);
включит для этого размера Inspection.
Как видишь описание этой функции зависит от версии и разрядности (32/64) AutoCAD
« Последнее редактирование: 15-11-2014, 18:20:55 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Как добавить Inspection для dimension'а в .net
« Ответ #7 : 15-11-2014, 11:37:06 »
Поделитесь пожалуйста опытом, как Вы сделали что бы в Debug'е отображался текст? Давно мучаюсь с этой проблемой:)
Не понял. О чем речь? Об использовании VS 2013 и пропадании текстов в отладчике? Тогда почитай:
http://adn-cis.org/forum/index.php?topic=1019
http://through-the-interface.typepad.com/through_the_interface/2013/11/debugging-autocad-using-visual-studio-2013.html
Если это не оно, то объясни с указанием разрядности и версии AutoCAD и версии Visual Studio.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение