Некорректный результат GetSplitCurves()

Автор Тема: Некорректный результат GetSplitCurves()  (Прочитано 4767 раз)

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

Оффлайн Алексей ТерноАвтор темы

  • ADN Club
  • ****
  • Сообщений: 381
  • Карма: 33
    • C3D Extensions
  • Skype: alexeyterno
Джентльмены, приветствую!

Мне тут понадобилось разделить полилинию по замкнутому контуру. Вот пример:

Сперва я попытался использовать метод GetSplitCurves(), чтобы получить уже готовые полилинии, но результат меня удивил. Полилиния действительно разрезается в точках пересечения с контуром, но как-то странно:

Я немного сдвинул полученные полилинии, чтобы было видно, какой получается результат. Причем в других местах, полилиния обрезается корректно:


Код:
Код - C# [Выбрать]
  1. [CommandMethod("test_2")]
  2. public static void test_2()
  3. {
  4.     Document doc = Application.DocumentManager.MdiActiveDocument;
  5.     Database db = doc.Database;
  6.     Editor ed = doc.Editor;
  7.  
  8.     using (Transaction trans = db.TransactionManager.StartTransaction())
  9.     {
  10.         BlockTable bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForWrite);
  11.         BlockTableRecord ms = (BlockTableRecord)trans.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
  12.  
  13.         Polyline border = (Polyline)trans.GetObject(ed.GetEntity("\nborder:").ObjectId, OpenMode.ForRead);
  14.         Polyline pline = (Polyline)trans.GetObject(ed.GetEntity("\npline:").ObjectId, OpenMode.ForRead);
  15.  
  16.         Point3dCollection points = new Point3dCollection();
  17.         border.IntersectWith(pline, Intersect.OnBothOperands, points, new IntPtr(), new IntPtr());
  18.  
  19.         DBObjectCollection objects = pline.GetSplitCurves(points);
  20.  
  21.         for (int i = 0; i < objects.Count; i++)
  22.         {
  23.             Polyline splitted = (Polyline)objects[i];
  24.             splitted.ColorIndex = i + 1;
  25.  
  26.             ms.AppendEntity(splitted);
  27.             trans.AddNewlyCreatedDBObject(splitted, true);
  28.         }
  29.  
  30.         trans.Commit();
  31.     }
  32. }
  33.  

Из-за чего в первом случае обрезка получается некорректная?

Отмечено как Решение Алексей Терно 13-05-2020, 13:05:29

Оффлайн Алексей ТерноАвтор темы

  • ADN Club
  • ****
  • Сообщений: 381
  • Карма: 33
    • C3D Extensions
  • Skype: alexeyterno
Re: Некорректный результат GetSplitCurves()
« Ответ #1 : 13-05-2020, 13:05:26 »
Оказывается все дело было в направлении разделяемой полилинии, а точнее в последовательности точек пересечения на ней. Если отсортировать все точки пересечения по направлению обрезаемой полилинии, то получается все правильно:


Добавил строчки 19-33:
Код - C# [Выбрать]
  1. [CommandMethod("test_2")]
  2. public static void test_2()
  3. {
  4.     Document doc = Application.DocumentManager.MdiActiveDocument;
  5.     Database db = doc.Database;
  6.     Editor ed = doc.Editor;
  7.  
  8.     using (Transaction trans = db.TransactionManager.StartTransaction())
  9.     {
  10.         BlockTable bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForWrite);
  11.         BlockTableRecord ms = (BlockTableRecord)trans.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
  12.  
  13.         Polyline border = (Polyline)trans.GetObject(ed.GetEntity("\nborder:").ObjectId, OpenMode.ForRead);
  14.         Polyline pline = (Polyline)trans.GetObject(ed.GetEntity("\npline:").ObjectId, OpenMode.ForRead);
  15.  
  16.         Point3dCollection points = new Point3dCollection();
  17.         border.IntersectWith(pline, Intersect.OnBothOperands, points, new IntPtr(), new IntPtr());
  18.  
  19.         List<Tuple<Point3d, double>> pointDist = new List<Tuple<Point3d, double>>();
  20.  
  21.         foreach (Point3d point in points)
  22.         {
  23.             pointDist.Add(new Tuple<Point3d, double>(point, pline.GetDistAtPoint(point)));
  24.         }
  25.  
  26.         pointDist.Sort((a, b) => a.Item2.CompareTo(b.Item2));
  27.  
  28.         points = new Point3dCollection();
  29.  
  30.         for (int i = 0; i < pointDist.Count; i++)
  31.         {
  32.             points.Add(pointDist[i].Item1);
  33.         }
  34.  
  35.         DBObjectCollection objects = pline.GetSplitCurves(points);
  36.  
  37.         for (int i = 0; i < objects.Count; i++)
  38.         {
  39.             Polyline splitted = (Polyline)objects[i];
  40.             splitted.ColorIndex = i + 1;
  41.  
  42.             ms.AppendEntity(splitted);
  43.             trans.AddNewlyCreatedDBObject(splitted, true);
  44.         }
  45.  
  46.         trans.Commit();
  47.     }
  48. }
  49.  

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Некорректный результат GetSplitCurves()
« Ответ #2 : 13-05-2020, 13:13:41 »
Вместо GetDistAtPoint я бы рекомендовал GetParamAtPoint
Да и вообще вместо Curve.GetSplitCurves(Point3dCollection) лучше использовать Curve.GetSplitCurves(DoubleCollection)
В DoubleCollection параметры отсортированы по возрастанию.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 534
  • Карма: 117
Re: Некорректный результат GetSplitCurves()
« Ответ #3 : 13-05-2020, 13:17:10 »
Из-за чего в первом случае обрезка получается некорректная?
...не успел написать  :D
нужно сортировать точки пересечения, а затем передавать в GetSplitCurves().

Для криволинейных сортировать сложнее, нужно в порядке удаления от начальной вершины.
//Длина участка от начала кривой, до точки p1
double dist = curve.GetDistAtPoint( p1 );

Оффлайн Алексей ТерноАвтор темы

  • ADN Club
  • ****
  • Сообщений: 381
  • Карма: 33
    • C3D Extensions
  • Skype: alexeyterno
Re: Некорректный результат GetSplitCurves()
« Ответ #4 : 13-05-2020, 13:45:02 »
В DoubleCollection параметры отсортированы по возрастанию.
У меня они отсортированы в порядке их добавления:


DoubleCollection тоже надо сортировать, однако, действительно - лучше использовать его или, в крайнем случае, List<double> для сортировки, чем городить Tuple ))

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 534
  • Карма: 117
Re: Некорректный результат GetSplitCurves()
« Ответ #5 : 13-05-2020, 13:45:52 »
Если отсортировать все точки пересечения по направлению обрезаемой полилинии, то получается все правильно:
Можешь попробовать отсортировать так...вроде покороче, может даже работает)))
var sortPoints = points.OfType<Point3d>().OrderBy( n => pline.GetDistAtPoint( n ) ).ToArray();
Point3dCollection sortPointsCollections = new Point3dCollection( sortPoints );

Да и вообще вместо Curve.GetSplitCurves(Point3dCollection) лучше использовать Curve.GetSplitCurves(DoubleCollection)
..делал очень давно, так что извиняюсь если что неточно.
...кажется что-то припоминаю, что у меня были иногда проблемы, когда применял Curve.GetSplitCurves(Point3dCollection). Метод Curve.GetSplitCurves(DoubleCollection) работал надежнее. То ли с округлением координат, дело было, чуток не попадали на разрезаемую кривую, и подтягивал их GetClosestPointTo.  Или Curve с самопересечением. Может и сам тогда где-то накосячил.

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Некорректный результат GetSplitCurves()
« Ответ #6 : 13-05-2020, 13:51:33 »
Алексей Терно,
Только в DoubleCollection не расстояния от начала кривой (Dist), а парамерты (Param) - это совершенно разные вещи для полилинии.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Алексей ТерноАвтор темы

  • ADN Club
  • ****
  • Сообщений: 381
  • Карма: 33
    • C3D Extensions
  • Skype: alexeyterno
Re: Некорректный результат GetSplitCurves()
« Ответ #7 : 13-05-2020, 13:52:50 »
То ли с округлением координат, дело было, чуток не попадали на разрезаемую кривую, и подтягивал их GetClosestPointTo
Да - есть такая проблема. Иногда приходилось дополнительно искать GetClosestPointTo.

так...вроде покороче, может даже работает)))
Да тут дело скорее в скорости работы кода - предполагается, что таких обрезаемых линий будет много и необходимо максимально сократить время на каждую операцию.

Пока решил остановиться на сортировке List<double> с дальнейшим созданием DoubleCollection.

Оффлайн Алексей ТерноАвтор темы

  • ADN Club
  • ****
  • Сообщений: 381
  • Карма: 33
    • C3D Extensions
  • Skype: alexeyterno
Re: Некорректный результат GetSplitCurves()
« Ответ #8 : 13-05-2020, 13:54:14 »
Только в DoubleCollection не расстояния от начала кривой (Dist), а парамерты (Param) - это совершенно разные вещи для полилинии.
К моему стыду, я узнал это только сейчас (( Всегда засовывал туда расстояния от начала и искренне удивлялся, что метод не работает )))

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 534
  • Карма: 117
Re: Некорректный результат GetSplitCurves()
« Ответ #9 : 13-05-2020, 13:55:40 »
Пока решил остановиться на сортировке List<double> с дальнейшим созданием DoubleCollection.

попробуй, вдруг подойдет.
Код - C# [Выбрать]
  1. Point3dCollection points = new Point3dCollection();
  2. border.IntersectWith( pline, Intersect.OnBothOperands, points, new IntPtr(), new IntPtr() );
  3.  
  4. var parameters = points.OfType<Point3d>().Select( n => pline.GetParameterAtPoint( n ) ).OrderBy(n=>n).ToArray();
  5. DoubleCollection dc = new DoubleCollection( parameters );
« Последнее редактирование: 13-05-2020, 14:03:13 от Александр Ривилис »

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Некорректный результат GetSplitCurves()
« Ответ #10 : 13-05-2020, 14:15:04 »
К моему стыду, я узнал это только сейчас (( Всегда засовывал туда расстояния от начала и искренне удивлялся, что метод не работает )))
А прочитать документацию как обычно времени не хватает? ;)
Впрочем, как обычно следует скептически относится к документации для .NET API и читать исходную для ObjectARX. Найди отличие:







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

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 534
  • Карма: 117
Re: Некорректный результат GetSplitCurves()
« Ответ #11 : 13-05-2020, 15:12:52 »
Впрочем, как обычно следует скептически относится к документации для .NET API и читать исходную для ObjectARX. Найди отличие:
Золотые слова.
Часто бывает - Заходишь в документацию .NET, хочешь посмотреть например в каких координатах возвращается точка Point3d WCS, UCS, OCS.... либо что за параметры требуются функции, и что они значат. А в .NET документации никакой конкретики, общее описание. Заходишь в документацию ObjectARX и часто все подробно описано.

Оффлайн Алексей ТерноАвтор темы

  • ADN Club
  • ****
  • Сообщений: 381
  • Карма: 33
    • C3D Extensions
  • Skype: alexeyterno
Re: Некорректный результат GetSplitCurves()
« Ответ #12 : 13-05-2020, 15:26:10 »
А прочитать документацию как обычно времени не хватает?
Если читать документацию, то писать программы становится очень скучно - никакой интриги, ни каких сюрпризов ))))