SelectCrossingPolygon. Как отловить некорректный контур?

Автор Тема: SelectCrossingPolygon. Как отловить некорректный контур?  (Прочитано 19627 раз)

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

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Здравствуйте!
Столкнулся с неприятной ошибкой в работе моей программы, связанной с тем, что в метод PromptSelectionResult передаются точки, образующие контур с самопересечениями.
Результатом работы метода редактора SelectCrossingPolygon является объект PromptSelectionResult с двумя свойствами - статус и значение. Если в метод передать некорректный контур или в указанном контуре не окажется нужных объектов, то возвращаемое значение метода будет одинаково: статус - Error, значение - null. Мне нужно отловить ситуацию, когда в метод передается некорректный контур. Как это можно сделать? Может быть есть какой-то способ проверки контура на корректность для передачи в метод?
Спасибо.

Для примера:
Код - C# [Выбрать]
  1. [CommandMethod("SelectCrossingTest")]
  2.         public void SelectCrossingTest()
  3.         {
  4.             Document adoc = Application.DocumentManager.MdiActiveDocument;
  5.             Database db = adoc.Database;
  6.             Editor ed = adoc.Editor;
  7.  
  8.             PromptEntityOptions entOpt = new PromptEntityOptions("\nSelect pline: ");
  9.             entOpt.SetRejectMessage("Is NOT pline!");
  10.             entOpt.AddAllowedClass(typeof(Polyline), true);
  11.  
  12.             PromptEntityResult entRes = ed.GetEntity(entOpt);
  13.             if (entRes.Status != PromptStatus.OK) return;
  14.  
  15.             ObjectId plineId = entRes.ObjectId;
  16.  
  17.             Point3dCollection gripPts = new Point3dCollection();
  18.  
  19.             using (Transaction tr = db.TransactionManager.StartTransaction())
  20.             {
  21.                 Polyline pline = tr.GetObject(plineId, OpenMode.ForRead) as Polyline;                
  22.                 pline.GetGripPoints(gripPts, new IntegerCollection(), new IntegerCollection());
  23.                 tr.Commit();
  24.             }
  25.  
  26.             PromptSelectionResult selRes = ed.SelectCrossingPolygon(gripPts, new SelectionFilter(new TypedValue[]{ new TypedValue((int)DxfCode.Start, "CIRCLE")}));
  27.             ed.WriteMessage("\nStatus: {0}", selRes.Status);
  28.         }

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Может быть есть какой-то способ проверки контура на корректность для передачи в метод?
Если имеется в виду "некорректный" == "самопересекающийся", то очевидным ответом будет проверить на самопересечение. Например, каждый сегмент, заданный точкой начала и конца, проверяется на пересечение со всеми остальными (кроме двух соседних). Если пересечение есть, и это не касание в конечных точках, то контур "некорректный".
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Да кто же его знает, что еще может подразумеваться под "некорректным". Сегодня вот такой нашли вариант - самопересекающийся, завтра может быть еще какой-то найдем :). Странно, что исключение в методе при этом не возникает.
Я подумал, что, возможно, есть какой-то стандартный способ проверки. Как-то же метод понимает, что контур ему не подходит?
И непонятно, в каком случае касание допустимое, а в каком - недопустимое. Проверил на 4-х разных контурах:
1-й - статус "ОК".
2-й - статус "Error" т.к. нет объектов внутри.
3-й - статус "Error" т.к. некорректный контур
4-й - статус "ОК", хотя самопересечение есть...
« Последнее редактирование: 27-01-2014, 18:36:36 от Загорулькин Дмитрий »

Отмечено как Решение Дмитрий Загорулькин 08-10-2014, 14:43:36

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Я вспомнил, что когда-то много лет назад использовал в ObjectARX для проверка на самопересечение класс AcDbMPolygon. Решил немного поэкспериментировать и получил такой код:

Код - C# [Выбрать]
  1. using System;
  2. using Autodesk.AutoCAD.Runtime;
  3. using Autodesk.AutoCAD.ApplicationServices;
  4. using Autodesk.AutoCAD.DatabaseServices;
  5. using Autodesk.AutoCAD.Geometry;
  6. using Autodesk.AutoCAD.EditorInput;
  7.  
  8. [assembly: CommandClass(typeof(Rivilis.TestSelfCrossing))]
  9.  
  10. namespace Rivilis
  11. {
  12.   public class TestSelfCrossing
  13.   {
  14.     [CommandMethod("TestCross", CommandFlags.Modal)]
  15.     public void TestCross()
  16.     {
  17.       Document adoc = Application.DocumentManager.MdiActiveDocument;
  18.       Database db = adoc.Database;
  19.       Editor ed = adoc.Editor;
  20.       PromptEntityOptions entOpt = new PromptEntityOptions("\nВыберите полилинию: ");
  21.       entOpt.SetRejectMessage("Это не полилиния!");
  22.       entOpt.AddAllowedClass(typeof(Polyline), true);
  23.       PromptEntityResult entRes = ed.GetEntity(entOpt);
  24.       if (entRes.Status != PromptStatus.OK) return;
  25.       Point3dCollection gripPts = new Point3dCollection();
  26.       MPolygon mpoly = new MPolygon();
  27.       bool isValidBoundary = false;
  28.       using (Transaction tr = db.TransactionManager.StartTransaction()) {
  29.         Polyline pline = tr.GetObject(entRes.ObjectId, OpenMode.ForRead) as Polyline;
  30.         pline.GetGripPoints(gripPts, new IntegerCollection(), new IntegerCollection());
  31.         try {
  32.           mpoly.AppendLoopFromBoundary(pline, true, Tolerance.Global.EqualPoint);
  33.           if (mpoly.NumMPolygonLoops != 0) {
  34.             isValidBoundary = true;
  35.           }
  36.         } catch {}
  37.         tr.Commit();
  38.       }
  39.       mpoly.Dispose();
  40.       if (isValidBoundary) {
  41.         PromptSelectionResult selRes = ed.SelectCrossingPolygon(gripPts, new SelectionFilter(new TypedValue[] { new TypedValue((int)DxfCode.Start, "CIRCLE") }));
  42.         ed.WriteMessage("\nStatus: {0}", selRes.Status);
  43.       } else {
  44.         ed.WriteMessage("\nНеподходящая граница!");
  45.       }
  46.     }
  47.   }
  48. }
  49.  

Несколько оговорок:
1. Необходимо к проекту подключить сборку AcMPolygonMGD.dll и установить для неё Copy Local в False
2. Я проверял только в AutoCAD 2013, но эта сборка есть во всех версиях начиная как минимум с AutoCAD 2008
3. Возможно она не пропустит контура, которые SelectCrossingPolygon и пропустила бы...
4. Работать будет только если UCS == WCS и полилиния лежит в плоскости WCS (это касается и твоего кода тоже).
5. Полилиния должна быть видна целиком на экране.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Интересное решение. Покрутил его и так и эдак - работает как надо! Буду думать, как его пристроить в программу. Спасибо!

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
У класса MPolygon есть еще много интересных возможностей. Например, проверка попадания точки внутрь контура.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Так это вообще великолепно! Можно будет вообще избавиться от использования SelectCrossingPolygon! Вычислить ключевые точки объектов и проверить, находятся ли они внутри полигона.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Ну если тебе достаточно проверять попадание точек параллелепипеда (Entity.GeometricExtents) внутрь контура - то это было бы оптимально. Лично я очень не люблю SelectCrossingPolygon и аналогичные методы, которые требуют видимость объектов на экране.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Думаю, мне достаточно будет даже попадание в контур только одной характерной точки объекта. Если при этом не выберутся объекты, частично попадающие в контур, но с характерной точкой вне его, то это будет даже плюсом.

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Я правильно понимаю, что если IntegerCollection, которую возвращает метод IsPointInsideMPolygon, будет непустая, то точка попала в контур? "Метод тыка" подтверждает это, но может быть как-то по другому надо?
Если это так, то заметил интересную особенность - если контур накладывается сам на себя, то точка внутри него не опознается. Например, для контура как на картинке, в зонах 1 и 4 точка распознается как точка внутри контура, а в зонах 2 и 3 - как вне его.
Код - C# [Выбрать]
  1. namespace Rivilis
  2. {
  3.     public class TestSelfCrossing
  4.     {
  5.         [CommandMethod("TestMPoly", CommandFlags.Modal)]
  6.         public void TestCross()
  7.         {
  8.             Document adoc = Application.DocumentManager.MdiActiveDocument;
  9.             Database db = adoc.Database;
  10.             Editor ed = adoc.Editor;
  11.             PromptEntityOptions entOpt = new PromptEntityOptions("\nВыберите полилинию: ");
  12.             entOpt.SetRejectMessage("Это не полилиния!");
  13.             entOpt.AddAllowedClass(typeof(Polyline), true);
  14.             PromptEntityResult entRes = ed.GetEntity(entOpt);
  15.             if (entRes.Status != PromptStatus.OK) return;
  16.  
  17.             Point2dCollection polyPts = new Point2dCollection();
  18.             using (Transaction tr = db.TransactionManager.StartTransaction())
  19.             {
  20.                 Polyline pline = tr.GetObject(entRes.ObjectId, OpenMode.ForRead) as Polyline;
  21.                 Point3dCollection gripPts = new Point3dCollection();
  22.                 pline.GetGripPoints(gripPts, new IntegerCollection(), new IntegerCollection());
  23.  
  24.                 foreach (Point3d pt in gripPts)
  25.                 {
  26.                     polyPts.Add(new Point2d(pt.X, pt.Y));
  27.                 }
  28.  
  29.                 tr.Commit();
  30.             }
  31.  
  32.             PromptPointResult ptRes = ed.GetPoint("\nУкажите точку: ");
  33.  
  34.             if (ptRes.Status != PromptStatus.OK) return;
  35.  
  36.             Point2dCollection testPrs = new Point2dCollection();
  37.             testPrs.Add(new Point2d(ptRes.Value.X, ptRes.Value.Y));
  38.  
  39.             bool[] testRes = PolygonPointsTest(polyPts, testPrs);
  40.  
  41.  
  42.             Application.ShowAlertDialog(testRes[0] ? "Точка внутри контура" : "Точка вне контура");
  43.         }
  44.  
  45.  
  46.  
  47.         public static bool[] PolygonPointsTest(Point2dCollection polygonPts, Point2dCollection testPts)
  48.         {
  49.             List<bool> testRes = new List<bool>();
  50.             using (MPolygon mPoly = new MPolygon())
  51.             {
  52.                 MPolygonLoop mpLoop = new MPolygonLoop();
  53.                 foreach (Point2d pt in polygonPts)
  54.                 {
  55.                     mpLoop.Add(new BulgeVertex(pt, 0.0));
  56.                 }
  57.  
  58.                 // Для того чтобы получить нормальный контур, нужно добавить первую точку
  59.                 mpLoop.Add(new BulgeVertex(polygonPts[0], 0.0));
  60.  
  61.                 mPoly.AppendMPolygonLoop(mpLoop, false, Tolerance.Global.EqualPoint);
  62.  
  63.                 foreach (Point2d pt in testPts)
  64.                 {
  65.                     IntegerCollection intCol = mPoly.IsPointInsideMPolygon(new Point3d(pt.X, pt.Y, 0.0), Tolerance.Global.EqualPoint);
  66.                     testRes.Add(intCol.Count > 0);
  67.                 }
  68.             }
  69.  
  70.             return testRes.ToArray();
  71.         }
  72.     }
  73. }
« Последнее редактирование: 06-02-2014, 17:03:21 от Загорулькин Дмитрий »

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Да.
Если это так, то заметил интересную особенность - если контур накладывается сам на себя, то точка внутри него не опознается. Например, для контура как на картинке, в зонах 1 и 4 точка распознается как точка внутри контура, а в зонах 2 и 3 - как вне его.
Это же у тебя самопересекающийся контур. Ты мог его сразу отсечь как некорректный.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Да, поначалу была идея сообщать пользователю о некорректном контуре и прерывать программу. Но беда в том, что автокад позволяет создавать самопересекающиеся контуры видовых экранов (я ищу объекты определенного типа, отображающиеся в отдельном видовом экране). Если стандартные возможности позволяют это, а программа будет говорить "нельзя", то это в некотором роде ущемление свободы действий пользователя.
Сейчас поэкспериментировал с ВЭ - логика отображения совпадает с логикой обнаружения точек внутри MPolygon. Так что, благодаря Вам, идеальный способ обнаружения нужных объектов найден! Спасибо еще раз!

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Но беда в том, что автокад позволяет создавать самопересекающиеся контуры видовых экранов
Это извращение! Я думаю что раз твоя программа анализирует контуры видовых экранов, то неплохо было бы и сообщать пользователю об этих "извращениях". Скорее всего он это сделал случайно и даже понятия об этом не имеет.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Ну то что я нарисовал - конечно извращение жуткое :)
А вот скрин участка чертежа, на котором споткнулась моя программа и из-за чего и пошел сыр-бор. Согласен, что это тоже не очень грамотно. Насчет предупреждения подумаю, может быть добавлю.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Не можешь спросить у автора этого чертежа в чем глубинный смысл "елозить" по одному месту (наложение сегментов полилилинии в левом нижнем углу чертежа)? Это небрежность или тут какой-то глубинный смысл?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Небрежность в чистом виде. В этом случае можно было обойтись стандартным прямоугольным ВЭ.

