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

ADN Club => AutoCAD .NET API => Тема начата: Захаров Максим от 23-10-2018, 17:31:53

Название: Сделать порядок следования вершин полилинии по часовой стрелке
Отправлено: Захаров Максим от 23-10-2018, 17:31:53
Здравствуйте.
Подскажите пожалуйста алгоритм. Как мне программно узнать порядок следования вершин в полилинии (по часовой стрелке или против часовой). Дуговых сегментов нет.
Спасибо
Название: Re: Сделать порядок следования вершин полилинии по часовой стрелке
Отправлено: Александр Ривилис от 23-10-2018, 17:37:41
Вариант на ObjectARX: http://adn-cis.org/kak-opredelit-napravlenie-vrashheniya-zamknutoj-polilinii.html
Справишься с переводом на .NET?
Название: Re: Сделать порядок следования вершин полилинии по часовой стрелке
Отправлено: Александр Ривилис от 23-10-2018, 17:42:30
Вот еще хорошее решение: https://forums.autodesk.com/t5/net/how-to-know-the-orientation-of-a-polyline/m-p/3789517/highlight/true#M33636
Название: Re: Сделать порядок следования вершин полилинии по часовой стрелке
Отправлено: Захаров Максим от 23-10-2018, 19:48:04
Спасибо Александр.
Воспользовался конвертером. Буду разбираться.
Название: Re: Сделать порядок следования вершин полилинии по часовой стрелке
Отправлено: Кирилл Захаров от 29-10-2018, 16:53:20
Могу предложить метод, которым я пользовался:
Код - C# [Выбрать]
  1.         /// <summary>
  2.         /// Порядок точек в наборе соответствует обходу по часовой стрелке
  3.         /// https://stackoverflow.com/a/1165943
  4.         /// </summary>
  5.         /// <param name="poligon"></param>
  6.         /// <returns></returns>
  7.         public static bool DirectionIsClockwise(IList<Point2d> poligon)
  8.         {
  9.             int N = poligon.Count();
  10.             double p = 0;
  11.             for (int i = 0; i < N; i++)
  12.             {
  13.                 Point2d p1 = poligon[i];
  14.                 Point2d p2 = poligon[(i + 1) % N];
  15.                 p += (p2.X - p1.X) * (p2.Y + p1.Y);
  16.             }
  17.             return p > 0;
  18.         }
  19.  

Воспользовался конвертером.
А можно узнать, что за конвертер?
Название: Re: Сделать порядок следования вершин полилинии по часовой стрелке
Отправлено: Александр Ривилис от 29-10-2018, 16:58:47
Могу предложить метод, которым я пользовался:
Это упрощенный вариант кода Gilles Chanteau без учета дуговых сегментов.
А можно узнать, что за конвертер?
Я так понимаю, что это один из конвертеров C#->VB.NET. Есть и онлайн-конвертеры, есть и в составе SharpDevelop (http://www.icsharpcode.net/)
Название: Re: Сделать порядок следования вершин полилинии по часовой стрелке
Отправлено: Кирилл Захаров от 29-10-2018, 17:52:33
Ага, спасибо, Александр
Название: Re: Сделать порядок следования вершин полилинии по часовой стрелке
Отправлено: Захаров Максим от 29-10-2018, 21:44:31
Я использовал конвертер "C++ to VB Converter"
Но он мне вообще не помог, я так и не смог код на VB.NET перевести. Второй пример я тоже так и не смог на VB.Net сделать как не старался. Воспользовался описанием самой идеи. Сегодня по быстрому написал код, вроде пока работает, но чувствую надо дорабатывать слишком просто. Хотя на всех моих полигонах отработал код без ошибок.
Код - vb.net [Выбрать]
  1. If TypeOf obj Is Autodesk.AutoCAD.DatabaseServices.Polyline Then
  2.                 Dim ParcelObj As Autodesk.AutoCAD.DatabaseServices.Polyline = obj
  3.                 Dim ang1 As Integer = 0
  4.                 Dim ang2 As Integer = 0
  5.                 For i As Integer = 0 To ParcelObj.NumberOfVertices - 2
  6.                     Dim seg1 As LineSegment2d = ParcelObj.GetLineSegment2dAt(i)
  7.                     If seg1.Length < 0.01 Then
  8.                         Continue For
  9.                     End If
  10.                     Dim seg2 As LineSegment2d = Nothing
  11.                     If i = ParcelObj.NumberOfVertices - 2 Then
  12.                         seg2 = ParcelObj.GetLineSegment2dAt(0)
  13.                     Else
  14.                         seg2 = ParcelObj.GetLineSegment2dAt(i + 1)
  15.                     End If
  16.                     Dim dangle1 As Double = seg1.Direction.Angle
  17.                     Dim dangle2 As Double = seg2.Direction.Angle
  18.                     Dim delta As Double = dangle2 - dangle1
  19.                     If delta > 0 Then
  20.                         ang1 += 1 '
  21.                     Else
  22.                         ang2 += 1
  23.                     End If
  24.                 Next i
  25.                 If ang1 < ang2 Then
  26.                     MsgBox("По часовой")
  27.                 Else
  28.                     MsgBox("Против часовой")
  29.                 End If
  30.             End If
Название: Re: Сделать порядок следования вершин полилинии по часовой стрелке
Отправлено: Александр Ривилис от 29-10-2018, 23:00:15
Я использовал конвертер "C++ to VB Converter"
Жуть. Это не C++, а C#!!!
Вот такой результат даёт конвертер (с небольшими моими доработками):
Код - vb.net [Выбрать]
  1. Public NotInheritable Class AlgebraicArea
  2.   Private Sub New()
  3.   End Sub
  4.   Public Shared Function GetArea(pt1 As Point2d, pt2 As Point2d, pt3 As Point2d) As Double
  5.     Return (((pt2.X - pt1.X) * (pt3.Y - pt1.Y)) - ((pt3.X - pt1.X) * (pt2.Y - pt1.Y))) / 2
  6.   End Function
  7.  
  8.   Public Shared Function GetArea(arc As CircularArc2d) As Double
  9.     Dim rad As Double = arc.Radius
  10.     Dim ang As Double = If(arc.IsClockWise, arc.StartAngle - arc.EndAngle, arc.EndAngle - arc.StartAngle)
  11.     Return rad * rad * (ang - Math.Sin(ang)) / 2
  12.   End Function
  13.  
  14.   Public Shared Function GetArea(pline As Polyline) As Double
  15.     Dim arc As New CircularArc2d()
  16.     Dim area As Double = 0
  17.     Dim last As Integer = pline.NumberOfVertices - 1
  18.     Dim p0 As Point2d = pline.GetPoint2dAt(0)
  19.  
  20.     If pline.GetBulgeAt(0) <> 0 Then
  21.       area += GetArea(pline.GetArcSegment2dAt(0))
  22.     End If
  23.     For i As Integer = 1 To last - 1
  24.       area += GetArea(p0, pline.GetPoint2dAt(i), pline.GetPoint2dAt(i + 1))
  25.       If pline.GetBulgeAt(i) <> 0 Then
  26.         area += GetArea(pline.GetArcSegment2dAt(i))
  27.       End If
  28.     Next
  29.     If (pline.GetBulgeAt(last) <> 0) AndAlso pline.Closed Then
  30.       area += GetArea(pline.GetArcSegment2dAt(last))
  31.     End If
  32.     Return area
  33.   End Function
  34. End Class

А это для проверки:
Код - vb.net [Выбрать]
  1. <CommandMethod("Test")>
  2. Public Sub ClockwisePolyline()
  3.   Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
  4.   Dim db As Database = HostApplicationServices.WorkingDatabase
  5.   Dim ed As Editor = doc.Editor
  6.  
  7.   Using tr As Transaction = db.TransactionManager.StartTransaction()
  8.     Dim btr As BlockTableRecord = CType(db.CurrentSpaceId.GetObject(OpenMode.ForWrite), BlockTableRecord)
  9.     Dim peo As PromptEntityOptions = New PromptEntityOptions(vbLf & "Select a polyline: ")
  10.     peo.SetRejectMessage("Selected object is not a polyline.")
  11.     peo.AddAllowedClass(GetType(Polyline), False)
  12.  
  13.     While True
  14.       Dim per As PromptEntityResult = ed.GetEntity(peo)
  15.       If per.Status <> PromptStatus.OK Then Exit While
  16.       Dim pline As Polyline = CType(per.ObjectId.GetObject(OpenMode.ForRead), Polyline)
  17.       Dim area As Double = GetArea(pline)
  18.       Application.ShowAlertDialog(String.Format("{0}" & vbLf & "Area = {1}", If(area < 0, "CW", "CCW"), area))
  19.     End While
  20.  
  21.     tr.Commit()
  22.   End Using
  23. End Sub
Название: Re: Сделать порядок следования вершин полилинии по часовой стрелке
Отправлено: Захаров Максим от 30-10-2018, 21:36:41
Спасибо Александр.
Я понял что второй пример на C# сделан. Но я так и смог понять как в пределах одного класса существует 3 функции с одинаковыми именами, поэтому и не получилось. Щас естественно все заработало. А конвертером "C++ to VB Converter" я пытался переработать пример из  http://adn-cis.org/kak-opredelit-napravlenie-vrashheniya-zamknutoj-polilinii.html.
В любом случае спасибо большое.
Название: Re: Сделать порядок следования вершин полилинии по часовой стрелке
Отправлено: Александр Ривилис от 30-10-2018, 22:18:30
А конвертером "C++ to VB Converter" я пытался переработать пример из  http://adn-cis.org/kak-opredelit-napravlenie-vrashheniya-zamknutoj-polilinii.html.
Ну это у тебя бы точно не получилось. Во-первых, нормальных конвертеров C++ -> VB.NET априори быть не может, потому что C++ бывает не только managed, но и native (как в данном случае). И во-вторых, не для всякой функции/метода из ObjectARX есть эквивалент в AutoCAD .NET API. Так что перевод возможен только ручной, да и то не всегда.