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

ADN Club => AutoCAD .NET API => Тема начата: Дмитрий Загорулькин от 01-04-2019, 20:20:35

Название: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Дмитрий Загорулькин от 01-04-2019, 20:20:35
Здравствуйте!
Столкнулся со странным поведением метода - возвращает PromptStatus.Error. Количество точек, правда, зашкаливает - больше тысячи. Может ли это быть причиной того, что метод не хочет работать? Есть ли какое-то ограничение у него на количество точек?
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Александр Ривилис от 01-04-2019, 20:23:11
Количество точек, правда, зашкаливает - больше тысячи. Может ли это быть причиной того, что метод не хочет работать? Есть ли какое-то ограничение у него на количество точек?
Официально точно никаких ограничений нет. Я бы предположил самопересечение контура (или касание его ребер).
P.S.: Надеюсь, что ты проверил, что все точки полигона в видимой области AutoCAD, так как PromptStatus.Error означает, что ничего не выбрано.
Можно еще попробовать проанализировать системную переменную ERRNO.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Дмитрий Загорулькин от 01-04-2019, 20:45:40
Хм, а точек даже меньше тысячи...
Прикладываю контур.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Привалов Дмитрий от 02-04-2019, 09:18:56
Прикладываю контур.
1. Как был получен контур? У тебя участки(сегменты) между вершинами не прямолинейные. см. между 1 и 2 вершиной еще одна точка лежащая на дуге ;-)
1.1 Возможно SelectCrossingPolygon не любит радиусы вообще.
1.2 Радиусы сегментов похоже заданы не корректно, pltools пишет радиус 25900 не знаю каких единиц.
2. Ну и на всякий случай проверь, что зуммирование экрана сработало как надо, перед вызовом Editor.SelectCrossingPolygon.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Дмитрий Загорулькин от 02-04-2019, 09:41:48
Контур построен с помощью оффсета от трассы проектируемой дороги или сети.
Конечно же кривые не любит. Он зараза такая вообще про них не в курсе - только коллекцию точек принимает :).
С радиусами там всё верно. При таком радиусе кривая становится почти прямой, что и наблюдается местами.
Я из этого контура вытягиваю коллекцию вершин и передаю в метод.
На самом деле, задачу уже решил с помощью PLTools - упростил, спрямил, прополол. В итоге с 390 точками метод справился. Теперь остался только спортивный интерес - почему этот исходный контур не обработался?
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Привалов Дмитрий от 02-04-2019, 10:10:55
Я из этого контура вытягиваю коллекцию вершин и передаю в метод.
Возможно тебе нужно добавить замыкающую вершину, т.к. полилиния была замкнута, а ты передаешь массив вершин, и получаешь разрыв контура. Т.е. в конце массива добавить точку с координатами 1й точки.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Дмитрий Загорулькин от 02-04-2019, 11:57:04
Я понял. Пример кода - лучше тысячи слов! :)
В приложенном файле чёрный контур - исходный, красный - полученный из исходного преобразованием дуг в прямые. Оба выдают ошибку с кодом 2: Invalid entity or selection set name (https://knowledge.autodesk.com/search-result/caas/CloudHelp/cloudhelp/2017/ENU/AutoCAD-AutoLISP/files/GUID-97327347-2A13-4CBC-BDBF-979C7F1CABD5-htm.html).
Код - C# [Выбрать]
  1. [CommandMethod("TestCrossingPolygonSelection")]
  2. public void TestCrossingPolygonSelectionCmd()
  3. {
  4.     Document adoc = Application.DocumentManager.MdiActiveDocument;
  5.     Editor ed = adoc.Editor;
  6.  
  7.     PromptEntityOptions plineOpt = new PromptEntityOptions
  8.         ("\nВыберите полилинию-контур: ");
  9.  
  10.     plineOpt.SetRejectMessage("\nЭто не полилиния!");
  11.     plineOpt.AddAllowedClass(typeof(Polyline), true);
  12.     PromptEntityResult plineRes = ed.GetEntity(plineOpt);
  13.     if (plineRes.Status != PromptStatus.OK) return;
  14.  
  15.     Point3dCollection pts = new Point3dCollection();
  16.  
  17. #pragma warning disable CS0618 // Type or member is obsolete
  18.     using (Polyline pline = plineRes.ObjectId.Open(OpenMode.ForRead) as Polyline)
  19. #pragma warning restore CS0618 // Type or member is obsolete
  20.     {
  21.         for (int i = 0; i < pline.NumberOfVertices; i++)
  22.         {
  23.             pts.Add(pline.GetPoint3dAt(i));
  24.         }
  25.     }
  26.  
  27.     if (!pts[0].IsEqualTo(pts[pts.Count - 1]))
  28.     {
  29.         pts.Add(pts[0]);
  30.     }
  31.  
  32.     PromptSelectionResult selRes = ed.SelectCrossingPolygon(pts);
  33.     if (selRes.Status == PromptStatus.Error)
  34.     {
  35.         short code = (short)Application.GetSystemVariable("ERRNO");
  36.         Application.ShowAlertDialog($"Ошибка: {code}");
  37.         return;
  38.     }
  39. }
  40.  
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Привалов Дмитрий от 02-04-2019, 12:13:00
Пример кода - лучше тысячи слов!
а где зуммирование вида, чтобы весь контур входил в экран? ;-)
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Привалов Дмитрий от 02-04-2019, 12:20:14
Пример кода - лучше тысячи слов!
а где зуммирование вида, чтобы весь контур входил в экран? ;-)