Оффлайн Константин Виноградов

  • ADN OPEN
  • Сообщений: 12
  • Карма: 2
Здравствуйте. В первом посту данной теме нашел для себя интересный код, для выбора объектов внутри полилинии. Пытался его реализовать для замкнутой полилинии состоящей из 4х точек.
При выполнении метода tr.Commit(), отладчик выдает сообщение "ArgumentNullException was unhandled by user code". Пытался найти причину неприятности, по поиск оказался безуспешным.
Единственное обратил внимание, что объект gripPts, после выполнения метода pline.GetGripPoints остался пустым. Помогите пожалуйста решить мою проблему.

                Polyline pline = tr.GetObject(plineId, OpenMode.ForRead) as Polyline;               
                pline.GetGripPoints(gripPts, new IntegerCollection(), new IntegerCollection());
                tr.Commit();

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
По куску кода непонятно, давайте весь метод.
Навскидку - может объект не полилиния, может коллекцию забыли создать для gripPts.

Оффлайн Константин Виноградов

  • ADN OPEN
  • Сообщений: 12
  • Карма: 2
Виноват, но не хотел грузить форум лишним текстом. И еще я код адаптировал под visual basic.net. Проблемный участок находится на строчках 36-39.


Код - vb.net [Выбрать]
  1.   Public Sub GetAddressList(ByVal ed As Editor)
  2.     Dim doc As Document = Application.DocumentManager.MdiActiveDocument
  3.     Dim db As Database = doc.Database
  4.     Dim MyT As Transaction = db.TransactionManager.StartTransaction()
  5.  
  6.     Dim values() As TypedValue = {New TypedValue(DxfCode.ExtendedDataRegAppName, "PLCHOUSENUMBER"), _
  7.     New TypedValue(DxfCode.LayoutName, "MODEL")}
  8.     Dim sfilter As New SelectionFilter(values)
  9.     Dim Res As PromptSelectionResult
  10.     ed.WriteMessage(vbLf & "Выберите дома для нового кластера.")
  11.     ed.UpdateScreen()
  12.  
  13.     Dim pKeyOpts As PromptKeywordOptions = New PromptKeywordOptions("")
  14.     pKeyOpts.Message = vbLf & "Каким методом выбора объекта вы хотите воспользоваться?"
  15.     pKeyOpts.Keywords.Add("Полигон")
  16.     pKeyOpts.Keywords.Add("Одиночно")
  17.     pKeyOpts.AllowNone = False
  18.     Dim pKeyRes As PromptResult = ed.GetKeywords(pKeyOpts)
  19.  
  20.     Select Case pKeyRes.StringResult
  21.       Case "Полигон"
  22.         Dim entOpt As PromptEntityOptions
  23.         entOpt = New PromptEntityOptions("\nВыберите полилинию:")
  24.         entOpt.SetRejectMessage("Это не полилиния!")
  25.         entOpt.AddAllowedClass(GetType(Polyline), True)
  26.         Dim entRes As PromptEntityResult
  27.         entRes = ed.GetEntity(entOpt)
  28.         If entRes.Status <> PromptStatus.OK Then
  29.           Exit Sub
  30.         End If
  31.         Dim pLineId As ObjectId = entRes.ObjectId
  32.         Dim gripPts As Point3dCollection = New Point3dCollection()
  33.         Dim pline As Polyline
  34.         MyT = db.TransactionManager.StartTransaction()
  35.         pline = MyT.GetObject(pLineId, OpenMode.ForRead)
  36.         pline.GetGripPoints(gripPts, New IntegerCollection(), New IntegerCollection())
  37.  
  38.         '       MyT.AddNewlyCreatedDBObject(gripPts, True)
  39.         MyT.Commit()
  40.         MyT.Dispose()
  41.  
  42.         Res = ed.SelectCrossingPolygon(gripPts, sfilter)
  43.         '       Res = ed.GetEntity(peo)
  44.       Case "Одиночно"
  45.         Res = ed.GetSelection(sfilter)
  46.     End Select
  47.  
  48.     If Res.Status = PromptStatus.Error Then
  49.       ed.WriteMessage(ControlChars.CrLf)
  50.       ed.WriteMessage("Чертеж не содержит номеров домов.")
  51.       ed.UpdateScreen()
  52.       Return
  53.     End If
  54.  
  55.     Dim acBlkTbl As BlockTable
  56.     acBlkTbl = MyT.GetObject(db.BlockTableId, OpenMode.ForRead)
  57.     'Dim acBlkTblRec As BlockTableRecord
  58.     'acBlkTblRec = MyT.GetObject(acBlkTbl(BlockTableRecord.ModelSpace), OpenMode.ForWrite)
  59.  
  60.  
  61.     Dim SS As Autodesk.AutoCAD.EditorInput.SelectionSet = Res.Value
  62.     Dim IdArray As ObjectId() = SS.GetObjectIds()
  63.  
  64.     Dim Id As ObjectId
  65.     Dim c As Long = 0
  66.     ReDim ad(SS.Count - 1)
  67.  
  68.     For Each Id In IdArray
  69.       Dim hn As BlockReference = MyT.GetObject(Id, OpenMode.ForRead)
  70.       Dim rs As Array = hn.GetXDataForApplication("ESTATE_DATAS").AsArray()
  71.       Dim rsFID As ResultBuffer = hn.GetXDataForApplication("FID")
  72.       If rsFID = Nothing Then
  73.       Else
  74.         ad(c).Fid = rsFID.AsArray(2).Value
  75.       End If
  76.       c = c + 1
  77.     Next
  78.     ad = GetExcelData(ad)
  79.  
  80.     Dim AdData As AddressDatas
  81.     Dim quartes As Integer
  82.     quartes = 0
  83.     For Each AdData In ad
  84.       quartes = quartes + AdData.Quarters
  85.     Next
  86.     Dim s As StringBuilder = New StringBuilder()
  87.     s.Append("В выбраных домах количество квартир равняется ")
  88.     s.Append(quartes)
  89.     ed.WriteMessage(s.ToString())
  90.     ed.WriteMessage(ControlChars.CrLf)
  91.     ed.UpdateScreen()
  92.  
  93.     BuildAddressTable(ed, ad)
  94.   End Sub
  95.  

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
А тут налицо стандартные грабли использования транзакций. Смотрите сколько их открыто и сколько закрыто. А вообще - приучайте себя использовать конструкцию Using для транзакций.

