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

ADN Club => AutoCAD .NET API => Тема начата: Алексей Терно от 13-05-2020, 12:41:45

Название: Некорректный результат GetSplitCurves()
Отправлено: Алексей Терно от 13-05-2020, 12:41:45
Джентльмены, приветствую!

Мне тут понадобилось разделить полилинию по замкнутому контуру. Вот пример:
(https://i.postimg.cc/cKT8gt8J/2020-05-13-12-24-59.png) (https://postimg.cc/cKT8gt8J)
Сперва я попытался использовать метод GetSplitCurves(), чтобы получить уже готовые полилинии, но результат меня удивил. Полилиния действительно разрезается в точках пересечения с контуром, но как-то странно:
(https://i.postimg.cc/crQCttpN/2020-05-13-12-26-49.png) (https://postimg.cc/crQCttpN)
Я немного сдвинул полученные полилинии, чтобы было видно, какой получается результат. Причем в других местах, полилиния обрезается корректно:
(https://i.postimg.cc/hh4R1zQB/2020-05-13-12-37-35.png) (https://postimg.cc/hh4R1zQB)

Код:
Код - 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.  

Из-за чего в первом случае обрезка получается некорректная?
Название: Re: Некорректный результат GetSplitCurves()
Отправлено: Алексей Терно от 13-05-2020, 13:05:26
Оказывается все дело было в направлении разделяемой полилинии, а точнее в последовательности точек пересечения на ней. Если отсортировать все точки пересечения по направлению обрезаемой полилинии, то получается все правильно:
(https://i.postimg.cc/R3Qb3mmR/2020-05-13-13-03-52.png) (https://postimg.cc/R3Qb3mmR)

Добавил строчки 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.  
Название: Re: Некорректный результат GetSplitCurves()
Отправлено: Александр Ривилис от 13-05-2020, 13:13:41
Вместо GetDistAtPoint я бы рекомендовал GetParamAtPoint
Да и вообще вместо Curve.GetSplitCurves(Point3dCollection) лучше использовать Curve.GetSplitCurves(DoubleCollection)
В DoubleCollection параметры отсортированы по возрастанию.
Название: Re: Некорректный результат GetSplitCurves()
Отправлено: Привалов Дмитрий от 13-05-2020, 13:17:10
Из-за чего в первом случае обрезка получается некорректная?
...не успел написать  :D
нужно сортировать точки пересечения, а затем передавать в GetSplitCurves().

Для криволинейных сортировать сложнее, нужно в порядке удаления от начальной вершины.
//Длина участка от начала кривой, до точки p1
double dist = curve.GetDistAtPoint( p1 );
Название: Re: Некорректный результат GetSplitCurves()
Отправлено: Алексей Терно от 13-05-2020, 13:45:02
В DoubleCollection параметры отсортированы по возрастанию.
У меня они отсортированы в порядке их добавления:
(https://i.postimg.cc/wTZ4c4yB/2020-05-13-13-41-11.png)

DoubleCollection тоже надо сортировать, однако, действительно - лучше использовать его или, в крайнем случае, List<double> для сортировки, чем городить Tuple ))
Название: Re: Некорректный результат GetSplitCurves()
Отправлено: Привалов Дмитрий от 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 с самопересечением. Может и сам тогда где-то накосячил.
Название: Re: Некорректный результат GetSplitCurves()
Отправлено: Александр Ривилис от 13-05-2020, 13:51:33
Алексей Терно,
Только в DoubleCollection не расстояния от начала кривой (Dist), а парамерты (Param) - это совершенно разные вещи для полилинии.
Название: Re: Некорректный результат GetSplitCurves()
Отправлено: Алексей Терно от 13-05-2020, 13:52:50
То ли с округлением координат, дело было, чуток не попадали на разрезаемую кривую, и подтягивал их GetClosestPointTo
Да - есть такая проблема. Иногда приходилось дополнительно искать GetClosestPointTo.

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

Пока решил остановиться на сортировке List<double> с дальнейшим созданием DoubleCollection.
Название: Re: Некорректный результат GetSplitCurves()
Отправлено: Алексей Терно от 13-05-2020, 13:54:14
Только в DoubleCollection не расстояния от начала кривой (Dist), а парамерты (Param) - это совершенно разные вещи для полилинии.
К моему стыду, я узнал это только сейчас (( Всегда засовывал туда расстояния от начала и искренне удивлялся, что метод не работает )))
Название: Re: Некорректный результат GetSplitCurves()
Отправлено: Привалов Дмитрий от 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 );
Название: Re: Некорректный результат GetSplitCurves()
Отправлено: Александр Ривилис от 13-05-2020, 14:15:04
К моему стыду, я узнал это только сейчас (( Всегда засовывал туда расстояния от начала и искренне удивлялся, что метод не работает )))
А прочитать документацию как обычно времени не хватает? ;)
Впрочем, как обычно следует скептически относится к документации для .NET API и читать исходную для ObjectARX. Найди отличие:

(https://live.staticflickr.com/65535/49890405122_e01cee0366_o.png)

(https://live.staticflickr.com/65535/49890412777_93822e7da7_o.png)



Название: Re: Некорректный результат GetSplitCurves()
Отправлено: Привалов Дмитрий от 13-05-2020, 15:12:52
Впрочем, как обычно следует скептически относится к документации для .NET API и читать исходную для ObjectARX. Найди отличие:
Золотые слова.
Часто бывает - Заходишь в документацию .NET, хочешь посмотреть например в каких координатах возвращается точка Point3d WCS, UCS, OCS.... либо что за параметры требуются функции, и что они значат. А в .NET документации никакой конкретики, общее описание. Заходишь в документацию ObjectARX и часто все подробно описано.
Название: Re: Некорректный результат GetSplitCurves()
Отправлено: Алексей Терно от 13-05-2020, 15:26:10
А прочитать документацию как обычно времени не хватает?
Если читать документацию, то писать программы становится очень скучно - никакой интриги, ни каких сюрпризов ))))