Как выборку объектов отсортировать по координате. Скажем полилинии по Z

Автор Тема: Как выборку объектов отсортировать по координате. Скажем полилинии по Z  (Прочитано 4943 раз)

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

Оффлайн anatoly53Автор темы

  • ADN OPEN
  • Сообщений: 10
  • Карма: 0

фотки с интернета

Задача простая, по выбранным полилиниям я строю треугольники и считаю площадь. Можно, конечно загнать в массив, обработать там, но это сложнее. Пока SelectionSet делаю руками. Утомительно это. Хотел сделать сортировку в новую выборку, тогда код уже готов.
******************************************************************************
Код - Visual Basic [Выбрать]
  1. Sub Plo4()
  2. 'Посчитать площадь м/у полилиниями по 4 точкам. Или по 3м, разделив их диагональю
  3. 'По 4м получается пропепеллер и пло не совсем та. Нужно вычислять перпендикуляр,....
  4. 'Разделив на 2 треугольника получим более простой и точный расчет.
  5. 'Главное - правильная сортировка пар горизонталей.
  6. 'Предпологаем, что по Z все получится, иначе можно использовать трангуляцию.
  7. 'Сортируем и обрабатываем пары.
  8.  
  9. Dim elem As Object
  10. Dim SelSet As AcadSelectionSet
  11. Dim nS As Integer
  12. Dim i As Integer, j As Integer
  13. 'Dim p1(0 To 3) As Double, p2 As Double  'координаты пар горизонталей
  14. Dim p1 As Variant, p2 As Variant
  15. Dim pp(0 To 8) As Double    'массив точек треугольника
  16. Dim S As Double, p As Double
  17. Dim sumS As Double
  18. 'Dim lin3 As Acad3DPolyline
  19. 'Dim p3(0 To 5) As Double
  20. Dim pntN(0 To 2) As Double
  21. Dim pntK(0 To 2) As Double
  22. Dim l3 As Acad3DPolyline
  23. Dim ot3 As AcadLine
  24. On Error Resume Next
  25. ThisDrawing.SelectionSets.Item("mySS").Delete
  26. Set SelSet = ThisDrawing.SelectionSets.Add("mySS")
  27. Set SelSet = ThisDrawing.ActiveSelectionSet
  28. On Error GoTo 0
  29. 'Set SelSet = ThisDrawing.ActiveSelectionSet
  30. nS = SelSet.Count
  31. 'Пока считаем, что все полилинии. И сортировка как надо. Потом добавим массив отсортированных объектов плолилиний
  32. For j = 0 To nS - 2
  33. i = i + 1
  34.         p1 = SelSet.Item(j).Coordinates
  35.         p2 = SelSet.Item(j + 1).Coordinates
  36. If Abs(p1(0) - p2(0)) > Abs(p1(0) - p2(2)) Then
  37.     pntN(0) = p2(0)
  38.     pntN(1) = p2(1)
  39.     p2(0) = p2(2)
  40.     p2(1) = p2(3)
  41.     p2(2) = pntN(0)
  42.     p2(3) = pntN(1)
  43. End If
  44.        
  45.         pp(0) = p1(0)   'т1 x
  46.        pp(1) = p1(1)   'т1 y
  47.        pp(2) = SelSet.Item(j).Elevation    'т1 z
  48.        
  49.         pp(3) = p1(2)   'т2 x
  50.        pp(4) = p1(3)   'т2 y
  51.        pp(5) = pp(2)   'т2 z
  52.        
  53.         pp(6) = p2(0)   'т3 x
  54.        pp(7) = p2(1)   'т3 y
  55.        pp(8) = SelSet.Item(j + 1).Elevation   'т3 z
  56. If 1 = 2 Then
  57.         Set l3 = ThisDrawing.ModelSpace.Add3DPoly(pp)
  58.         l3.color = acGreen
  59. End If
  60. pntN(0) = pp(3): pntN(1) = pp(4): pntN(2) = pp(5)
  61. GoSub Perimetr
  62. sumS = sumS + S
  63. 'Второй треугольник
  64.        pp(0) = p2(0)   'т1/2 x
  65.        pp(1) = p2(1)   'т2/2 y
  66.        pp(2) = SelSet.Item(j + 1).Elevation    'т1/2 z
  67.        
  68.         pp(3) = p2(2)   'т2/2 x
  69.        pp(4) = p2(3)   'т2/2 y
  70.        pp(5) = pp(2)   'т2/2 z
  71.        
  72.         pp(6) = p1(2)   'т3/2 x
  73.        pp(7) = p1(3)   'т3/2 y
  74.        pp(8) = SelSet.Item(j).Elevation    'т3/2 z
  75. If 1 = 2 Then
  76.         Set l3 = ThisDrawing.ModelSpace.Add3DPoly(pp)
  77.         l3.color = acBlue
  78. End If
  79. GoSub Perimetr
  80.         sumS = sumS + S
  81. If 1 = 1 Then
  82.         pntK(0) = pp(0): pntK(1) = pp(1): pntK(2) = pp(5)
  83.         Set ot3 = ThisDrawing.ModelSpace.AddLine(pntN, pntK)
  84.         ot3.color = acCyan
  85.     End If
  86. Next
  87. sumS = (Round(sumS, 0))
  88. MsgBox (i & " трапеций(я). Площадь =" & sumS)
  89. Exit Sub
  90. Perimetr:
  91. 'S = p · (p - a) · (p - b) · (p - c) p-полупериметр
  92. a = (p2(0) - pp(3)) ^ 2 + (pp(1) - pp(4)) ^ 2 + (pp(2) - pp(5)) ^ 2
  93. a = Sqr(a)
  94. b = (pp(3) - pp(6)) ^ 2 + (pp(4) - pp(7)) ^ 2 + (pp(5) - pp(8)) ^ 2
  95. b = Sqr(b)
  96. c = (pp(6) - pp(0)) ^ 2 + (pp(7) - pp(1)) ^ 2 + (pp(8) - pp(2)) ^ 2
  97. c = Sqr(c)
  98. p = (a + b + c) / 2
  99. S = p * (p - a) * (p - b) * (p - c)
  100. S = Sqr(S)
  101.  
  102. Return
  103. End Sub

« Последнее редактирование: 21-02-2023, 21:17:51 от Александр Ривилис »

Оффлайн alz

  • ADN OPEN
  • **
  • Сообщений: 93
  • Карма: 11
Мне кажется только писать саму сортировку
что то типа такого, правда на шарпе

       
Код - C# [Выбрать]
  1. //функция сортировки
  2.         private List<Polyline> SortPoint(List<Polyline> result)
  3.         {
  4.             //если есть что сортировать, минимум 2 элемента
  5.             //если нечего возвращаем полученный список
  6.             if (result.Count > 1)
  7.             {
  8.                 //создаем список с отсортированными значениями
  9.                 List<Polyline> sorted_coll = new List<Polyline>();
  10.                 //проходим по первоначальному списку пока в нем еще есть неотсортированные элементы
  11.                 while (result.Count > 0)
  12.                 {
  13.                     //переменная для хранения полилинии с минимальной высотой
  14.                     Polyline lowPoly;
  15.                     //переменная для хранения минимальной высоты
  16.                     double minElev = 0;
  17.                     //проходим по всем полилиниям в переданном списке
  18.                     for (int i = 0; i < result.Count; i++)
  19.                     {
  20.                         //если полилинии в переменной еще нет то первую записываем в нее а так же ее высоту в минимальную
  21.                         if (i == 0)
  22.                         {
  23.                             lowPoly = result[i];
  24.                             minElev = result[i].Elevation;
  25.                         }
  26.                         else
  27.                         {
  28.                             //если в переменной полилинии что-то хранится то сравниваем ее отметку с текущей
  29.                             //если отметка ниже то перезаписываем минимальную полилинию и ее отметку
  30.                             if (result[i].Elevation < minElev)
  31.                             {
  32.                                 lowPoly = result[i];
  33.                                 minElev = result[i].Elevation ;
  34.                             }
  35.                         }
  36.                     }
  37.                     //после прохода по всем полилиниям в списке удаляем минимальную по высоте и добавляем ее в отсортированный список
  38.                     result.Remove(lowPoly );
  39.                     sorted_coll.Add(lowPoly );
  40.                 }
  41.                 //возвращаем отсортированный список
  42.                 return sorted_coll;
  43.             }
  44.             return result;
  45.         }


Ну и как вариант вроде можно создать кортеж типа (высота , полилиния) забить их в список и просто отсортировать через линк, выглядит компактнее, но насколько это оптимально даже не знаю кортежи списки и линк вроде как в vba доступны
Код - C# [Выбрать]
  1.   private List<Polyline> SortPoint(List<Polyline> result)
  2.         {
  3.             if (result.Count > 1)
  4.             {      
  5.                 //создаем список кортежей        
  6.                 List<(double, Polyline)> cor = new List<(double, Polyline)>();
  7.                 foreach (Polyline p in result)
  8.                 {
  9.                     //добавляем  кортеж из высоты и полилинии в список
  10.                     cor.Add((p.Elevation, p));
  11.                 }
  12.                 //сортируем кортеж
  13.                 cor = cor.OrderBy(c => c.Item1).ToList();
  14.                 //заменяем элементы первоначального списка отсортированными
  15.                 result.Clear();
  16.                 foreach ((double, Point3d) c in cor)
  17.                 {
  18.                     result.Add(c.Item2);
  19.                 }                
  20.             }
  21.             return result;
  22.         }

Ну и третий вариант в голову пришел просто собрать в список отметки всех линий, отсортировать стандартной сортировкой а потом пройтись по списку и закинуть в отсортированный список полилинии соответствующие отметкам

Код - C# [Выбрать]
  1.   private List<Polyline> SortPoint(List<Polyline> result)
  2.         {
  3.             if (result.Count > 1)
  4.             {      
  5.                 //создаем список с отметками
  6.                 List<double> el = new List<double>();
  7.                 foreach (Polyline p in result)
  8.                 {
  9.                     el.Add(p.Elevation);
  10.                 }
  11.                 //сортируем отметки
  12.                 el.Sort();
  13.                 //создаем список отсортированных результатов
  14.                 List<Point3d> reslist = new List<Point3d>();
  15.                 //записываем в него полилинии в соответствии с отметками
  16.                 foreach (double e in el)
  17.                 {
  18.                     for (int i = 0; i < result.Count; i++)
  19.                     {
  20.                         if (e.Equals(result[i].Elevation))
  21.                         {
  22.                             reslist.Add(result[i]);
  23.                             result.Remove(result[i]);
  24.                             break;
  25.                         }
  26.                     }
  27.                 }
  28.                 return reslist;    
  29.             }
  30.             return result;
  31.         }

Может кто тут из корифеев скажет что из этого эффективнее? Или свой вариант попроще покажет.
« Последнее редактирование: 22-03-2023, 11:00:35 от alz »

Оффлайн alz

  • ADN OPEN
  • **
  • Сообщений: 93
  • Карма: 11
Блин, посидел покумекал, и понял что все это с линком делается вообще через одну  строчку а городил до этого ((

Код - C# [Выбрать]
  1. SelSet = SelSet.OrderBy(c => c.Elevation).ToList();