Оффлайн Константин Виноградов

  • ADN OPEN
  • Сообщений: 12
  • Карма: 2
На счет граблей, согласен. Я когда пытался найти причину создал лишнюю параллельную транзакцию. В данном методе я все переделал под использовании конструкции using для транзакции, но ошибка осталась та же. В pline содержатся 4 точки, в gripPts.
Ниже код приложил, как кнопку скрыть добавить на этом форуме не нашел.
Код - vb.net [Выбрать]
  1.   Public Sub GetAddressList(ByVal ed As Editor)
  2.     Dim doc As Document = Application.DocumentManager.MdiActiveDocument
  3.     Dim db As Database = doc.Database
  4.  
  5.     Dim values() As TypedValue = {New TypedValue(DxfCode.ExtendedDataRegAppName, "PLCHOUSENUMBER"), _
  6.     New TypedValue(DxfCode.LayoutName, "MODEL")}
  7.     Dim sfilter As New SelectionFilter(values)
  8.     Dim Res As PromptSelectionResult
  9.     ed.WriteMessage(vbLf & "Выберите дома для нового кластера.")
  10.     ed.UpdateScreen()
  11.  
  12.     Dim pKeyOpts As PromptKeywordOptions = New PromptKeywordOptions("")
  13.     pKeyOpts.Message = vbLf & "Каким методом выбора объекта вы хотите воспользоваться?"
  14.     pKeyOpts.Keywords.Add("Полигон")
  15.     pKeyOpts.Keywords.Add("Одиночно")
  16.     pKeyOpts.AllowNone = False
  17.     Dim pKeyRes As PromptResult = ed.GetKeywords(pKeyOpts)
  18.  
  19.     Select Case pKeyRes.StringResult
  20.       Case "Полигон"
  21.         Dim entOpt As PromptEntityOptions
  22.         entOpt = New PromptEntityOptions("\nВыберите полилинию:")
  23.         entOpt.SetRejectMessage("Это не полилиния!")
  24.         entOpt.AddAllowedClass(GetType(Polyline), True)
  25.         Dim entRes As PromptEntityResult
  26.         entRes = ed.GetEntity(entOpt)
  27.         If entRes.Status <> PromptStatus.OK Then
  28.           Exit Sub
  29.         End If
  30.         Dim pLineId As ObjectId = entRes.ObjectId
  31.         Dim gripPts As Point3dCollection = New Point3dCollection()
  32.         Dim pline As Polyline
  33.         Using MyT As Transaction = db.TransactionManager.StartTransaction()
  34.           pline = MyT.GetObject(pLineId, OpenMode.ForRead)
  35.           pline.GetGripPoints(gripPts, New IntegerCollection(), New IntegerCollection())
  36.           '       MyT.AddNewlyCreatedDBObject(gripPts, True)
  37.           MyT.Commit()
  38.           MyT.Dispose()
  39.         End Using
  40.         Res = ed.SelectCrossingPolygon(gripPts, sfilter)
  41.         '       Res = ed.GetEntity(peo)
  42.       Case "Одиночно"
  43.         Res = ed.GetSelection(sfilter)
  44.     End Select
  45.  
  46.     If Res.Status = PromptStatus.Error Then
  47.       ed.WriteMessage(ControlChars.CrLf)
  48.       ed.WriteMessage("Чертеж не содержит номеров домов.")
  49.       ed.UpdateScreen()
  50.       Return
  51.     End If
  52.     Using MyT As Transaction = db.TransactionManager.StartTransaction()
  53.       Dim acBlkTbl As BlockTable
  54.       acBlkTbl = MyT.GetObject(db.BlockTableId, OpenMode.ForRead)
  55.       'Dim acBlkTblRec As BlockTableRecord
  56.       'acBlkTblRec = MyT.GetObject(acBlkTbl(BlockTableRecord.ModelSpace), OpenMode.ForWrite)
  57.     End Using
  58.  
  59.  
  60.     Dim SS As Autodesk.AutoCAD.EditorInput.SelectionSet = Res.Value
  61.     Dim IdArray As ObjectId() = SS.GetObjectIds()
  62.     Dim Id As ObjectId
  63.     Dim c As Long = 0
  64.     ReDim ad(SS.Count - 1)
  65.     Using MyT As Transaction = db.TransactionManager.StartTransaction()
  66.       For Each Id In IdArray
  67.  
  68.         Dim hn As BlockReference = MyT.GetObject(Id, OpenMode.ForRead)
  69.  
  70.         Dim rs As Array = hn.GetXDataForApplication("ESTATE_DATAS").AsArray()
  71.         Dim rsFID As ResultBuffer = hn.GetXDataForApplication("FID")
  72.  
  73.         If rsFID = Nothing Then
  74.  
  75.         Else
  76.           ad(c).Fid = rsFID.AsArray(2).Value
  77.         End If
  78.         c = c + 1
  79.  
  80.       Next
  81.     End Using
  82.     ad = GetExcelData(ad)
  83.  
  84.     Dim AdData As AddressDatas
  85.     Dim quartes As Integer
  86.     quartes = 0
  87.     For Each AdData In ad
  88.       quartes = quartes + AdData.Quarters
  89.     Next
  90.     Dim s As StringBuilder = New StringBuilder()
  91.     s.Append("В выбраных домах количество квартир равняется ")
  92.     s.Append(quartes)
  93.     ed.WriteMessage(s.ToString())
  94.     ed.WriteMessage(ControlChars.CrLf)
  95.     ed.UpdateScreen()
  96.  
  97.     BuildAddressTable(ed, ad)
  98.   End Sub
  99.  

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Давай полностью проект (в zip-архиве) вместе с файлом, на котором экспериментируешь и укажи версию AutoCAD. Хотя мне совершенно непонятно зачем вызывать метод GetGripPoints для получения вершин полилинии.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Ну как минимум явный вызов .Dispose() не нужен.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Ну как минимум явный вызов .Dispose() не нужен.
100%
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Константин Виноградов

  • ADN OPEN
  • Сообщений: 12
  • Карма: 2