чет типа такого, перед вызовом SelectCrossingPolygon и аналогичных методов из Editor
иначе он возвращает ошибку:

Код - C# [Выбрать]
  1. //Зуммирование вида
  2. Point2d min2d = new Point2d(MinX, MinY);
  3. Point2d max2d = new Point2d(MaxX, MaxY);
  4. ViewTableRecord view = new ViewTableRecord();
  5. view.CenterPoint = min2d + ((max2d - min2d) / 2.0);
  6. view.Height = max2d.Y - min2d.Y;
  7. view.Width = max2d.X - min2d.X;
  8. ed.SetCurrentView(view);
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Дмитрий Загорулькин от 02-04-2019, 12:26:58
В боевом коде есть. В тестовом - это лишнее нагромождение. Можно же просто зуммировать перед запуском команды. Тут дело 100% не в зуме.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Дмитрий Загорулькин от 02-04-2019, 12:34:03
Я бы предположил самопересечение контура (или касание его ребер).
Всё, нашел - была одна совпадающая вершина. Вы оказались правы.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Александр Ривилис от 02-04-2019, 12:39:41
Я бы предположил самопересечение контура (или касание его ребер).
Всё, нашел - была одна совпадающая вершина. Вы оказались правы.
Я уже как раз начинал тестировать, но ты успел раньше. :) Кстати, в AutoCAD 2020, на котором я начал тестировать, при selRes.Status == PromptStatus.Error системная переменная ERRNO остаётся равной 0, что не есть хорошо...
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Привалов Дмитрий от 02-04-2019, 13:10:59
Кстати, в AutoCAD 2020, на котором я начал тестировать
Ну хот в кратце, по секрету можно нам рассказать. Значимые изменения будут от 2019?
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Александр Ривилис от 02-04-2019, 13:26:16
Кстати, в AutoCAD 2020, на котором я начал тестировать
Ну хот в кратце, по секрету можно нам рассказать. Значимые изменения будут от 2019?
Эта версия уже официально вышла и уже есть её анонсы. Например, в первую очередь для программистов, здесь: https://adndevblog.typepad.com/autocad/2019/03/autocad-2020-quick-overview.html
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Дмитрий Загорулькин от 02-04-2019, 14:05:24
Хм... Прошу прощения, ошибся. Не помогла "прополка". У меня в окошке стало появляться "Ошибка: 0". Я посмотрел коды ошибок - No Error. Обрадовался и решил что всё ОК. А то что
Код - C# [Выбрать]
  1. selRes.Status == PromptStatus.Error
как-то упустил из виду на радостях. Тесты показали, что просто сперва возвращается ERRNO = 2, а на третьем-четвёртом запуске и далее после обработки полилинии командой PL-VxOpt из PLTools - ERRNO = 0. Причём, обработана только одна полилиния, а ERRNO = 0 выдаёт на обеих. Такое поведение в Civil 3D as AutoCAD 2017. Может быть Вы как раз это наблюдали в AutoCAD 2020?

Иногда, кстати, вместо "Ошибка: 2" выводится "Ошибка: 93" - такого кода вообще нет в списке! Но воспроизвести при записи видео не получилось.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Александр Ривилис от 02-04-2019, 14:34:52
Не помогла "прополка".
Жаль.
Тесты показали, что просто сперва возвращается ERRNO = 2, а на третьем-четвёртом запуске и далее - ERRNO = 0. Такое поведение в Civil 3D as AutoCAD 2017. Может быть Вы как раз это наблюдали в AutoCAD 2020?
Нет. У меня уже при первом запуске. Что я тебе могу посоветовать? Никогда не пользоваться Editor.SelectXXX методами. Причин почему на данном контуре не срабатывает выборка может быть множество. Одна из причин как ни странно может быть связана с разрешением экрана AutoCAD. Как работают все эти методы Editor.SelectXXX? Они работают с проекциями примитивов на некий виртуальный экран. В твоём случае вполне возможно, что в проекции начинают совпадать вершины контура выбора. Еще одна возможная причина - удалённость вершин контура от начала координат.
В данном случае вершина с номером 88 отстоит от соседней на 0.00003, что явно маловато при шестизначных значениях координат.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Александр Ривилис от 02-04-2019, 14:59:35
Дмитрий Загорулькин,
Попробуй такой вариант:
Код - 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.  
  8. // This line is not mandatory, but improves loading performances
  9. [assembly: CommandClass(typeof(TestSelectCP.MyCommands))]
  10.  
  11. namespace TestSelectCP
  12. {
  13.   public class MyCommands
  14.   {
  15.     const double FUZZ = 0.1;
  16.     [CommandMethod("TestCrossingPolygonSelection")]
  17.     public void TestCrossingPolygonSelectionCmd()
  18.     {
  19.       Document adoc = Application.DocumentManager.MdiActiveDocument;
  20.       Editor ed = adoc.Editor;
  21.  
  22.       PromptEntityOptions plineOpt = new PromptEntityOptions
  23.           ("\nВыберите полилинию-контур: ");
  24.  
  25.       plineOpt.SetRejectMessage("\nЭто не полилиния!");
  26.       plineOpt.AddAllowedClass(typeof(Polyline), true);
  27.       PromptEntityResult plineRes = ed.GetEntity(plineOpt);
  28.       if (plineRes.Status != PromptStatus.OK) return;
  29.  
  30.       Point3dCollection pts = new Point3dCollection();
  31.  
  32. #pragma warning disable CS0618 // Type or member is obsolete
  33.       using (Polyline pline = plineRes.ObjectId.Open(OpenMode.ForRead) as Polyline)
  34. #pragma warning restore CS0618 // Type or member is obsolete
  35.       {
  36.         for (int i = 0; i < pline.NumberOfVertices; i++)
  37.         {
  38.           Point3d p = pline.GetPoint3dAt(i);
  39.           // if (i == 0 || pts[i-1].DistanceTo(p) >= FUZZ) <--- Исправлено по наводке Дмитрия Загорулькина
  40.           if (pts.Count == 0 || pts[pts.Count-1].DistanceTo(p) >= FUZZ)
  41.             pts.Add(p);
  42.         }
  43.       }
  44.       // Повторять последнюю точку не нужно!!!
  45.  
  46.       if (pts[0].DistanceTo(pts[pts.Count - 1]) < FUZZ)
  47.       {
  48.         pts.RemoveAt(pts.Count - 1);
  49.       }
  50.  
  51.       //double dist = 1e+32;
  52.       //int iMindist = -1;
  53.       //for (int i = 0; i < pts.Count; i++)
  54.       //{
  55.       //  double dist1 = pts[i].DistanceTo(pts[(i + 1) % pts.Count]);
  56.       //  if (dist1 < dist) {
  57.       //    dist = dist1; iMindist = i;
  58.       //  }
  59.       //}
  60.       //ed.WriteMessage($"\ndist={dist} iMindist={iMindist}");
  61.       PromptSelectionResult selRes = ed.SelectCrossingPolygon (pts);
  62.       if (selRes.Status == PromptStatus.Error)
  63.       {
  64.         short code = (short)Application.GetSystemVariable("ERRNO");
  65.         Application.ShowAlertDialog($"Ошибка: {code}");
  66.         return;
  67.       }
  68.     }
  69.   }
  70.  
  71. }
  72.  
