Выбор вложенных объектов секущей рамкой в Autocad через .NET

Автор Тема: Выбор вложенных объектов секущей рамкой в Autocad через .NET  (Прочитано 15169 раз)

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

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

Оффлайн Кирилл ЗахаровАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 119
  • Карма: 5
Здравствуйте!
Я пытаюсь разобраться, как можно сделать выбор множества объектов, вложенных во внешнюю ссылку, секущей рамкой.
Я видел сообщения Александра Ривилиса на эту тему на форуме Autodesk Community: https://forums.autodesk.com/t5/net/selection-of-multiple-nested-entities/td-p/3750848?nobounce.
Он пишет, что можно использовать P/Invoke чтобы вызвать соответствующую функцию ObjectARX. У меня пока не хватает знаний, чтобы разобраться до конца как это делается, но я нашел еще один интересный пример на эту тему: http://adndevblog.typepad.com/autocad/2012/04/retrieving-nested-entities-under-cursor-aperture-using-net-api.html.
Используя этот пример, я попытался сделать выбор вложенных объектов рамкой, но пока не преуспел. Думаю, что я близок к решению. Привожу свой код:
Код - 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 System.Runtime.InteropServices;
  8.  
  9.  
  10. [assembly: CommandClass(typeof(Multiply_Nested_Select_Test.MyCommands))]
  11.  
  12. namespace Multiply_Nested_Select_Test
  13. {
  14.     public class MyCommands
  15.     {
  16.  
  17.  
  18.         [CommandMethod("SelectNestedTest", CommandFlags.Modal)]
  19.         public void MyCommand()
  20.         {
  21.             Document doc = Application.DocumentManager.MdiActiveDocument;
  22.             Editor ed = doc.Editor;
  23.             Database db = doc.Database;
  24.             XrefGraph xg = db.GetHostDwgXrefGraph(true);
  25.  
  26.             Point3d pt1 = new Point3d();
  27.             Point3d pt2 = new Point3d();
  28.             using (Transaction tr = db.TransactionManager.StartTransaction())
  29.             {
  30.                 SpecifySelectionWindow(out pt1, out pt2, db, ed);//Это метод для задания секущей рамки
  31.                 /////////////////////////////////////////////////////////////////////////////
  32.                 //Код выбора вложенных объектов рамкой
  33.  
  34.                 ResultBuffer resbuf = new ResultBuffer();
  35.  
  36.                 string arg = "_N:D";
  37.  
  38.                 IntPtr ptrPoint1 = Marshal.UnsafeAddrOfPinnedArrayElement(
  39.                     pt1.ToArray(), 0);
  40.                 IntPtr ptrPoint2 = Marshal.UnsafeAddrOfPinnedArrayElement(
  41.                     pt2.ToArray(), 0);
  42.  
  43.                 ArxImports.ads_name sset;
  44.  
  45.                 PromptStatus prGetResult = ArxImports.acedSSGet(
  46.                     arg, ptrPoint1, ptrPoint2, resbuf.UnmanagedObject, out sset);
  47.  
  48.                 int len;
  49.                 ArxImports.acedSSLength(ref sset, out len);
  50.                 ed.WriteMessage("\n" + len.ToString());
  51.                 /////////////////////////////////////////////////////////////////////////////
  52.                 tr.Commit();
  53.             }
  54.  
  55.            
  56.         }
  57.  
  58.         private static bool SpecifySelectionWindow(out Point3d pt1, out Point3d pt2, Database db, Editor adocEd)
  59.         {
  60.             pt1 = new Point3d();
  61.             pt2 = new Point3d();
  62.             Transaction tr = db.TransactionManager.StartTransaction();
  63.             using (tr)
  64.             {
  65.                 try
  66.                 {
  67.  
  68.                     PromptPointOptions ppo = new PromptPointOptions("\n\tSpecify a first corner: ");
  69.                     PromptPointResult ppr = adocEd.GetPoint(ppo);
  70.                     if (ppr.Status != PromptStatus.OK) return false;
  71.                     PromptCornerOptions pco = new PromptCornerOptions("\n\tOther corner: ", ppr.Value);
  72.                     PromptPointResult pcr = adocEd.GetCorner(pco);
  73.                     if (pcr.Status != PromptStatus.OK) return false;
  74.                     pt1 = ppr.Value;
  75.                     pt2 = pcr.Value;
  76.                     if (pt1.X == pt2.X || pt1.Y == pt2.Y)
  77.                     {
  78.                         adocEd.WriteMessage("\nInvalid point specification");
  79.                         return false;
  80.                     }
  81.  
  82.                     tr.Commit();
  83.                     return true;
  84.                 }
  85.                 catch (System.Exception ex)
  86.                 {
  87.                     adocEd.WriteMessage(ex.Message + "\n" + ex.StackTrace);
  88.                     return false;
  89.                 }
  90.             }
  91.         }
  92.  
  93.  
  94.     }
  95. //Класс в котором задаются методы для доступа к функциям ObjectARX, который я взял из примера
  96. class ArxImports
  97.     {
  98.         public struct ads_name
  99.         {
  100.             public IntPtr a;
  101.             public IntPtr b;
  102.         };
  103.  
  104.         [StructLayout(LayoutKind.Sequential, Size = 32)]
  105.         public struct resbuf { }
  106.  
  107.         [DllImport("accore.dll",
  108.             CallingConvention = CallingConvention.Cdecl,
  109.             CharSet = CharSet.Unicode,
  110.             ExactSpelling = true)]
  111.         public static extern PromptStatus acedSSGet(
  112.             string str, IntPtr pt1, IntPtr pt2,
  113.             IntPtr filter, out ads_name ss);
  114.  
  115.         [DllImport("accore.dll",
  116.             CallingConvention = CallingConvention.Cdecl,
  117.             CharSet = CharSet.Unicode,
  118.             ExactSpelling = true)]
  119.         public static extern PromptStatus acedSSFree(ref ads_name ss);
  120.  
  121.         [DllImport("accore.dll",
  122.             CallingConvention = CallingConvention.Cdecl,
  123.             CharSet = CharSet.Unicode,
  124.             ExactSpelling = true)]
  125.         public static extern PromptStatus acedSSLength(
  126.             ref ads_name ss, out int len);
  127.  
  128.         [DllImport("accore.dll",
  129.             CallingConvention = CallingConvention.Cdecl,
  130.             CharSet = CharSet.Unicode,
  131.             ExactSpelling = true)]
  132.         public unsafe static extern PromptStatus acedSSNameX(
  133.             resbuf** rbpp, ref ads_name ss, int i);
  134.        
  135.     }
  136.  
  137. }
  138.  

При использовании этого кода не выбирается ни одного объекта. Я думаю, мне нужно каким-то образом осуществить выполнение следующих функций ObjectARX:

Код - C++ [Выбрать]
  1. // switch on the multi selection of nested entities
  2. setAllowDuplicateSelection(curDoc(), true);  
  3. curDoc()->inputPointManager()->turnOnSubentityWindowSelection();
  4.  
(Взято из примера http://adndevblog.typepad.com/autocad/2012/08/acedssget-multi-select-in-n-mode.html)

Подскажите, пожалуйста, как можно решить эту проблему.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Код - C++ [Выбрать]
  1. curDoc()->inputPointManager()->turnOnSubentityWindowSelection();
эквивалентно
Код - C# [Выбрать]
  1. Application.DocumentManager.MdiActiveDocument.Editor.TurnSubentityWindowSelectionOn;
Код - C++ [Выбрать]
  1. curDoc()->inputPointManager()->turnOffSubentityWindowSelection();
эквивалентно
Код - C# [Выбрать]
  1. Application.DocumentManager.MdiActiveDocument.Editor.TurnSubentityWindowSelectionOff;
По поводу
Код - C++ [Выбрать]
  1. setAllowDuplicateSelection(curDoc(), true);
нужно посмотреть.

P.S.: Хотя я совсем не уверен, что это будет работать с внешними ссылками. Nested object - это вложенные объекты и обычно под этим подразумеваются объекты в блоках, а не во внешних ссылках.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
P.S.: Убери из SpecifySelectionWindow всякое упоминание о транзакциях. Они там совершенно не нужны. Да и в MyCommand тоже.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Кирилл ЗахаровАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 119
  • Карма: 5
Да, это косяк с транзакцией) Спасибо за подсказки!

