Определение внуренних и внешних углов в контуре

Автор Тема: Определение внуренних и внешних углов в контуре  (Прочитано 22170 раз)

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

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

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

  • ADN OPEN
  • **
  • Сообщений: 59
  • Карма: 0
Добрый день!
Подскажите, есть ли возможность определить тип угла в контуре - внешний он или внутренний?

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Я вот сейчас ничего не понял)
Контур - это замкнутая полилиния? Тогда что такое внешний угол и внутренний угол? Я вот чисто из геометрии рассуждаю - в замкнутом контуре у нас есть только острый и тупой угол. И все они внутри!
Уточните вопрос, пожалуйста - о чем речь вообще

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

  • ADN OPEN
  • **
  • Сообщений: 59
  • Карма: 0
1) Да контур - замкнутая полилиния
2)


Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Как я и сказал - это острый угол и тупой. Первый <=90 градусов, второй > 90 градусов. Обычная геометрия
Если касаемо программы - просто проходите по сегментам полилинии и меряете угол между ними. Только вот есть куча нюансов: три типа полилинии, у которых разные методы работы и дуговые сегменты (хотя дуговые сегменты, думаю, не проблема)

Оффлайн bargool

  • ADN Club
  • ***
  • Сообщений: 111
  • Карма: 6
Возможно, имеется в виду, угол "поворачивает" "внутрь" контура, или "наружу". Человек, небось, решает какой-нибудь convex hull, или что-то подобное..
Алексей

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Человек, небось, решает какой-нибудь convex hull, или что-то подобное..
Человек ждет, когда ему готовое решение напишут. Знаю по прошлым темам  ;) ;D

Оффлайн bargool

  • ADN Club
  • ***
  • Сообщений: 111
  • Карма: 6
Кстати, вот тут есть пояснение, что такое внешние и внутренние углы. Но мы не знаем, что топик-стартер хотел на самом деле.
Алексей

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

  • ADN OPEN
  • **
  • Сообщений: 59
  • Карма: 0
Я так понимаю мне надо использовать GetLineSegmentAt()?
И нет я не жду готовое решение, пытаюсь разобраться сам.))) И прошу не давать готовый код)

Поправьте если буду не прав:
1) выбираем контур Autodesk.AutoCAD.EditorInput.Editor.GetSelection
2) Получаем количество вершин Autodesk.AutoCAD.DatabaseServices.Polyline.NumberOfVertices
3) В цикле от 0 до Autodesk.AutoCAD.DatabaseServices.Polyline.NumberOfVertices получаем сегменты контура
4) Считаем угол между сегментами

Оффлайн bargool

  • ADN Club
  • ***
  • Сообщений: 111
  • Карма: 6
Наконец-то посмотрел на картинку.
Я в этом случае делал так:
1. Три вершины смежных сегментов образуют треугольник.
2. Берём точку внутри этого треугольника (например, какую-нибудь характерную)
3. И определяем - внутри многоугольника эта точка, или снаружи. Задача о попадании точки внутрь многоугольника - легка. Если хотим самостоятельной работы - гуглится тоже легко (кстати, советую ресурс - там много хороших алгоритмов описано).
UPD: Правда, я работал не с автокадовскими кривыми, по-этому решал чисто геометрически.
Алексей

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Я так понимаю мне надо использовать GetLineSegmentAt()?
Если у вас полилиния является объектом Polyline, то да - вам подойдут:
Код - C# [Выбрать]
  1. lwp.GetArcSegment2dAt(int index);
  2. lwp.GetArcSegmentAt(int index);
  3. lwp.GetLineSegment2dAt(int index);
  4. lwp.GetLineSegmentAt(int index);
где index - номер вершины.
Итерацию по вершинам:
Код - C# [Выбрать]
  1. for (var i = 0; i < pline.NumberOfVertices; i++)
  2. {
  3. }

Если у вас Polyline2d или Polyline3d, то там другие методы работы (сам еще не знаю какие)

Все остальные манипуляции - геометрия и математика =)

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

  • ADN OPEN
  • **
  • Сообщений: 59
  • Карма: 0
Я так понимаю мне надо использовать GetLineSegmentAt()?
Если у вас полилиния является объектом Polyline, то да - вам подойдут:
Код - C# [Выбрать]
  1. lwp.GetArcSegment2dAt(int index);
  2. lwp.GetArcSegmentAt(int index);
  3. lwp.GetLineSegment2dAt(int index);
  4. lwp.GetLineSegmentAt(int index);
где index - номер вершины.
Итерацию по вершинам:
Код - C# [Выбрать]
  1. for (var i = 0; i < pline.NumberOfVertices; i++)
  2. {
  3. }

Если у вас Polyline2d или Polyline3d, то там другие методы работы (сам еще не знаю какие)

Все остальные манипуляции - геометрия и математика =)

Долго писал я, но видимо в правильном направлении.

Командой (entget(car(entsel))) выводит, что у меня контуры LWPOLYLINE. То есть мне подходит GetLineSegmentAt();?

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
То есть мне подходит GetLineSegmentAt();?
Ну тогда да - это ваш случай. Только нужно еще проверить, что это именно прямолинейный участок. Для этого подойдет метод GetBulge(int index) - если 0, значит прямолинейный

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Предлагаю простейший способ:
1) Получаем площадь полилинии S1.
2) Удаляем угловую вершину и получаем площадь полученной полилинии S2.
3) Сравниваем площади. Если S1 < S2 - угол внешний, S1 > S2 - внутренний, S1 == S2 - три точки на одной прямой.
4) Отменяю транзакцию (ну или восстанавливаю вершину).

Метод оказался заманчивым, но не универсальным.
« Последнее редактирование: 08-11-2015, 00:13:59 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Александр Ривилис, изящно! ))

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

  • ADN OPEN
  • **
  • Сообщений: 59
  • Карма: 0
Предлагаю простейший способ:
1) Получаем площадь полилинии S1.
2) Удаляем угловую вершину и получаем площадь полученной полилинии S2.
3) Сравниваем площади. Если S1 < S2 - угол внешний, S1 > S2 - внутренний, S1 == S2 - три точки на одной прямой.
4) Отменяю транзакцию (ну или восстанавливаю вершину).
Прошу прощения, но я как то не понял данного метода)
Площадь полилинии? Она же вроде =0, или я что то не понимаю(если это просто прямая)? Я однозначно чего то не понимаю....


Ааааааа, то есть удалив вершину, соединяем предыдущую и следующие вершины, после измеряем площадь получившегося контура? Таким образом?

Оффлайн art_rrc

  • ADN Club
  • **
  • Сообщений: 70
  • Карма: 1
  • Skype: art_sapranovich