У меня он работает безошибочно на твоих полилиниях.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Александр Ривилис от 02-04-2019, 15:06:51
Иногда, кстати, вместо "Ошибка: 2" выводится "Ошибка: 93" - такого кода вообще нет в списке! Но воспроизвести при записи видео не получилось.
Код такой есть, но что он в данном случае значит - большой вопрос:
Код - C++ [Выбрать]
  1. #define  OL_EBADTYPE   93  /* Bad value type */
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Привалов Дмитрий от 02-04-2019, 15:42:08
Количество точек, правда, зашкаливает - больше тысячи. Может ли это быть причиной того, что метод не хочет работать?

Они работают с проекциями примитивов на некий виртуальный экран. В твоём случае вполне возможно, что в проекции начинают совпадать вершины контура выбора.

Очевидно это и есть ответ. Жаль, метод оказался еще менее надежным, чем предполагалось.
Мне вот стало интересно, а зачем вообще было эти методы реализовывать через проекции? Не понимаю плюсов такого решения.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Александр Ривилис от 02-04-2019, 15:43:31
Мне вот стало интересно, а зачем вообще было эти методы реализовывать через проекции? Не понимаю плюсов такого решения.
Всё упирается в скорость выбора.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Привалов Дмитрий от 02-04-2019, 15:48:41
Всё упирается в скорость выбора.
Ну ладно выбираемые примитивы в пределах экрана спроецировали, но зачем понадобилось контур выбора проецировать и проверять что в него попало? Это ведь действительно накладывает ограничение на контур.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Александр Ривилис от 02-04-2019, 15:51:02
но зачем понадобилось контур выбора проецировать и проверять что в него попало
Странный вопрос. Предложи другой вариант.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Привалов Дмитрий от 02-04-2019, 16:01:36
Странный вопрос. Предложи другой вариант.
Ну насколько я понял действительно спроецированные объекты получить быстрее. При этом насколько я помню, если объекты не совпадают по Z c контуром, то в эту выборку не попадут.
Проецировали бы не в экранную плоскость, а в плоскость контура, без пересчета его координат.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Дмитрий Загорулькин от 02-04-2019, 16:03:24
У меня он работает безошибочно на твоих полилиниях.
Это странно - у Вас в коде в 39 строке ошибка логическая. Догадаетесь, что за ошибка? :)
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Александр Ривилис от 02-04-2019, 16:04:46
Ну насколько я понял действительно спроецированные объекты получить быстрее.
Они уже спроецированы, а не в момент вызова Editor.SelectXXX. Быстрота не в их получении, а в скорости фильтрации спроецированных объектов. Как минимум мы перешли из 3D в 2D.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Александр Ривилис от 02-04-2019, 16:08:21
Это странно - у Вас в коде в 39 строке ошибка логическая. Догадаетесь, что за ошибка? :)
Да. Вместо:
Код - C# [Выбрать]
  1. if (i == 0 || pts[i-1].DistanceTo(p) >= FUZZ)
должно быть:
Код - C# [Выбрать]
  1. if (pts.Count == 0 || pts[i-1].DistanceTo(p) >= FUZZ)
Но в данном случае сработало.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Дмитрий Загорулькин от 02-04-2019, 16:10:19
Очень тепло, но нет! :)
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Александр Ривилис от 02-04-2019, 16:12:50
Очень тепло, но нет! :)
Ну видимо я сегодня плохо соображаю. Объясни.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Привалов Дмитрий от 02-04-2019, 16:14:26
Они уже спроецированы, а не в момент вызова Editor.SelectXXX. Быстрота не в их получении, а в скорости фильтрации спроецированных объектов. Как минимум мы перешли из 3D в 2D.
А ну ладно. Теперь стала понятнее внутрянка их работы и возможные ограничения.
Возможно разработчиков Civil 3D эти функции не устроили и они написали свои. Есть на это шанс?
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Александр Ривилис от 02-04-2019, 16:16:36
Есть на это шанс?
Нет. Но никто тебе не мешает написать самому. Civil 3d (а точнее Map 3d) использует ObjectARX и AutoCAD .NET API.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Александр Ривилис от 02-04-2019, 16:18:14
Очень тепло, но нет! :)
А сообразил:
Код - C# [Выбрать]
  1.     if (pts.Count == 0 || pts[pts.Count-1].DistanceTo(p) >= FUZZ)
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Привалов Дмитрий от 02-04-2019, 16:19:13
Очень тепло, но нет!
Код - C# [Выбрать]
  1.  [s](i != 0 || pts[i-1].DistanceTo(p) >= FUZZ)[/s]?
тоже перегрелся)
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Дмитрий Загорулькин от 02-04-2019, 16:23:50
А сообразил
Да. Причём из-за этого Ваш код у меня работал очень странно. Он пропустил одну точку по условиям и далее по идее должно было быть исключение - индекс выходит за пределы коллекции. Но вместо этого возвращалась точка (0,0,0) и условие всегда выполнялось. Я FUZZ уже размером несколько десятков ставил - а результат не менялся. В общем, странное поведение Point3dCollection.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Александр Ривилис от 02-04-2019, 16:29:40
Дмитрий Загорулькин,
Теперь нормально работает?
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Дмитрий Загорулькин от 02-04-2019, 16:31:43
Да, работает как надо! Спасибо! Я пробовал FUZZ ставить поменьше: на 0,001 работает, а вот 0,0001 - уже нет.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Александр Ривилис от 02-04-2019, 16:42:34
Дмитрий Загорулькин,
Отлично! Я исправил код, чтобы те кто им захочет воспользоваться, не выискивали исправления.
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Привалов Дмитрий от 02-04-2019, 16:49:00
Я исправил код
возможно одной проверки может быть недостаточно, при контуре близком к линии?
Код - C# [Выбрать]
  1. // Повторять последнюю точку не нужно!!!
  2. if (pts[0].DistanceTo(pts[pts.Count - 1]) < FUZZ)
  3. {
  4. pts.RemoveAt(pts.Count - 1);
  5. }
Название: Re: Ограничение на количество точек полигона для метода Editor.SelectCrossingPolygon
Отправлено: Александр Ривилис от 02-04-2019, 16:52:39
Я исправил код
возможно одной проверки может быть недостаточно, при контуре близком к линии?
Код - C# [Выбрать]
  1. // Повторять последнюю точку не нужно!!!
  2. if (pts[0].DistanceTo(pts[pts.Count - 1]) < FUZZ)
  3. {
  4. pts.RemoveAt(pts.Count - 1);
  5. }
Код не универсальный. В данном случае проверяется близость первой и последней вершин контура.