Оффлайн trir

  • ADN Club
  • ****
  • Сообщений: 470
  • Карма: 63
А в результате, что должно получится?

Оффлайн Кирилл ЗахаровАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 119
  • Карма: 5
Напишу когда и если получится

Оффлайн trir

  • ADN Club
  • ****
  • Сообщений: 470
  • Карма: 63
Ты пытаешься получить не существующие объекты

Оффлайн Кирилл ЗахаровАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 119
  • Карма: 5
Ты пытаешься получить не существующие объекты

Вы не правы. Объекты внешних ссылок присутствуют в базе данных чертежа так же как и объекты внутри блоков. И доступ к ним осуществляется аналогично.
Отсылаю вас к замечательной программе на лиспе, на которую я наткнулся однажды: http://lee-mac.com/nestedmove.html.
Посмотрите на анимацию, демонстрирующую работу программы. Все именно так и работает.

Оффлайн trir

  • ADN Club
  • ****
  • Сообщений: 470
  • Карма: 63
неа, они в разных Database

Оффлайн Кирилл ЗахаровАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 119
  • Карма: 5
Не буду с вами спорить

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Код - C# [Выбрать]
  1.     [DllImport("accore.dll",
  2.         EntryPoint = "?setAllowDuplicateSelection@@YA?AW4ErrorStatus@Acad@@PAVAcApDocument@@E@Z",
  3.         CallingConvention = CallingConvention.Cdecl,
  4.         CharSet = CharSet.Unicode)]
  5.     public static extern Int32 setAllowDuplicateSelection32(IntPtr doc, [MarshalAs(UnmanagedType.I1)] bool bset);
  6.  
  7.     [DllImport("accore.dll",
  8.         EntryPoint = "?setAllowDuplicateSelection@@YA?AW4ErrorStatus@Acad@@PEAVAcApDocument@@E@Z",
  9.         CallingConvention = CallingConvention.Cdecl,
  10.         CharSet = CharSet.Unicode)]
  11.     public static extern Int32 setAllowDuplicateSelection64(IntPtr doc, [MarshalAs(UnmanagedType.I1)] bool bset);
  12.     public static Int32 setAllowDuplicateSelection(Document doc, bool bset)
  13.     {
  14.       if (IntPtr.Size == 8)
  15.         return setAllowDuplicateSelection64(doc.UnmanagedObject, bset);
  16.       else
  17.         return setAllowDuplicateSelection32(doc.UnmanagedObject, bset);
  18.     }
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Отмечено как Решение Кирилл Захаров 15-03-2017, 00:13:26

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Я посмотрел что ты хочешь и понимаю, что у тебя таким образом ничего не получится. Увы. Т.е. задать точки и вызвать acedSSGet(L"_C",...) (это аналог Editor.SelectCrossingWindow в ObjectARX) и при этом получить вложенные примитивы (даже внутри одной базы, а уж тем более из Xref) нельзя. Этот метод не позволяет получить вложенные объекты. Можно только так:

Код - 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 System.Runtime.InteropServices;
  8.  
  9.  
  10. [assembly: CommandClass(typeof(Multiply_Nested_Select_Test.MyCommands))]
  11.  
  12. namespace Multiply_Nested_Select_Test
  13. {
  14.   public class MyCommands
  15.   {
  16.     [CommandMethod("SelectNestedTest", CommandFlags.Modal)]
  17.     public void MyCommand()
  18.     {
  19.       Document doc = Application.DocumentManager.MdiActiveDocument;
  20.       Editor ed = doc.Editor;
  21.       Database db = doc.Database;
  22.  
  23.       ResultBuffer resbuf = new ResultBuffer();
  24.  
  25.       string arg = "_:D:N";
  26.  
  27.       ArxImports.ads_name sset;
  28.       ed.TurnSubentityWindowSelectionOn();
  29.       ArxImports.setAllowDuplicateSelection(doc, true);
  30.       PromptStatus prGetResult = ArxImports.acedSSGet(
  31.           arg, IntPtr.Zero /* ptrPoint1 */, IntPtr.Zero /* ptrPoint2 */, resbuf.UnmanagedObject, out sset);
  32.       int len;
  33.       ArxImports.setAllowDuplicateSelection(doc, false);
  34.       ed.TurnSubentityWindowSelectionOff();
  35.       ArxImports.acedSSLength(ref sset, out len);
  36.       ed.WriteMessage("\n" + len.ToString());
  37.       /////////////////////////////////////////////////////////////////////////////
  38.     }
  39.   }
  40.   //Класс в котором задаются методы для доступа к функциям ObjectARX, который я взял из примера
  41.   class ArxImports
  42.   {
  43.     public struct ads_name
  44.     {
  45.       public IntPtr a;
  46.       public IntPtr b;
  47.     };
  48.  
  49.     [StructLayout(LayoutKind.Sequential, Size = 32)]
  50.     public struct resbuf { }
  51.  
  52.     [DllImport("accore.dll",
  53.         CallingConvention = CallingConvention.Cdecl,
  54.         CharSet = CharSet.Unicode,
  55.         ExactSpelling = true)]
  56.     public static extern PromptStatus acedSSGet(
  57.         string str, IntPtr pt1, IntPtr pt2,
  58.         IntPtr filter, out ads_name ss);
  59.  
  60.     [DllImport("accore.dll",
  61.         CallingConvention = CallingConvention.Cdecl,
  62.         CharSet = CharSet.Unicode,
  63.         ExactSpelling = true)]
  64.     public static extern PromptStatus acedSSFree(ref ads_name ss);
  65.  
  66.     [DllImport("accore.dll",
  67.         CallingConvention = CallingConvention.Cdecl,
  68.         CharSet = CharSet.Unicode,
  69.         ExactSpelling = true)]
  70.     public static extern PromptStatus acedSSLength(
  71.         ref ads_name ss, out int len);
  72.  
  73.     [DllImport("accore.dll",
  74.         CallingConvention = CallingConvention.Cdecl,
  75.         CharSet = CharSet.Unicode,
  76.         ExactSpelling = true)]
  77.     public unsafe static extern PromptStatus acedSSNameX(
  78.         resbuf** rbpp, ref ads_name ss, int i);
  79.  
  80.     [DllImport("accore.dll",
  81.         EntryPoint = "?setAllowDuplicateSelection@@YA?AW4ErrorStatus@Acad@@PAVAcApDocument@@E@Z",
  82.         CallingConvention = CallingConvention.Cdecl,
  83.         CharSet = CharSet.Unicode)]
  84.     public static extern Int32 setAllowDuplicateSelection32(IntPtr doc, [MarshalAs(UnmanagedType.I1)] bool bset);
  85.  
  86.     [DllImport("accore.dll",
  87.         EntryPoint = "?setAllowDuplicateSelection@@YA?AW4ErrorStatus@Acad@@PEAVAcApDocument@@E@Z",
  88.         CallingConvention = CallingConvention.Cdecl,
  89.         CharSet = CharSet.Unicode)]
  90.     public static extern Int32 setAllowDuplicateSelection64(IntPtr doc, [MarshalAs(UnmanagedType.I1)] bool bset);
  91.     public static Int32 setAllowDuplicateSelection(Document doc, bool bset)
  92.     {
  93.       if (IntPtr.Size == 8)
  94.         return setAllowDuplicateSelection64(doc.UnmanagedObject, bset);
  95.       else
  96.         return setAllowDuplicateSelection32(doc.UnmanagedObject, bset);
  97.     }
  98.   }
  99. }

При этом ты можешь выбирать объекты не только по одному, но и рамкой:

« Последнее редактирование: 15-03-2017, 02:42:57 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Кирилл ЗахаровАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 119
  • Карма: 5
Спасибо огромное, Александр!

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Кирилл Захаров,
Хочешь сказать, что это тебя устраивает? Вообще-то это совсем не то, что ты спрашивал.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Кирилл ЗахаровАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 119
  • Карма: 5
Да, но я могу это использовать. С помощью добавления буквы S к строке selection mode я обеспечу чтобы пользователь мог только 1 раз либо выбрать рамкой либо одиночным кликом. Затем каким-нибудь образом проверю, что выбор сделан именно рамкой (пока не знаю как) и если выбор сделан неправильно буду возвращаться в цикле обратно.
Главная цель достигнута.