То что здесь назвали "внешним" углом, делает фигуру невыпуклой. От этого можно и плясать. Создаем цикл по вершинам до .NumberOfVertices-1 и строим прямую от пред. точки до текущей, потом проверяем .InterSectWith, т.е. пересечение с нашим контуром (это метод VBA, не уверен что на С# так же). Если >0, то угол внешний.

Оффлайн trir

  • ADN Club
  • ****
  • Сообщений: 470
  • Карма: 63
Есть хорошая книжка - ISBN 5-94157-264-6
Советую почитать

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Ааааааа, то есть удалив вершину, соединяем предыдущую и следующие вершины, после измеряем площадь получившегося контура? Таким образом?
Да. И так итеративно перебрать все вершины, для каждой выполняя все 4 обозначенных пункта.

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

  • ADN OPEN
  • **
  • Сообщений: 59
  • Карма: 0
Попытался написать программку, на мой взгляд должно было работать, но выдает ошибку Unhandled Access Violation Reading 0x0000 Exception at 2a55ba83h(понять не могу в чем проблема)(((
Код - C# [Выбрать]
  1. namespace Angles
  2. {
  3.     public class FindAngles
  4.     {
  5.         [CommandMethod("Find", CommandFlags.Modal | CommandFlags.UsePickSet | CommandFlags.Redraw)]
  6.         public void test()
  7.         {
  8.             DocumentCollection acDocMgr = AcAp.Application.DocumentManager;
  9.             Document acDoc = acDocMgr.MdiActiveDocument;
  10.             Database acCurDb = acDoc.Database;
  11.             Editor ed = acDoc.Editor;
  12.             double polies = 0;
  13.             int S = 0, p=0;
  14.             double totalArea = 0;
  15.             double totalLength = 0;
  16.             ObjectId[] ids;
  17.             using (DocumentLock docLock = acDoc.LockDocument())
  18.             {
  19.                 using (Transaction tr = acCurDb.TransactionManager.StartTransaction())
  20.                 {
  21.                     PromptSelectionResult acSSPrompt = ed.GetSelection();
  22.                     if (acSSPrompt.Status == PromptStatus.OK)
  23.                     {
  24.                         SelectionSet acSSet = acSSPrompt.Value;
  25.                         foreach (SelectedObject acSSObj in acSSet)
  26.                         {
  27.                             if (acSSObj != null)
  28.                             {
  29.                                 Polyline polyk = tr.GetObject(acSSObj.ObjectId, OpenMode.ForWrite) as Polyline;
  30.                                 if (polyk != null)
  31.                                 {
  32.                                     polies = polyk.Area;
  33.                                     for (int j = 0; j < polyk.NumberOfVertices; j++)
  34.                                     {
  35.                                         polyk.RemoveVertexAt(j);
  36.                                         polyk.Close();
  37.                                         double k = polyk.Area;
  38.                                         if (k > polies)
  39.                                         {
  40.                                             S += 1;
  41.                                         }
  42.                                         if (k < polies)
  43.                                         {
  44.                                             p += 1;
  45.                                         }
  46.                                     }
  47.                                 }
  48.                             }
  49.                         }
  50.                     }
  51.                         tr.Commit();
  52.                 }
  53.             }
  54.             ed.WriteMessage("\n" + S + p);
  55.         }
  56.     }
  57. }

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
S1 == S2 - три точки на одной прямой
Если S1 == S2, то либо удалённая точка находится на одной прямой с предыдущей и последующей точками, либо эта точка имеет те же координаты, что и последующая (или предыдущая).

Оффлайн bargool

  • ADN Club
  • ***
  • Сообщений: 111
  • Карма: 6
Не учтён п.4 совета Александра Наумовича. В какой-то момент от полилинии ничего не останется

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
выдает ошибку Unhandled Access Violation Reading 0x0000 Exception at 2a55ba83h
Когда выкладываешь ведро кода, не забывай указывать номер строки, в которой выскакивает ошибку.

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
кроме того, что указал bargool, вряд ли имеет смысл пытаться получить площадь полилинии, состоящей лишь из двух оставшихся вершин (равно как и понять, какой же угол они образуют :) ).

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
не вижу в коде варианта, предусматривающего k == polies.

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

  • ADN OPEN
  • **
  • Сообщений: 59
  • Карма: 0
Не учтён п.4 совета Александра Наумовича. В какой-то момент от полилинии ничего не останется
Вспомнил об этом, уже когда написал на форум и уехал от компа. Сейчас буду пробовать.
На счет номера строки, просто выбивает ошибку без указания номера, сейчас попробую отловить ошибку.

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
На счет номера строки, просто выбивает ошибку без указания номера, сейчас попробую отловить ошибку.
Пошаговую отладку (F10, F11, etc) и breakpoint никто не отменял. Может и это заинтересует. :)

P.S. тынц (если интересно происхождение слова).

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

  • ADN OPEN
  • **
  • Сообщений: 59
  • Карма: 0
Про пошаговую слышал и знаю) просто не успел провести, исправил несколько ошибок и все заработало!!!!
1)в цикле перебора вершин запустил транзакцию, которую потом отменял(Abort).
2)polyk.close() стояло(ошибочно думал, что это делает полилинию замкнутой), изменил на polyk.Closed = true
Благодарю всех за помощь

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

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

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

  • ADN OPEN
  • **
  • Сообщений: 59
  • Карма: 0
melkalex90
Так и где результирующий (работающий код)?

Код - C# [Выбрать]
  1. namespace Angles
  2. {
  3.     public class FindAngles
  4.     {
  5.         [CommandMethod("Find", CommandFlags.Modal | CommandFlags.UsePickSet | CommandFlags.Redraw)]
  6.         public void test()
  7.         {
  8.             DocumentCollection acDocMgr = AcAp.Application.DocumentManager;
  9.             Document acDoc = acDocMgr.MdiActiveDocument;
  10.             Database acCurDb = acDoc.Database;
  11.             Editor ed = acDoc.Editor;
  12.             double polies = 0;
  13.             int S = 0, p=0;
  14.             double totalArea = 0;
  15.             double totalLength = 0;
  16.             ObjectId[] ids;
  17.  
  18.             try
  19.             {
  20.                 using (DocumentLock docLock = acDoc.LockDocument())
  21.                 {
  22.                     using (Transaction tr = acCurDb.TransactionManager.StartTransaction())
  23.                     {
  24.                         PromptSelectionResult acSSPrompt = ed.GetSelection();
  25.                         if (acSSPrompt.Status == PromptStatus.OK)
  26.                         {
  27.                             SelectionSet acSSet = acSSPrompt.Value;
  28.                             foreach (SelectedObject acSSObj in acSSet)
  29.                             {
  30.                                 if (acSSObj != null)
  31.                                 {
  32.                                     Polyline polyk = tr.GetObject(acSSObj.ObjectId, OpenMode.ForWrite) as Polyline;
  33.                                     if (polyk != null)
  34.                                     {
  35.                                         polies = polyk.Area;
  36.                                         for (int j = 0; j < polyk.NumberOfVertices; j++)
  37.                                         {
  38.                                             using (Transaction tr1 = acCurDb.TransactionManager.StartTransaction())
  39.                                             {
  40.                                                 polyk.RemoveVertexAt(j);
  41.                                                 double k = polyk.Area;
  42.                                                 polyk.Closed = true;
  43.  
  44.                                                 if (k > polies)
  45.                                                 {
  46.                                                     S += 1;
  47.                                                 }
  48.                                                 if (k < polies)
  49.                                                 {
  50.                                                     p += 1;
  51.                                                 }
  52.                                                 else
  53.                                                 {
  54.  
  55.                                                 }
  56.                                                 tr1.Abort();
  57.                                             }
  58.                                         }
  59.                                     }
  60.                                 }
  61.                             }
  62.                         }
  63.  
  64.                         tr.Commit();
  65.                     }
  66.                 }
  67.             }
  68.              catch(System.Exception ex)
  69.                 {
  70.                 ed.WriteMessage("\n" + ex.Message + "\n" + ex.StackTrace);
  71.             }
  72.            ed.WriteMessage("\n" + S + " " + p);
  73.         }
  74.     }
  75. }

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Предлагаю простейший способ:
1) Получаем площадь полилинии S1.
2) Удаляем угловую вершину и получаем площадь полученной полилинии S2.
3) Сравниваем площади. Если S1 < S2 - угол внешний, S1 > S2 - внутренний, S1 == S2 - три точки на одной прямой.
4) Отменяю транзакцию (ну или восстанавливаю вершину).
кстати, я не проверял, но как быть с ситуациями, когда удаление очередной вершины создаёт самопересекающийся контур? Сейчас вожусь не с акадом, поэтому бросить всё и начать проверять не могу...

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
melkalex90, а что это хитрая конструкция в виде не относящейся ни к чему вложенной транзакции? Ты объекты получаешь при помощи внешней, а внутренная-то тебе зачем?

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Цитата: melkalex90
Код - C# [Выбрать]
  1. Polyline polyk = tr.GetObject(acSSObj.ObjectId, OpenMode.ForWrite) as Polyline;
  2.   if (polyk != null)
  3.   {
Почему не хочешь отфильтровывать лишнее? Зачем пытаться приводить к полилинии то, что ею не является, если этого легко можно избежать (представь, что пользователь нажмёт комбинацию клавиш Ctrl + A)?

Смотри второй параметр перегруженого варианта метода:
Код - C# [Выбрать]
  1. Editor.GetSelection Method (PromptSelectionOptions, SelectionFilter)
ну, или этот, на худой конец:
Код - C# [Выбрать]
  1. Editor.GetSelection Method (SelectionFilter)

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

  • ADN OPEN
  • **
  • Сообщений: 59
  • Карма: 0
melkalex90, а что это хитрая конструкция в виде не относящейся ни к чему вложенной транзакции? Ты объекты получаешь при помощи внешней, а внутренная-то тебе зачем?
Честно признаюсь, я так не разобрался, для чего конкретно нужна транзакция.  Александр Ривилис написал: 4) Отменяю транзакцию (ну или восстанавливаю вершину), - потому решил попробовать добавить ее. И оно заработало.
Цитата: melkalex90
Код - C# [Выбрать]
  1. Polyline polyk = tr.GetObject(acSSObj.ObjectId, OpenMode.ForWrite) as Polyline;
  2.   if (polyk != null)
  3.   {
Почему не хочешь отфильтровывать лишнее? Зачем пытаться приводить к полилинии то, что ею не является, если этого легко можно избежать (представь, что пользователь нажмёт комбинацию клавиш Ctrl + A)?

Смотри второй параметр перегруженого варианта метода:
Код - C# [Выбрать]
  1. Editor.GetSelection Method (PromptSelectionOptions, SelectionFilter)
ну, или этот, на худой конец:
Код - C# [Выбрать]
  1. Editor.GetSelection Method (SelectionFilter)
А это сделаю.

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Зачем пытаться приводить к полилинии то, что ею не является, если этого легко можно избежать
Так вроде он избежал =) При использовании оператора as, если объект не полилиния, в переменную polyk запишется null. А далее он проверяет polyk != null...

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Так вроде он избежал =)
Он не избежал попытки приведения. Фильтрация это устраняет.

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Он не избежал попытки приведения. Фильтрация это устраняет.
Конечно с фильтрацией намного правильней будет. Но и ошибки он не допустил ))
А про фильтрацию ему уже писали раньше...

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
melkalex90, а что это хитрая конструкция в виде не относящейся ни к чему вложенной транзакции? Ты объекты получаешь при помощи внешней, а внутренная-то тебе зачем?
А вот тут я был неправ... Нашёл в документации:
Цитата: ObjectARX SDK
Transactions can be nested—that is, you can start one transaction inside another and end or abort the recent transaction. The transaction manager maintains transactions in a stack, with the most recent transaction at the top of the stack. When you start a new transaction using AcTransactionManager::startTransaction(), the new transaction is added to the top of the stack and a pointer to it is returned (an instance of AcTransaction). When someone calls AcTransactionManager::endTransaction() or AcTransactionManager::abortTransaction(), the transaction at the top of the stack is ended or aborted.

When object pointers are obtained from object IDs, they are always associated with the most recent transaction. You can obtain the recent transaction using AcTransactionManager::topTransaction(), then use AcTransaction::getObject() or AcTransactionManager::getObject() to obtain a pointer to an object. The transaction manager automatically associates the object pointers obtained with the recent transaction. You can use AcTransaction::getObject() only with the most recent transaction.

When nested transactions are started, the object pointers obtained in the outer containing transactions are also available for operation in the innermost transaction. If the recent transaction is aborted, all the operations done on all the objects (associated with either this transaction or the containing ones) since the beginning of the recent transaction are canceled and the objects are rolled back to the state at the beginning of the recent transaction. The object pointers obtained in the recent transaction cease to be valid once it's aborted.

If the innermost transaction is ended successfully by calling AcTransactionManager::endTransaction(), the objects whose pointers were obtained in this transaction become associated with the containing transaction and are available for operation. This process is continued until the outermost (first) transaction is ended, at which time modifications on all the objects are committed. If the outermost transaction is aborted, all the operations on all the objects are canceled and nothing is committed.

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
А про фильтрацию ему уже писали раньше...
Не вижу этого в теме, потому и пишу о фильтрации.

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Не вижу этого в теме, потому и пишу о фильтрации
Писал вот тут - а это тема того-же автора. Причем в другой части кода (уверен, что той-же самой программы) как раз фильтрация и используется
А так - повторение - мать учения =)

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

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

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Здесь добавил:
Цитата: Андрей Бушман
Менеджер транзакций автоматически ассоциирует все ранее полученные объекты (и операции, производимые над ними) с самой последней транзакцией из стека имеющихся транзакций.

Когда запущена вложенная транзакция - объекты, полученные во внешней транзакции, будут также доступны для работы во вложенной. Если вложенная транзакция будет прервана, то и все операции, выполненные в рамках этой транзакции, над объектами (не важно в какой транзакции эти объекты были получены: во внешней или во внутренней) так же будут отменены и объекты откатываются к тому состоянию, в котором они находились в момент начала работы вложенной транзакции.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Мне кажется, что такой вариант должен работать быстрее:

Код - C# [Выбрать]
  1. using System;
  2. using System.Collections.Generic;
  3. using Autodesk.AutoCAD.Runtime;
  4. using Autodesk.AutoCAD.ApplicationServices;
  5. using Autodesk.AutoCAD.DatabaseServices;
  6. using Autodesk.AutoCAD.Geometry;
  7. using Autodesk.AutoCAD.EditorInput;
  8.  
  9. #pragma warning disable 0618
  10.  
  11. [assembly: CommandClass(typeof(Rivilis.TestPolygon))]
  12.  
  13. namespace Rivilis
  14. {
  15.   public class TestPolygon
  16.   {
  17.     [CommandMethod("TP", CommandFlags.Modal | CommandFlags.UsePickSet)]
  18.     public void MyCommand()
  19.     {
  20.       Document doc = Application.DocumentManager.MdiActiveDocument;
  21.       if (doc == null) return;
  22.       Editor ed = doc.Editor;
  23.       Database db = doc.Database;
  24.       PromptSelectionOptions pso = new PromptSelectionOptions();
  25.       pso.MessageForAdding = "\nВыберите полилинии: ";
  26.       pso.MessageForRemoval = "\nУдалите полилинии: ";
  27.       TypedValue[] filList = new TypedValue[1] {
  28.         new TypedValue((int)DxfCode.Start, "LWPOLYLINE")
  29.       };
  30.       SelectionFilter sf = new SelectionFilter(filList);
  31.       PromptSelectionResult psr = ed.GetSelection(pso, sf);
  32.       if (psr.Status == PromptStatus.OK) {
  33.         foreach (ObjectId id in psr.Value.GetObjectIds()) {
  34.           var inds = GetVertexiesDesc(id);
  35.           int i = 0; // Считаем количество выпуклых углов
  36.           foreach (var ind in inds) if (ind.Value) i++;
  37.           ed.WriteMessage("\nВ полилинии {0} выпуклых углов {1}",
  38.             id.Handle.ToString(), i);
  39.         }
  40.       }
  41.     }
  42.  
  43.     /// <summary>
  44.     /// Получаем коллекцию пар (номер вершины) - (флаг выпуклости вершины)
  45.     /// </summary>
  46.     /// <param name="id">ObjectId полилинии.</param>
  47.     /// <returns></returns>
  48.     public static Dictionary<int, bool> GetVertexiesDesc(ObjectId id)
  49.     {
  50.       var inds = new Dictionary<int, bool>();
  51.       using (Polyline poly = id.Open(OpenMode.ForWrite) as Polyline) {
  52.         double s = poly.Area;
  53.         for (int i = 0; i < poly.NumberOfVertices; i++) {
  54.           double bulge = poly.GetBulgeAt(i);
  55.           Point2d p = poly.GetPoint2dAt(i);
  56.           poly.RemoveVertexAt(i); // Удаляем вершину
  57.           double s1 = poly.Area;
  58.           poly.AddVertexAt(i, p, bulge, 0, 0); // Возвращаем вершину
  59.           if (s > s1) inds.Add(i, true); else inds.Add(i, false);
  60.         }
  61.         poly.Cancel();
  62.       }
  63.       return inds;
  64.     }
  65.   }
  66. }
кстати, я не проверял, но как быть с ситуациями, когда удаление очередной вершины создаёт самопересекающийся контур?
Доказать не могу, но во всех моих тестах при получении самопересекающегося контура всё срабатывало правильно. Похоже, что такие контура могут получится только если угол выпуклый. А если он выпуклый, то его удаление в любом случае уменьшают площадь. В прочем на 100% утверждать не берусь.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн art_rrc

  • ADN Club
  • **
  • Сообщений: 70
  • Карма: 1
  • Skype: art_sapranovich
Контур коридора вполне может оказаться таким. Тут скорее нужна доп. информация от автора, какого плана фигуры будут обрабатываться.

Оффлайн art_rrc

  • ADN Club
  • **
  • Сообщений: 70
  • Карма: 1
  • Skype: art_sapranovich
Мой вариант с прямыми лишен такого бага, но вот для такого варианта не подойдет. Но такого может и не быть, либо автор может о нем знать и применить Ваш способ.

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

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

Отмечено как Решение Александр Ривилис 07-11-2015, 17:51:44

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Почти не тестировал, но похоже работает:

Код - C# [Выбрать]
  1. using System;
  2. using System.Collections.Generic;
  3. using Autodesk.AutoCAD.Runtime;
  4. using Autodesk.AutoCAD.ApplicationServices;
  5. using Autodesk.AutoCAD.DatabaseServices;
  6. using Autodesk.AutoCAD.Geometry;
  7. using Autodesk.AutoCAD.EditorInput;
  8.  
  9. #pragma warning disable 0618
  10.  
  11. [assembly: CommandClass(typeof(Rivilis.TestPolygon))]
  12.  
  13. namespace Rivilis
  14. {
  15.   public class TestPolygon
  16.   {
  17.     [CommandMethod("TP", CommandFlags.Modal | CommandFlags.UsePickSet)]
  18.     public void MyCommand()
  19.     {
  20.       Document doc = Application.DocumentManager.MdiActiveDocument;
  21.       if (doc == null) return;
  22.       Editor ed = doc.Editor;
  23.       Database db = doc.Database;
  24.       PromptSelectionOptions pso = new PromptSelectionOptions();
  25.       pso.MessageForAdding = "\nВыберите полилинии: ";
  26.       pso.MessageForRemoval = "\nУдалите полилинии: ";
  27.       TypedValue[] filList = new TypedValue[1] {
  28.         new TypedValue((int)DxfCode.Start, "*POLYLINE")
  29.       };
  30.       SelectionFilter sf = new SelectionFilter(filList);
  31.       PromptSelectionResult psr = ed.GetSelection(pso, sf);
  32.       if (psr.Status == PromptStatus.OK) {
  33.         foreach (ObjectId id in psr.Value.GetObjectIds()) {
  34.           var inds = GetVertexiesDesc(id);
  35.           int i = 0; // Считаем количество выпуклых углов
  36.           foreach (var ind in inds) if (ind.Value) i++;
  37.           ed.WriteMessage("\nВ полилинии {0} выпуклых углов {1}",
  38.             id.Handle.ToString(), i);
  39.         }
  40.       }
  41.     }
  42.  
  43.     /// <summary>
  44.     /// Получаем коллекцию пар (номер вершины) - (флаг выпуклости вершины)
  45.     /// </summary>
  46.     /// <param name="id">ObjectId полилинии.</param>
  47.     /// <returns></returns>
  48.     public static Dictionary<int, bool> GetVertexiesDesc(ObjectId id)
  49.     {
  50.       var inds = new Dictionary<int, bool>();
  51.       using (Curve poly = id.Open(OpenMode.ForRead) as Curve) {
  52.         Vector3d norm = Vector3d.ZAxis;
  53.         try { norm = poly.GetPlane().Normal; } catch { }
  54.         // Количество вершин полилинии. Если полилиния незамкнутая, то
  55.         // к EndParam нужно добавить 1.
  56.         int nVerts = (int)(poly.EndParam + (poly.Closed ? 0 : 1) + 1e-6);
  57.  
  58.         // Полный угол со знаком для определения направления:
  59.         // обход по часовой или против часовой стрелки.
  60.         double angle = 0;
  61.         // Коллекция углов в каждой из вершин
  62.         List<double> angles = new List<double>(nVerts);
  63.  
  64.         for (int i = 0; i < nVerts; i++) {
  65.           Point3d p1 = poly.GetPointAtParameter((i) % nVerts);
  66.           Point3d p2 = poly.GetPointAtParameter((i+1) % nVerts);
  67.           Point3d p3 = poly.GetPointAtParameter((i+2) % nVerts);
  68.           double ang = signedAngle(p1, p2, p3, norm);
  69.           angles.Add(ang); angle += ang;
  70.         }
  71.         for (int i = 0; i < angles.Count; i++) {
  72.           inds.Add(i, angle * angles[i] > 0);
  73.         }
  74.       }
  75.       return inds;
  76.     }
  77.  
  78.     /// <summary>
  79.     /// Функция получает угол со знаком между указанными векторами, заданными точками,
  80.     /// относительно плоскости заданной нормалью
  81.     /// </summary>
  82.     public static double signedAngle(Point3d p1, Point3d p2, Point3d p3, Vector3d norm)
  83.     {
  84.       return signedAngle(p2 - p1, p3 - p2, norm);
  85.     }
  86.     /// <summary>
  87.     /// Функция получает угол со знаком между указанными векторами,
  88.     /// относительно плоскости заданной нормалью
  89.     /// </summary>
  90.     public static double signedAngle(Vector3d v1, Vector3d v2, Vector3d norm)
  91.     {
  92.       Vector3d v3 = v1.CrossProduct(v2);
  93.       double angle = Math.Acos(v1.GetNormal().DotProduct(v2.GetNormal()));
  94.       return angle * Math.Sign(v3.DotProduct(norm));
  95.     }
  96.   }
  97. }

Достоинство этого алгоритма в том, что он не модифицирует полилинии и потенциально значительно быстрее алгоритма с вычислением площади. Ну и работает как с LWPOLYLINE, так и с POLYLINE
« Последнее редактирование: 07-11-2015, 17:28:25 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN OPEN
  • **
  • Сообщений: 59
  • Карма: 0
Доброе утро. Честно сказать каких конкретно видов будет коридор не могу, но пример коридора, из объекта с которым я в данный момент тестирую программу вот:


Оффлайн art_rrc

  • ADN Club
  • **
  • Сообщений: 70
  • Карма: 1
  • Skype: art_sapranovich
тестирую программу
Программу для чего? На какой вы рассчитываете ИТОГ? Может быть вам вовсе не нужна информация о типе угла, а достаточно немного скорректировать логику программы.

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

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

Оффлайн art_rrc

  • ADN Club
  • **
  • Сообщений: 70
  • Карма: 1
  • Skype: art_sapranovich
Не смотрели мой последний код? Интересно всё ли я там учёл.
Очень логичный подход. Т.к. нужно определить тип угла, то и работать нужно с углами (имхо), что и реализовано. И если не придираться к незначительным проверкам (см. вложение, ответ должен быть явно 2 или 4 или предупреждение что плиния не замкнута), то на моих тестовых примерах все работает корректно (т.к. речь идет о комнатах, то вывернутые плинии не тестировал).

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

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

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

  • ADN OPEN
  • **
  • Сообщений: 59
  • Карма: 0
тестирую программу
Программу для чего? На какой вы рассчитываете ИТОГ? Может быть вам вовсе не нужна информация о типе угла, а достаточно немного скорректировать логику программы.
В итоге должно быть приложение, которое по заданным параметрам(размеры помещений, кол-во внутренних и внешних углов), считает кол-во материалов необходимых для отделки объекта. В связи с тем, что L и F профили считаются по количеству внутренних и внешних углов в помещении, то у меня есть необходимость проводить эти расчеты(на сколько я понимаю по другому(ну не считая ручной ввод) этого не реализовать).

melkalex90, art_rrc
Не смотрели мой последний код? Интересно всё ли я там учёл.
Пока еще не успел, только приехал домой. Сейчас попробую проверить.

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

  • ADN OPEN
  • **
  • Сообщений: 59
  • Карма: 0
Александр, работает, считает все выпуклые углы. Пока не разобрался с самим кодом, буду разбираться) Спасибо.

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

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

Оффлайн NurGeo

  • ADN OPEN
  • Сообщений: 31
  • Карма: 1
Конечно решение по коду найдено, но вдруг кому понадобится. В геодезии есть правило. Сумма внутренних углов замкнутого полигона равна (180*n-2), сумма внешних углов полигона равна (180*n+2). n-количество углов в полигоне. Исходя из этого можно было узнать какие углы высчитаны внутренние или внешние.

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

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

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
какие углы высчитаны
расчитаны, вычислены.... может вычесаны? :)

Оффлайн NurGeo

  • ADN OPEN
  • Сообщений: 31
  • Карма: 1
Не понял. Как это ты из суммы углов собираешься определить внутренний или внешний конкретный из углов многоугольника?
Ну, если постоянно отнимать от угла (XYAxis) передней линии обратный угол задней линии, то ты будешь получать всегда угол с одной стороны полигона. Вычислив углы на всех вершинах по этому методу и по данным формулам можно узнать, какими являются все вычисленные углы.
расчитаны, вычислены.... может вычесаны?
Что поделать, русский язык никогда у меня не был в любимых предметах, а щас когда вырос, часто неудобно из-за этого.  ::)

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

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