Сделать порядок следования вершин полилинии по часовой стрелке

Автор Тема: Сделать порядок следования вершин полилинии по часовой стрелке  (Прочитано 8292 раз)

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

Оффлайн Захаров МаксимАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 141
  • Карма: 3
Здравствуйте.
Подскажите пожалуйста алгоритм. Как мне программно узнать порядок следования вершин в полилинии (по часовой стрелке или против часовой). Дуговых сегментов нет.
Спасибо

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Отмечено как Решение Александр Ривилис 23-10-2018, 19:49:50

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Захаров МаксимАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 141
  • Карма: 3
Спасибо Александр.
Воспользовался конвертером. Буду разбираться.

Оффлайн Кирилл Захаров

  • ADN OPEN
  • ***
  • Сообщений: 119
  • Карма: 5
Могу предложить метод, которым я пользовался:
Код - 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.  

Воспользовался конвертером.
А можно узнать, что за конвертер?

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Могу предложить метод, которым я пользовался:
Это упрощенный вариант кода Gilles Chanteau без учета дуговых сегментов.
А можно узнать, что за конвертер?
Я так понимаю, что это один из конвертеров C#->VB.NET. Есть и онлайн-конвертеры, есть и в составе SharpDevelop
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Кирилл Захаров

  • ADN OPEN
  • ***
  • Сообщений: 119
  • Карма: 5
Ага, спасибо, Александр

Оффлайн Захаров МаксимАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 141
  • Карма: 3
Я использовал конвертер "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

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Я использовал конвертер "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
« Последнее редактирование: 29-10-2018, 23:31:55 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Захаров МаксимАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 141
  • Карма: 3
Спасибо Александр.
Я понял что второй пример на C# сделан. Но я так и смог понять как в пределах одного класса существует 3 функции с одинаковыми именами, поэтому и не получилось. Щас естественно все заработало. А конвертером "C++ to VB Converter" я пытался переработать пример из  http://adn-cis.org/kak-opredelit-napravlenie-vrashheniya-zamknutoj-polilinii.html.
В любом случае спасибо большое.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
А конвертером "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. Так что перевод возможен только ручной, да и то не всегда.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение