Получение объектов модели в границах видового экрана на листе

Автор Тема: Получение объектов модели в границах видового экрана на листе  (Прочитано 17156 раз)

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

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

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

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

Сделал тестовый проект и тестовый чертеж. К теме прикладываю и то и другое. В тексте тоже код напишу для дискуссий
Функция состоит из одного окошка с кнопкой. Вызов функции:
Код - C# [Выбрать]
  1. public class Class1
  2. {
  3.     // Вызов функции
  4.     Win _mpTotals;
  5.     [CommandMethod("VPtest", CommandFlags.Modal)]
  6.     public void Main()
  7.     {
  8.         if (_mpTotals == null)
  9.         {
  10.             _mpTotals = new Win();
  11.             _mpTotals.Closed += win_Closed;
  12.         }
  13.  
  14.         if (_mpTotals.IsLoaded)
  15.             _mpTotals.Activate();
  16.         else
  17.             AcApp.ShowModelessWindow(AcApp.MainWindow.Handle, _mpTotals);
  18.     }
  19.     void win_Closed(object sender, EventArgs e)
  20.     {
  21.         _mpTotals = null;
  22.         Utils.SetFocusToDwgView();
  23.     }
  24. }
Обработка нажатия кнопки:
Извините, вам запрещён просмотр содержимого спойлеров.

Список листов специально так сделан в списке потому что код выдергивал из большого проекта
Работа с листом:
Извините, вам запрещён просмотр содержимого спойлеров.

Код выбора объектов в модели брал тут. Мне кажется, что он косячный....
В общем на строчке ed.SwitchToModelSpace(); ловится ошибка eCannotChangeActiveViewport, а в командной строек пишется Нет активных видовых экранов в пространстве модели. Ошибка ловится, если я нахожусь, например, на Лист1, а видовой экран на Лист2. Если в момент запуска функции я буду на Лист2, то все сработает

Возможно к вечеру у меня уже каша в голове....  :(

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

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

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Так может сначала нужно переключится на Лист2?
Так я вроде это и делаю)) Ну пытаюсь по крайней мере - в коде обработки нажатия на кнопку это происходит
Цитировать
lm.CurrentLayout = layout;

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

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

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

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

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Еще немного потестив, выяснил, что ошибка происходит на Лист1! При итерации по объектам листа там находится видовой экран, которого физически в общем-то там нет
Значит вопрос - как "проверять" видовые экраны на их реальное существование? (да, глупо звучит ))) )

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

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

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Ты не с той стороны подходишь. Иди со стороны Layout.GetViewports - это и будут видовые экраны листа
Я сейчас начну плакать и смеяться одновременно  :'(
Урезал до самого минимума приложенный в топике код. Теперь просто получить инфу по видовым экранам листа:
Код - C# [Выбрать]
  1. private List<string> layouts = new List<string>
  2. {
  3.     "Лист1",
  4.     "Лист2",
  5.     "Лист3",
  6.     "Лист4"
  7. };
  8.  
  9. private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
  10. {
  11.     try
  12.     {
  13.         var doc = AcApp.DocumentManager.MdiActiveDocument;
  14.         var ed = doc.Editor;
  15.         var db = HostApplicationServices.WorkingDatabase;
  16.  
  17.         var lm = LayoutManager.Current;
  18.         using (doc.LockDocument())
  19.         {
  20.             foreach (var layout in layouts)
  21.             {
  22.                 lm.CurrentLayout = layout;
  23.                 ed.WriteMessage("\n layout: " + lm.CurrentLayout);
  24.                 // Данные из таблиц
  25.                 GetDataFromTablesForLayout(
  26.                     layout,
  27.                     db);
  28.             }
  29.         }
  30.  
  31.     }
  32.     catch (Exception ex)
  33.     {
  34.         MessageBox.Show(ex.Message);
  35.     }
  36. }
  37.  
  38. [DllImport("accore.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedTrans")]
  39. private static extern int acedTrans(double[] point, IntPtr fromRb, IntPtr toRb, int disp, double[] result);
  40.  
  41. private void GetDataFromTablesForLayout(string layoutName, Database db)
  42. {
  43.     var ed = AcApp.DocumentManager.MdiActiveDocument.Editor;
  44.     using (var tr = db.TransactionManager.StartTransaction())
  45.     {
  46.         var layoutDic = tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead, false) as DBDictionary;
  47.         if (layoutDic != null)
  48.         {
  49.             foreach (var entry in layoutDic)
  50.             {
  51.                 var layoutId = entry.Value;
  52.                 var layout = tr.GetObject(layoutId, OpenMode.ForRead) as Layout;
  53.                 if (layout != null && layout.LayoutName.Equals(layoutName))
  54.                 {
  55.                     var vps = layout.GetViewports();
  56.                     foreach (ObjectId objectId in vps)
  57.                     {
  58.                         using (var psVp = (Viewport)tr.GetObject(objectId, OpenMode.ForRead))
  59.                         {
  60.                             ed.WriteMessage("nViewPorts count: " + vps.Count);
  61.                             ed.WriteMessage("\nON: " + psVp.On);
  62.                             ed.WriteMessage("\nNumber: " + psVp.Number);
  63.                             ed.WriteMessage("\nTransparent: " + psVp.Transparent);
  64.                         }
  65.                     }
  66.                     break;
  67.                 }
  68.             }
  69.         }
  70.         tr.Commit();
  71.     }
  72. }
Для тестирования использую все тот-же файл (он приложен в топике). В файле у меня вставлены видовые экраны на Лист2 и Лист3. А вот, что я получаю в командной строке после работы кода:
Цитировать
Команда: VPTEST

Команда:
 layout: Лист1nViewPorts count: 1
ON: True
Number: 1
Transparent: TrueВыполняется регенерация листов.
Регенерация модели - кэширование видовых экранов.

 layout: Лист2nViewPorts count: 2
ON: True
Number: 1
Transparent: TruenViewPorts count: 2
ON: True
Number: 2
Transparent: TrueВыполняется регенерация листов.
Регенерация модели - кэширование видовых экранов.

 layout: Лист3nViewPorts count: 2
ON: True
Number: 1
Transparent: TruenViewPorts count: 2
ON: True
Number: 2
Transparent: TrueВыполняется регенерация листов.

 layout: Лист4nViewPorts count: 1
ON: True
Number: 1
Transparent: TrueВосстановление кэшированных видовых экранов - Выполняется регенерация листов.
Выполняется регенерация листов.

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Дальше больше - у "несуществующих" видовых экранов даже есть GeometricExtents  :D
Цитировать
layout: Лист1
ViewPorts count: 1
GeometricExtents: ((-7296.28715820779,-19707.9341033739,0),(107843.647167478,49022.2680983523,0))
Выполняется регенерация листов.
Регенерация модели - кэширование видовых экранов.

 layout: Лист2
ViewPorts count: 2
GeometricExtents: ((-53086.0451707609,-37718.4322762899,0),(126110.691411774,69249.0417919972,0))

ViewPorts count: 2
GeometricExtents: ((37179.7882091809,3934.61940203956,0),(53809.7819253212,12392.0045362966,0))
Выполняется регенерация листов.
Регенерация модели - кэширование видовых экранов.

 layout: Лист3
ViewPorts count: 2
GeometricExtents: ((-5002.78674225538,-17253.761352533,0),(108390.068971918,50433.5614439305,0))

ViewPorts count: 2
GeometricExtents: ((11285.0028004109,13607.3497198238,0),(48253.7262624344,35479.3855414141,0))
Выполняется регенерация листов.

 layout: Лист4
ViewPorts count: 1
GeometricExtents: ((-17304.1191661114,-11239.9954564359,0),(96088.7365480622,56447.3273400276,0))

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

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

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
И? Что теперь не так?
Так все тоже - на Лист1, например, в чертеже нет видового экрана, а на Лист2 он один. Но код выдает на Лист1 один видовой экран, а на Лист2 - два видовых экрана. А когда в коде доходит до ed.SwitcoToModelSpace(), то ловится ошибка и автокад сообщает, что он не может этого сделать ибо нет видового экрана!
Пришел на данный момент к самому банальному решению - обернул все это дело в try{} catch{} - все работает

Но остается сам главный вопрос, который и звучит в названии темы - получение объектов модели в границах видового экрана. Тот код, на который я давал ссылку в топике - работает совершенно не верно. Находил тему, где говорится что конвертирование точек, представленное тут неправильное. Но пока-что заставить код работать правильно у меня не получилось

Отмечено как Решение Александр Пекшев aka Modis 17-01-2017, 22:06:36

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
http://adn-cis.org/forum/index.php?topic=228.msg415#msg415
Божечки! Вот этот ответ и нужно было услышать =)))

Но вопрос топика остается. Или лучше новую тему?

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Я в свое время очень много времени потратил на похожую задачу. Здесь очень много различных тонкостей и в общем виде ее решать очень сложно. В итоге, я сделал так:
1. Устанавливаю текущим нужный лист.
2. Нахожу все ВЭ на листе.
3. Извлекаю точки контура ВЭ. При этом я не обрабатывал подрезку ВЭ криволинейным объектом.
4. Транслирую точки контура в модель.
5. С помощью объекта MPoligon определяю, попадают ли нужные мне объекты в этот контур. То есть, сперва я получаю все объекты нужного типа в модели, а потом из них выбираю нужные.
Ну и далее произвожу нужные мне обработки.

Мне нужны были метки Civil, я определял их попадание в контур по точке вставки метки.

Свой код по идеологическим причинам выкладывать не хочу. Если будут какие-то конкретные вопросы, наверное, смогу подсказать.

Еще, где-то на просторах интернета был код, который переводит контуры ВЭ в модель. Можно попробовать найти его и использовать как пример.

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Бегло просмотрел код. Навскидку, увидел пару отличий от моего кода:
1. Переключение листа я делаю вне транзакции. Можно в транзакции получить все нужные названия листов, а потом закрыть транзакцию и переключить лист на нужный. Возможно, что в этом проблема.
2. Перед трансляцией точек из листа в модель нужно установить текущим нужный ВЭ. ВЭ на листе ведь может быть несколько. Устанавливаю через переменную AutoCAD:
Код - C# [Выбрать]
  1. // Переключаемся в обрабатываемый ВЭ                    
  2. Application.SetSystemVariable("CVPORT", viewport.Number);
Насколько я помню, самая большая сложность была в том, чтобы найти правильную последовательность действий. Чуть не тот порядок - и валятся ошибки.
Вообще, что-то сложно понять логику. В коде "тык по кнопке" блокируется документ, запускается транзакция и проходишь по листам. Внутри выполняется GetDataFromTablesForLayout, в котором снова блокируется документ, запускается транзакция и опять проход по листам. В чем логика?