В приложении полностью проект, команда в Autocad Unitcount.
На счет .dispose попробую удалить.
Версия autocad 2008
« Последнее редактирование: 15-05-2014, 14:15:33 от Константин Виноградов »

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Версия autocad 2008
Похоже это баг в AutoCAD .NET API этой версии, а так как она уже давно не поддерживается, то находи вершины полилинии другим способом.
Кстати, этот код не будет работать ни в одной ПСК не равной МСК и если чертеж не будет виден целиком на экране.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Константин Виноградов

  • ADN OPEN
  • Сообщений: 12
  • Карма: 2
Версия autocad 2008
Похоже это баг в AutoCAD .NET API этой версии, а так как она уже давно не поддерживается, то находи вершины полилинии другим способом.
Кстати, этот код не будет работать ни в одной ПСК не равной МСК и если чертеж не будет виден целиком на экране.
Спасибо большое за ответ.
Очень жаль. Похоже придется перенести код на Autocad 2011 (для другой версии лицензии нет), который вроде тоже не поддерживается уже. Хотя может и стоило бы вручную перебрать вершины полилинии и добавить их в коллекцию Point3DCollection.
На счет МСК не проблем, а вот почему весь чертеж должен быть виден на экране, подскажите пожалуйста?

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
На счет МСК не проблем, а вот почему весь чертеж должен быть виден на экране, подскажите пожалуйста?
Метод Editor.SelectCrossingPolygon, как и большинство методов Editor.SelectXXX, требует чтобы все точки, которые ему переданы были видны на экране, т.к. этот метод оперирует не с базой данных чертежа, а с его отображением на экран (точнее на активный видовой порт).
Поэтому по возможности следует отказаться от использования этих методов, т.к. их использование может приводить к очень странным результатам.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Константин Виноградов

  • ADN OPEN
  • Сообщений: 12
  • Карма: 2
Александр Ривилис,  спасибо понял. Данную проблему раньше встречал при обычном выборе объектов, когда точки выбора за видовой экран уходили.
Извините, что замучил, но хотел задать последний вопрос. Я вот смотрю почти везде примеры приведены на C#, стоит ли мне с Visual Basic перейти на C#? Данный переход проблем в принципе не составит.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Я вот смотрю почти везде примеры приведены на C#, стоит ли мне с Visual Basic перейти на C#? Данный переход проблем в принципе не составит.
Лично я рекомендовал бы перейти на C#.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Константин Виноградов

  • ADN OPEN
  • Сообщений: 12
  • Карма: 2
Александр Ривилис, спасибо большое.

Оффлайн Алексей (IdeaSoft)

  • ADN
  • *
  • Сообщений: 1188
  • Карма: 9
    • idea-soft.ru
  • Skype: makar_govorun
Да кто же его знает, что еще может подразумеваться под "некорректным".

Под "некорректным" может быть скорее еще случай, когда координаты X и Y узлов совпадают.
Может еще на это стоит проверять?

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Под "некорректным" может быть скорее еще случай, когда координаты X и Y узлов совпадают.
Может еще на это стоит проверять?
Речь о контуре для Editor.SelectCrossingPolygon? Если да, то несколько соображений на вскидку:
1. Точки должны передаваться в UCS (ПСК), а не в WCS (МСК).
2. Не думаю что совпадающие вершины будут мешать, но нужно проверять экспериментально. Возможно разное поведение в разных версиях AutoCAD.
3. Вершины должны быть в одной плоскости.
4. Не должно быть самопересекающихся сегментов.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN OPEN
  • ***
  • Сообщений: 119
  • Карма: 5
Здравствуйте, знаю, что это очень старая тема.
У меня тоже возникла необходимость проверять полилинии на самопересечение. Я решил эту проблему с помощью метода IntersectWith.
Хочу поделиться:
Код - C# [Выбрать]
  1.         private bool PolylineIsSelfIntersecting(Polyline poly)
  2.         {
  3.             Dictionary<Point3d, int?> polyPts = new Dictionary<Point3d, int?>();
  4.             int vertCount = poly.NumberOfVertices;
  5.             for (int i = 0; i < vertCount; i++)
  6.             {
  7.                 Point3d pt3d = poly.GetPoint3dAt(i);
  8.                 //Если точки повторяются, то есть самопересечение
  9.                 //Но допускается повторение первой и последней точек
  10.                 int? existPtNum = null;
  11.                 polyPts.TryGetValue(pt3d, out existPtNum);
  12.                 if (existPtNum==null//Такой точки не было
  13.                     ||(i== vertCount-1 && existPtNum==0))//Такая тока была, но это замыкание, а не самопересечение
  14.                 {
  15.                     polyPts[pt3d]= i;
  16.                 }
  17.                 else
  18.                     return true;  
  19.             }
  20.             //Использование метода IntersectWith
  21.             Point3dCollection intersectionPts = new Point3dCollection();
  22.             poly.IntersectWith(poly, Intersect.OnBothOperands, intersectionPts, IntPtr.Zero, IntPtr.Zero);
  23.  
  24.             foreach (Point3d intersectionPt in intersectionPts)
  25.             {
  26.                 if (!polyPts.Keys.Contains(intersectionPt))
  27.                 {
  28.                     return true;
  29.                 }
  30.             }
  31.  
  32.             return false;
  33.         }
  34.  

Оффлайн RevitTormentor

  • ADN OPEN
  • ***
  • Сообщений: 162
  • Карма: 6
1DhgvrWLWtLBt8hosfjNHt8Lqv8tK59F89
Иногда встречаю в примерах такие кракозябры. Это запутать взломщиков такая штука? Или это как то подвязано с ID кнопок на панели? Тоже у кого то встречал такое "запутанное" дело.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
1DhgvrWLWtLBt8hosfjNHt8Lqv8tK59F89
Иногда встречаю в примерах такие кракозябры. Это запутать взломщиков такая штука? Или это как то подвязано с ID кнопок на панели? Тоже у кого то встречал такое "запутанное" дело.
Где вы этот код нашли? Проверьте свой комп на вирусы/трояны.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн RevitTormentor

  • ADN OPEN
  • ***
  • Сообщений: 162
  • Карма: 6
Да я Александр не про свой комп, про примеры кода на форуме.
Например этот у Александра увидел

Код - C# [Выбрать]
  1.    private void DocumentManager_DocumentCreated(object sender, Autodesk.AutoCAD.ApplicationServices.1DhgvrWLWtLBt8hosfjNHt8Lqv8tK59F89 e)
  2.         {
  3.             AcApp.DocumentManager.MdiActiveDocument.ImpliedSelectionChanged -= MdiActiveDocument_ImpliedSelectionChanged;
  4.             AcApp.DocumentManager.MdiActiveDocument.ImpliedSelectionChanged += MdiActiveDocument_ImpliedSelectionChanged;
  5.         }
  6.  

Почему то не работает у меня вставка кода в виде кода. Попробовал в ручном режиме первый tag не помню как пишется
« Последнее редактирование: 04-02-2018, 14:40:29 от Александр Ривилис »

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Да я Александр не про свой комп, про примеры кода на форуме.
Например этот у Александра увидел
У какого Александра? Где ссылка на пост с этим кодом?
Почему то не работает у меня вставка кода в виде кода.
Кто-бы сомневался. У тебя на компе вирус, связанный с Bitcoin. Поищи в гугле эту строку: 1DhgvrWLWtLBt8hosfjNHt8Lqv8tK59F89
У нас на сайте и форуме эта строка есть только в твоих сообщениях. В данном коде у тебя строка DocumentCollectionEventArgs заменена на 1DhgvrWLWtLBt8hosfjNHt8Lqv8tK59F89. Явный вирус.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн RevitTormentor

  • ADN OPEN
  • ***
  • Сообщений: 162
  • Карма: 6
Видимо да т.к. даже это сообщение я вижу вот так




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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Да. А должно было быть так:



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

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

  • ADN OPEN
  • ***
  • Сообщений: 119
  • Карма: 5
Еще раз, очень старая тема, но я еще хочу добавить по поводу проверки на самопересечение.
Сейчас в AutoCAD 2018 я пользуюсь таким методом:
Код - C# [Выбрать]
  1.         /// <summary>
  2.         /// Полилиния пересекает сама себя
  3.         /// </summary>
  4.         /// <param name="poly"></param>
  5.         /// <returns></returns>
  6.         public static bool PolylineIsSelfIntersecting(Polyline poly)
  7.         {
  8.             Curve3d curve3D = poly.GetGeCurve();
  9.             CurveCurveIntersector3d intersector = new CurveCurveIntersector3d(curve3D, curve3D, Vector3d.ZAxis);
  10.  
  11.             return intersector.NumberOfIntersectionPoints > 0;
  12.         }
  13.  
В документации к классу CurveCurveIntersector3d прямо сказано, что для нахождения самопересечений нужно передать в качестве параметров ссылку на одну и ту же кривую.
Я не знаю, есть ли этот класс в более старых версиях API.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Я не знаю, есть ли этот класс в более старых версиях API.
Есть как минимум с AutoCAD 2008.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение