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

ADN Club => AutoCAD .NET API => Тема начата: Дмитрий Загорулькин от 02-12-2020, 14:16:03

Название: Как определить минимальное количество вершин для метода Spline.ToPolyline?
Отправлено: Дмитрий Загорулькин от 02-12-2020, 14:16:03
Здравствуйте!
Конвертирую сплайны в полилинии с помощью метода Spline.ToPolyline (https://help.autodesk.com/view/OARX/2021/ENU/?guid=OARX-ManagedRefGuide-Autodesk_AutoCAD_DatabaseServices_Spline_ToPolyline_uint__MarshalAsUnmanagedType_U1__bool__MarshalAsUnmanagedType_U1__bool). В нём первым параметром задаётся количество вершин для аппроксимации. Я полагал, что минимум можно задать 2 вершины - тогда сплайн преобразуется в отрезок. Но на практике оказалось, что с 2-мя вершинами выскакивает исключение eInvalidInput. Поэкспериментировал и выяснил, что корректно срабатывает, если количество вершин аппроксимации не меньше, чем значение Spline.NumControlPoints - 2. И я так подозреваю, что если сплайн будет построен по FitPoints, то надо будет вместо NumControlPoints опираться на количество NumFitPoints. Может, есть какая-то информация о том, как подбирать минимальное кол-во вершин аппроксимации для сплайна? В справке не нашёл такого.
Название: Re: Как определить минимальное количество вершин для метода Spline.ToPolyline?
Отправлено: Привалов Дмитрий от 02-12-2020, 14:23:39
В справке не нашёл такого.
Хм в arxdoc.chm вроде написано минимальное количество.

More polyline vertices make a more accurate apporximation, but too many vertices reduces the display performance of the polyline.

numOfVertices must be no smaller than the number of spline fit points.

максимальное скорее всего подобрать из соображений точности, например number of spline fit points * 8
Название: Re: Как определить минимальное количество вершин для метода Spline.ToPolyline?
Отправлено: Дмитрий Загорулькин от 02-12-2020, 14:53:42
numOfVertices must be no smaller than the number of spline fit points.
максимальное скорее всего подобрать из соображений точности, например number of spline fit points * 8
Не годится, вот свойства моего сплайна:
Код - C# [Выбрать]
  1.  NumControlPoints = {int} 6
  2.  NumFitPoints = {int} 0
2 больше 0, но для метода требуется значение не менее 4.
Название: Re: Как определить минимальное количество вершин для метода Spline.ToPolyline?
Отправлено: Александр Ривилис от 02-12-2020, 15:09:41
Дмитрий Загорулькин,
Кроме того, что нашел Привалов Дмитрий, никакой информации нет.
Название: Re: Как определить минимальное количество вершин для метода Spline.ToPolyline?
Отправлено: Привалов Дмитрий от 02-12-2020, 15:15:14
Не годится
Из справки AutoCAD очевидно, что с количеством управляющих и определяющих точек могут быть "нюансы":

Выполнение некоторых операций приводит к удалению определяющих точек. В этих случаях ручки располагаются в управляющих точках сплайна. К таким операциям относятся обрезка сплайна, перемещение контрольных точек и удаление определяющих данных.

Повысить точность сплайна можно, увеличив количество управляющих точек в какой-либо из его частей, или изменив весовые коэффициенты некоторых из управляющих точек. Повышение весового коэффициента управляющей точки заставляет сплайн проходить ближе к ней. Еще один способ увеличения точности сплайна - повышение его порядка. Порядком сплайна называется число, на единицу большее степени полинома, описывающего сплайн. Например, кубический сплайн имеет порядок 4. Чем выше порядок сплайна, тем больше у него управляющих точек.

Соответственно нужно анализировать больше параметров, ну или не париться и сделать как-то так:
int Points = Math.Max(NumControlPoints, NumFitPoints) *8;
Название: Re: Как определить минимальное количество вершин для метода Spline.ToPolyline?
Отправлено: Дмитрий Загорулькин от 02-12-2020, 15:30:10
Выполнение некоторых операций приводит к удалению определяющих точек. В этих случаях ручки располагаются в управляющих точках сплайна. К таким операциям относятся обрезка сплайна, перемещение контрольных точек и удаление определяющих данных.

Повысить точность сплайна можно, увеличив количество управляющих точек в какой-либо из его частей, или изменив весовые коэффициенты некоторых из управляющих точек. Повышение весового коэффициента управляющей точки заставляет сплайн проходить ближе к ней. Еще один способ увеличения точности сплайна - повышение его порядка. Порядком сплайна называется число, на единицу большее степени полинома, описывающего сплайн. Например, кубический сплайн имеет порядок 4. Чем выше порядок сплайна, тем больше у него управляющих точек.
Что-то я не понял, что тут написано... Получается, что у сплайна есть:
- определяющие точки
- управляющие точки
- контрольные точки
Что из этого ControlPoints, а что FitPoints? Может ли ControlPoints быть меньше FitPoints?
ну или не париться и сделать как-то так:
int Points = Math.Max(NumControlPoints, NumFitPoints) *8;
Мне надо определить как можно меньшее число, но чтобы оно не вызывало исключения в методе. Например, мне попался сплайн, у которого NumControlPoints = 111. Если ещё на 8 умножить, то получится дикое количество в 888 вершин! Это нехорошо...
Вот ещё пример попался: длина сплайна 0.0003 ед. чертежа и у него NumControlPoints = 7. Если на 8 умножить, то у такой микроскопической полилинии получится 56 вершин!
Название: Re: Как определить минимальное количество вершин для метода Spline.ToPolyline?
Отправлено: Александр Ривилис от 02-12-2020, 15:39:01
Дмитрий Загорулькин,
Может положится на AutoCAD и не задавать количество вершин?
- управляющие точки
- контрольные точки
Это одно и тоже - ControlPoints. В AutoCAD'е есть два вида сплайнов. В одних есть FitData, в других нет.
https://knowledge.autodesk.com/ru/support/autocad/learn-explore/caas/CloudHelp/cloudhelp/2016/RUS/AutoCAD-Core/files/GUID-58316136-30EB-499C-ACAD-31D0C653B2B2-htm.html
Название: Re: Как определить минимальное количество вершин для метода Spline.ToPolyline?
Отправлено: Привалов Дмитрий от 02-12-2020, 15:51:23
Мне надо определить как можно меньшее число
Это аппроксимация и по идее, чтобы повторить геометрию сплайна полилинией без  сглаживания нужно большее количество точек.

мне попался сплайн, у которого NumControlPoints = 111. Если ещё на 8 умножить, то получится дикое количество в 888 вершин! Это нехорошо...
Возможно это не аргумент. Для раздумья:
1. Возможно полилиния с 888 вершинами пострится быстрее, чем сплайн с 111.
2. Изыскатели как правило все рисуют полилиниями без дуг с большим количеством вершин(заборы, границы, горизонтали и т.д.). Т.к. заказчики могут перекидывать в другие САПРы и простые полилинии перекидываются без проблем. 1000 вершин на полилинию не так уж и много.
3. А может вершин сплайна изначально много, можно оптимизировать, а потом аппроксимировать.
4. Попробовать аппроксимировать другим способом. Александр вроде приводил на форуме пример аппроксимации Curve на примере Polyline.
Название: Re: Как определить минимальное количество вершин для метода Spline.ToPolyline?
Отправлено: Привалов Дмитрий от 02-12-2020, 16:01:51
Вот ещё пример попался: длина сплайна 0.0003 ед. чертежа и у него NumControlPoints = 7. Если на 8 умножить, то у такой микроскопической полилинии получится 56 вершин!
Такое в автокаде сплошь и рядом. Выбери свою стратегию для таких объектов:
1. Не обращать внимания, делать единообразно как для всех
2. Не аппроксимировать сплайны, длина которых меньше допуска.
3. Перед аппроксимацией удалить, как объект "нулевой длины" не попадающий в допуск.
4. Нужен для целостности контура? Упростить, можно заменить например на отрезок, начало и конец известны. Или удалить промежуточные точки сплайна.
Название: Re: Как определить минимальное количество вершин для метода Spline.ToPolyline?
Отправлено: Дмитрий Загорулькин от 02-12-2020, 16:04:02
Может положиться на AutoCAD и не задавать количество вершин?
Вы про метод ToPolyline без параметра numOfVertices? Я его пробовал, но мне не понравилось, что он по умолчанию очень много вершин создаёт даже для довольно простых кривых. На примере во вложении для этой кривой создалось 222 вершины!
В AutoCAD'е есть два вида сплайнов. В одних есть FitData, в других нет.
Да, и если я всё правильно понимаю, один в другой можно переключать ручкой на сплайне.
1. Возможно полилиния с 888 вершинами пострится быстрее, чем сплайн с 111.
2. Изыскатели как правило все рисуют полилиниями без дуг с большим количеством вершин(заборы, границы, горизонтали и т.д.). Т.к. заказчики могут перекидывать в другие САПРы и простые полилинии перекидываются без проблем. 1000 вершин на полилинию не так уж и много.
Лишние вершины полилиний очень сильно увеличивают размер чертежа и уменьшают быстродействие. Я помню чистил такие чертежи с диким количеством вершин с помощью "прополки" из PLTools и за счёт этого уменьшал вес файла чертежа на десятки мегабайт.
3. А может вершин сплайна изначально много, можно оптимизировать, а потом аппроксимировать.
4. Попробовать аппроксимировать другим способом. Александр вроде приводил на форуме пример аппроксимации Curve на примере Polyline.
Я затем извлекаю вершины из полилинии и выполняю оптимизацию. Поэтому, очень хочется, чтобы изначально в эту оптимизацию приходило как можно меньше вершин. Особенно, на микроскопических сплайнах.
Я пока остановился на таком варианте:
Код - C# [Выбрать]
  1. var splinePointsCount = (uint)Math.Max(spline.NumFitPoints, spline.NumControlPoints);
Использую его для сплайнов, длина которых меньше значимой величины.

(https://i.postimg.cc/bdH2L0XV/maf-vertices.gif) (https://postimg.cc/bdH2L0XV)
Название: Re: Как определить минимальное количество вершин для метода Spline.ToPolyline?
Отправлено: Александр Ривилис от 02-12-2020, 16:21:19
Я пока остановился на таком варианте:
Это правильно для достаточно гладких сплайнов с достаточно большим количеством вершин. А вот если у него Fit/Knot-точек мало, а он достаточно большой, то точность аппроксимации может быть неудовлетворительной. Аппроксимацию лучше делать, задавшись максимальной высотой хорды. Мне так кажется...
Название: Re: Как определить минимальное количество вершин для метода Spline.ToPolyline?
Отправлено: Дмитрий Загорулькин от 02-12-2020, 16:33:48
Я проводил опыты и пришёл к выводу, что в большинстве случаев 100 точек на сплайн достаточно для первоначальной аппроксимации. Это, конечно, много для простых кривых, но это в среднем меньше, чем использует стандартная аппроксимация. Поэтому, я изначально по умолчанию поставил такую величину как константу. Но сегодня, когда тестировал большой чертёж с кучей сплайнов, среди которых оказалось много крошечных, решил что для них 100 точек многовато. Потому и озадачился минимально допустимым значением.
В итоге, у меня получилось так:
Код - C# [Выбрать]
  1. uint approxVerticesCount = 100;
  2. var splinePointsCount = (uint)Math.Max(spline.NumFitPoints, spline.NumControlPoints);
  3. if (approxVerticesCount < splinePointsCount || (spline.TryGetLength(out var length) && length < tolerance))
  4. {
  5.    approxVerticesCount = splinePointsCount;
  6. }