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

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

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

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

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

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

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

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

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

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