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

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

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

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

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

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 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
  • *****
  • Сообщений: 13829
  • Карма: 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
  • *****
  • Сообщений: 13829
  • Карма: 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, в котором снова блокируется документ, запускается транзакция и опять проход по листам. В чем логика?

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
В коде "тык по кнопке" блокируется документ, запускается транзакция и проходишь по листам. Внутри выполняется GetDataFromTablesForLayout, в котором снова блокируется документ, запускается транзакция и опять проход по листам. В чем логика?
Если вы смотрели код из топика - то там полнейший мусор )) Скажем так - рабочий процесс переделывание одного в другое вызвал массу неточностей. В итоге все было урезано до минимума. И переключение листов выполняется без транзакций, а блокировка документа только один раз написана.
Пару сообщений назад я писал "урезанный" код, правда из него убраны "попытки" получения объектов по видовому экрану и оставлено было только получение видовых экранов. Т.е. вместо этого:
Код - C# [Выбрать]
  1. using (var psVp = (Viewport)tr.GetObject(objectId, OpenMode.ForRead))
  2.  {
  3.    ed.WriteMessage("nViewPorts count: " + vps.Count);
  4.    ed.WriteMessage("\nON: " + psVp.On);
  5.    ed.WriteMessage("\nNumber: " + psVp.Number);
  6.  ed.WriteMessage("\nTransparent: " + psVp.Transparent);
  7.  }

должен быть уже тот код с попытками получения координат границ и прочего

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
То есть, сейчас уже все работает как надо? :)

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

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

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Учитывая эту тему и пару других тем, я все же заставил код работать. Код, правда, сделан под чертеж, приложенный в вопросе. Некоторые моменты не совсем понял...
Прошу знатоков посмотреть на код для выявления явных проблем  ::)
Код - C# [Выбрать]
  1. using AcApp = Autodesk.AutoCAD.ApplicationServices.Core.Application;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Runtime.InteropServices;
  5. using System.Windows;
  6. using Autodesk.AutoCAD.DatabaseServices;
  7. using Autodesk.AutoCAD.EditorInput;
  8. using Autodesk.AutoCAD.Geometry;
  9.  
  10. namespace VPtestForForum_2017
  11. {
  12.     public partial class Win
  13.     {
  14.         public Win()
  15.         {
  16.             InitializeComponent();
  17.         }
  18.  
  19.         private List<string> layouts = new List<string>
  20.         {
  21.             "Лист1",
  22.             "Лист2",
  23.             "Лист3",
  24.             "Лист4"
  25.         };
  26.  
  27.         private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
  28.         {
  29.             try
  30.             {
  31.                 var doc = AcApp.DocumentManager.MdiActiveDocument;
  32.                 var ed = doc.Editor;
  33.                 var db = HostApplicationServices.WorkingDatabase;
  34.  
  35.                 var lm = LayoutManager.Current;
  36.                 using (doc.LockDocument())
  37.                 {
  38.                     foreach (var layout in layouts)
  39.                     {
  40.                         lm.CurrentLayout = layout;
  41.                         ed.WriteMessage("\nlayout: " + lm.CurrentLayout + "\n");
  42.                         // Данные из видовых экранов
  43.                         GetDataFromTablesForLayout(db);
  44.                     }
  45.                 }
  46.  
  47.             }
  48.             catch (Exception ex)
  49.             {
  50.                 MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace);
  51.             }
  52.         }
  53.  
  54.         [DllImport("accore.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedTrans")]
  55.         private static extern int acedTrans(double[] point, IntPtr fromRb, IntPtr toRb, int disp, double[] result);
  56.  
  57.         private void GetDataFromTablesForLayout(Database db)
  58.         {
  59.             var ed = AcApp.DocumentManager.MdiActiveDocument.Editor;
  60.             using (var tr = db.TransactionManager.StartTransaction())
  61.             {
  62.                 using (var layout = tr.GetObject(LayoutManager.Current.GetLayoutId(LayoutManager.Current.CurrentLayout),
  63.                             OpenMode.ForRead) as Layout)
  64.                 {
  65.                     var vps = layout?.GetViewports();
  66.                     if (vps != null && vps.Count > 0)
  67.                         for (var k = 1; k < vps.Count; k++)// счетчик делаем с 1, т.к. первый видовой экран в списке - пространство листа
  68.                         {
  69.                             try
  70.                             {
  71.                                 var psVpPnts = new Point3dCollection();
  72.                                 // Переключаемся в пространство модели
  73.                                 ed.SwitchToModelSpace();
  74.                                 /* Получаем координаты границ видового экрана
  75.                                  * Такой порядок действий и последующая конвертация точек
  76.                                  * выполнены на основе этого топика - http://www.theswamp.org/index.php?topic=42503.msg476994#msg476994
  77.                                  */
  78.                                 using (var psVp = (Viewport)tr.GetObject(vps[k], OpenMode.ForRead))
  79.                                 {
  80.                                     // Если видовой экран прямоугольный
  81.                                     if (!psVp.NonRectClipOn)
  82.                                     {
  83.                                         psVp.GetGripPoints(psVpPnts, new IntegerCollection(), new IntegerCollection());
  84.                                        
  85.                                         // Вот дальнейшего действия не понял, но с ним работает ((
  86.                                         Point3d tmp = psVpPnts[2];
  87.                                         psVpPnts[2] = psVpPnts[1];
  88.                                         psVpPnts[1] = tmp;
  89.                                     }
  90.                                     else // Если границы ВЭ - полилиния
  91.                                     {
  92.                                         ObjectId nonrectoid = psVp.NonRectClipEntityId;
  93.                                         Polyline nrvp = tr.GetObject(nonrectoid, OpenMode.ForRead) as Polyline;
  94.                                         nrvp?.GetStretchPoints(psVpPnts);
  95.                                     }
  96.                                 }
  97.                                
  98.                                 //// Transform the PS points to MS points
  99.                                 ResultBuffer rbPSDCS = new ResultBuffer(new TypedValue(5003, 3));
  100.                                 ResultBuffer rbDCS = new ResultBuffer(new TypedValue(5003, 2));
  101.                                 ResultBuffer rbWCS = new ResultBuffer(new TypedValue(5003, 0));
  102.                                 var retPoint = new double[] { 0, 0, 0 };
  103.                                 // loop the ps points
  104.                                 var msVpPnts = new Point3dCollection();
  105.                                 foreach (Point3d pnt in psVpPnts)
  106.                                 {
  107.                                     // translate from from the DCS of Paper Space (PSDCS) RTSHORT=3
  108.                                     // to the DCS of the current model space viewport RTSHORT=2
  109.                                     acedTrans(pnt.ToArray(), rbPSDCS.UnmanagedObject, rbDCS.UnmanagedObject, 0, retPoint);
  110.                                     //translate the DCS of the current model space viewport RTSHORT=2
  111.                                     //to the WCS RTSHORT=0
  112.                                     acedTrans(retPoint, rbDCS.UnmanagedObject, rbWCS.UnmanagedObject, 0, retPoint);
  113.                                     // add the resulting point to the ms pnt array
  114.                                     msVpPnts.Add(new Point3d(retPoint));
  115.                                 }
  116.                                 // once switched, we can use the normal selection mode to select
  117.                                 var filList = new[] { new TypedValue((int)DxfCode.Start, "ACAD_TABLE") };
  118.                                 var selectionresult = ed.SelectCrossingPolygon(msVpPnts,
  119.                                     new SelectionFilter(filList));
  120.                                 if (selectionresult.Value.Count > 0)
  121.                                 {
  122.                                     foreach (SelectedObject selectedObject in selectionresult.Value)
  123.                                     {
  124.                                         ed.WriteMessage("\nObject: " + selectedObject.ObjectId.GetObject(OpenMode.ForRead).GetType());
  125.                                     }
  126.  
  127.                                 }
  128.                                 // now switch back to PS
  129.                                 ed.SwitchToPaperSpace();
  130.                             }
  131.                             catch (Exception exception)
  132.                             {
  133.                                 ed.WriteMessage("\nWas error: " + exception.StackTrace);
  134.                             }
  135.                         }
  136.                 }
  137.                 tr.Commit();
  138.             }
  139.         }
  140.     }
  141. }

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Код - C# [Выбрать]
  1. using (var psVp = (Viewport)tr.GetObject(vps[k], OpenMode.ForRead))
1. Если объект получен через транзакцию, не нужно его в using пихать.
2. var - это плохо  ;)
Есть подозрение, что если на листе будет несколько ВЭ, в которых будут отображаться !разные! нужные объекты, то код некорректно отработает.
Цитировать
// Вот дальнейшего действия не понял, но с ним работает ((
Метод возвращает точки в порядке "крест-накрест". А дальнейшие действия изменяют порядок точек, чтобы он был в обход контура.

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
1. Если объект получен через транзакцию, не нужно его в using пихать.
Точно! Нужно убрать лишние строки
2. var - это плохо
Этот спор был в другой теме и все остались при своем мнение ;) Мне удобно
Есть подозрение, что если на листе будет несколько ВЭ, в которых будут отображаться !разные! нужные объекты, то код некорректно отработает
Ну вот тут уже нужно кучу тестов проводить. Опробовал код в исходном рабочем проекте и на большом чертеже (где по несколько видовых экранов) - частично сработало все, а частично нет. Но на сегодня все - домой уже хочется )))
Метод возвращает точки в порядке "крест-накрест". А дальнейшие действия изменяют порядок точек, чтобы он был в обход контура
Ну как бы сами действия я понял )) Я ни как не пойму почему это нужно делать и почему без этого не работает  ???

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Метод возвращает точки в порядке "крест-накрест". А дальнейшие действия изменяют порядок точек, чтобы он был в обход контура.
Ну как бы сами действия я понял )) Я ни как не пойму почему это нужно делать и почему без этого не работает 
Выключил комп, пошел одеваться и до меня вроде дошло наконец - видимо, когда создается ВЭ то мы задаем две противоположные точки, поэтому все 4 точки не создают контур. Это действие превращает эти четыре точки в прямоугольник.
Дмитрий Загорулькин,  вы правильно мне все объяснили, просто к вечеру мозг решил отказаться воспринимать информацию :D

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Дмитрий Загорулькин, спасибо Вам! И даже не за то, что отвечали мне тут, а за то, что в другой ветке уже есть пример кода от Вас, который мне подходит - http://adn-cis.org/forum/index.php?topic=504.msg1596#msg1596
Мне чуть-чуть не хватило, чтобы самому до этого "дойти" )) Буквально пару важных строк

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

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

Оффлайн geosys

  • ADN OPEN
  • Сообщений: 25
  • Карма: 3
Извиняюсь за поднятие старой темы. У меня похожая проблема, но прочитав тему, так и не понял, как её решили.
Моя ситуация: на листе 6 видовых экранов. Команда layout.GetViewports() выдает мне только один, который является видовым экраном листа и который мне не нужен (имя листа задано верно и он открыт/активен). При этом, если проходиться по всем объектам листа, то я эти видовые экраны там вижу (и их количество 7, как и положено). Но при попытке выцепить программно видовой экран оттуда и применить к нему команду doc.Editor.SwitchToModelSpace(); я получаю eCannotChangeActiveViewport. В чем может быть прикол?

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
В чем может быть прикол?
имя листа задано верно
Я так думаю, что всё-же не тот лист берётся. Но это только предположение. Для более точного ответа мало информации о проблеме.

Оффлайн geosys

  • ADN OPEN
  • Сообщений: 25
  • Карма: 3
Спасибо за ответ, уже проверял этот вариант - лист правильный...

Что ещё может быть не так? Может кто-то сталкивался?

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Что ещё может быть не так?
Испорчен чертёж. Проверьте с помощью AUDIT или на другом чертеже поэкспериментируйте.
А вообще, если так не хотите показывать свой код. Есть эта тема, есть другая - ссылки есть в сообщениях этой темы. В них есть примеры кодов. Проверяйте, как они будут отрабатывать у вас и тогда уже будет более предметный разговор, если вы сообщите что-то типа: взял код из сообщения № темы такой-то, вот мой чертёж (вложение) версия AutoCAD такая-то, разрядность такая. На такой-то строке получаю такой-то результат, а должен быть вот такой. Ну и т.д. А то сейчас это какая-то игра в угадайку...

Оффлайн geosys

  • ADN OPEN
  • Сообщений: 25
  • Карма: 3
Спасибо, с чертежом всё норм. Функция layout.GetViewports() не видит видовые экраны в случая импорта листа из шаблона. Если данный лист присутствует в чертеже, то всё фунциклирует как надо. Теперь я окончательно перестал понимать почему так происходит.
Код - C# [Выбрать]
  1. //из основного кода
  2. //импорт шаблона
  3. ImportLayout("c:\\test.dwt","Чертеж_ЗУ_А3_КПТ_В");
  4. //mpcol - коллеция ObjectId нескольких полилиний
  5. for (int i=0;i<mpcol.Count;i++)
  6. {
  7.         ObjectId vp = displayatvp("Чертеж_ЗУ_А3_КПТ_В",mpcol[i],i,1.5);
  8. }
  9. //..
  10.  
  11. //попытка отобразить каждую полилинию в каждом видовом окне
  12. static public ObjectId displayatvp(string listname, ObjectId target, int curindex, double vpheight)
  13. {
  14.         Document doc =Platform.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
  15.         Database db = doc.Database;
  16.         Editor ed = doc.Editor;
  17.         ObjectId vpid=ObjectId.Null;
  18.         using (DocumentLock acLckDoc = doc.LockDocument())
  19.         {
  20.                 Transaction tr =db.TransactionManager.StartTransaction();
  21.                 using (tr)
  22.                 {
  23.                         Entity ent=tr.GetObject(target,OpenMode.ForRead) as Entity;
  24.                         Extents3d ext=ent.GeometricExtents;
  25.                         LayerTable ltb = (LayerTable)tr.GetObject(db.LayerTableId,OpenMode.ForRead);
  26.                         LayoutManager acLayoutMgr = LayoutManager.Current;
  27.                         DBDictionary layoutDic = tr.GetObject(db.LayoutDictionaryId, OpenMode.ForWrite, false) as DBDictionary;
  28.                         Layout layout = tr.GetObject(entry.Value, OpenMode.ForRead) as Layout;
  29.                         foreach (DBDictionaryEntry entry in layoutDic)
  30.                         {
  31.                                 if (!layout.ModelType)
  32.                                 {
  33.                                         if (layout.LayoutName==listname)
  34.                                         {
  35.                                                 acLayoutMgr.CurrentLayout = layout.LayoutName;
  36.                                                 ObjectIdCollection idsVports = layout.GetViewports();//даёт 1
  37.                                                 BlockTableRecord btrLayout = tr.GetObject(layout.BlockTableRecordId, OpenMode.ForRead) as BlockTableRecord;
  38.  
  39.                                                 //вот так я вижу видовые экраны
  40.                                                 /*                              ObjectIdCollection idsVports=new ObjectIdCollection();
  41.                                                         foreach (ObjectId id in btrLayout)
  42.                                                         {
  43.                                                                 DBObject obj=tr.GetObject(id,OpenMode.ForRead);
  44.                                                                 if (obj is Viewport)
  45.                                                                 {
  46.                                                                         idsVports.Add(id);
  47.                                                                 }
  48.                                                         }
  49.                                                         idsVports.RemoveAt(0);*/
  50.                                                
  51.                                                 int vpindex=curindex+1; //для избежания первого видового экрана листа
  52.                                                 Viewport vp = (Viewport)tr.GetObject(idsVports[vpindex], OpenMode.ForRead);
  53.                                                 double mScrRatio = (vp.Width / vp.Height);
  54.                                                 Matrix3d matWCS2DCS;
  55.                                                 matWCS2DCS = Matrix3d.PlaneToWorld(vp.ViewDirection);
  56.                                                 matWCS2DCS = Matrix3d.Displacement(vp.ViewTarget - Point3d.Origin) * matWCS2DCS;
  57.                                                 matWCS2DCS = Matrix3d.Rotation(-vp.TwistAngle, vp.ViewDirection, vp.ViewTarget) * matWCS2DCS;
  58.                                                 matWCS2DCS = matWCS2DCS.Inverse();
  59.                                                 ext.TransformBy(matWCS2DCS);
  60.                                                 double mWidth;
  61.                                                 mWidth = (ext.MaxPoint.X - ext.MinPoint.X);
  62.                                                 double mHeight;
  63.                                                 mHeight = (ext.MaxPoint.Y - ext.MinPoint.Y);
  64.                                                 Point2d mCentPt = new Point2d(
  65.                                                         ((ext.MaxPoint.X + ext.MinPoint.X) * 0.5),
  66.                                                         ((ext.MaxPoint.Y + ext.MinPoint.Y) * 0.5));
  67.                                                 vp.UpgradeOpen();
  68.                                                 if (mWidth > (mHeight * mScrRatio))  mHeight = mWidth / mScrRatio;
  69.                                                 vp.ViewHeight = mHeight * vpheight;
  70.                                                 vp.ViewCenter = mCentPt;
  71.                                                 vp.Visible = true;
  72.                                                 vp.On = true;
  73.                                                 doc.Editor.SwitchToModelSpace();
  74.                                                 Application.SetSystemVariable("CVPORT", vp.Number);
  75.                                                 //doc.Editor.SwitchToPaperSpace();
  76.                                                 vpid=vp.ObjectId;
  77.                                         }
  78.                                 }}}
  79.                 tr.Commit();
  80.                 return vpid;
  81.         }}
  82.  
  83. //импорт листа
  84. public static void ImportLayout(string sourceFileName,string layoutName)
  85. {
  86.         Document destDoc = Application.DocumentManager.MdiActiveDocument;
  87.         Database destDb = destDoc.Database;
  88.         var destEd = destDoc.Editor;
  89.         Database sourceDb = new Database(false, true);
  90.         sourceDb.ReadDwgFile(sourceFileName, FileOpenMode.OpenForReadAndAllShare, true, "");
  91.         using (DocumentLock acLckDoc = destDoc.LockDocument())
  92.         {
  93.                 using (var destTr = destDb.TransactionManager.StartTransaction())
  94.                 {
  95.                         DBDictionary layouts =
  96.                                 destTr.GetObject(destDb.LayoutDictionaryId,
  97.                                                  OpenMode.ForRead) as DBDictionary;
  98.                         HostApplicationServices.WorkingDatabase = destDb;
  99.                         var destLayoutManager = LayoutManager.Current;
  100.                         var destLayoutId = destLayoutManager.CreateLayout(layoutName);
  101.                         var destLayout = (Layout)destTr.GetObject(destLayoutId, OpenMode.ForWrite);
  102.                         HostApplicationServices.WorkingDatabase = sourceDb;
  103.  
  104.                         using (var sourceTr = sourceDb.TransactionManager.StartTransaction())
  105.                         {
  106.                                 var layoutDictionary = (DBDictionary)sourceTr.GetObject(sourceDb.LayoutDictionaryId, OpenMode.ForRead);
  107.  
  108.                                 if (!layoutDictionary.Contains(layoutName))
  109.                                 {
  110.                                         destEd.WriteMessage("В шаблоне отсутствует лист "+layoutName+".");
  111.                                         return;
  112.                                 }
  113.                                 var sourceLayoutManager = LayoutManager.Current;
  114.                                 var sourceLayoutId = sourceLayoutManager.GetLayoutId(layoutName);
  115.                                 var sourceLayout = (Layout)sourceTr.GetObject(sourceLayoutId, OpenMode.ForRead);
  116.                                 destLayout.CopyFrom(sourceLayout);
  117.                                 var layoutTableRecord =
  118.                                         (BlockTableRecord)sourceTr.GetObject(sourceLayout.BlockTableRecordId, OpenMode.ForRead);
  119.                                 var objIdCol = new ObjectIdCollection();
  120.  
  121.                                 foreach (var layoutObjectId in layoutTableRecord)
  122.                                 {
  123.                                         objIdCol.Add(layoutObjectId);
  124.                                 }
  125.                                 var idMap = new IdMapping();
  126.                                 destDb.WblockCloneObjects(objIdCol, destLayout.BlockTableRecordId, idMap, DuplicateRecordCloning.Ignore, false);
  127.                                 sourceTr.Commit();
  128.                         }
  129.                         HostApplicationServices.WorkingDatabase = destDb;
  130.                         destTr.Commit();
  131.                 }
  132.         }
  133. }
Основной код также находится в транзакции, а у каждой функции дочерние транзакции. Пробовал вынести вызов обеих функций за пределы основной транзакции - результат тот же. Логично предположить, что функция импорта каким-то образом недорабатывает перенос видовых экранов? Хотя если запускать её отдельно, то все экраны на месте. Вобщем, теперь даже не знаю, куда копать...

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Функция layout.GetViewports() не видит видовые экраны в случая импорта листа из шаблона.
Воооот оно в чём дело! А мы могли бы ещё долго гадать...
Суть в том, что импортированный лист ещё нужно инициализировать. Как это сделать можно посмотреть тут: https://www.theswamp.org/index.php?topic=37443.0

Оффлайн geosys

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

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Код - C# [Выбрать]
  1.  // Если видовой экран прямоугольный
  2. if (!psVp.NonRectClipOn)
  3. {
  4.    psVp.GetGripPoints(psVpPnts, new IntegerCollection(), new IntegerCollection());
  5.                                        
  6.     // Вот дальнейшего действия не понял, но с ним работает ((
  7.     Point3d tmp = psVpPnts[2];
  8.     psVpPnts[2] = psVpPnts[1];
  9.     psVpPnts[1] = tmp;
  10. }
Скорее всего, автором этого способа определения граничных точек прямоугольного видового экрана является Augusto Goncalves: https://adndevblog.typepad.com/autocad/2014/11/from-model-space-to-paper-space.html
Новый претендент на первоисточник: https://adndevblog.typepad.com/autocad/2012/04/selecting-model-space-entities-from-paper-space-using-autocad-selection-sets-in-c.html
Обнаружил, что в последних версиях AutoCAD он даёт сбой. Причина проста: добавилась ещё одна ручка у видового экрана - посередине. Сейчас вообще не понимаю: к чему были такие сложности, если эти точки легко высчитываются по положению центра ВЭ и его размерам или с помощью его GeometricExtents?  :-\

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

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

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Думаю, что следует воспользоваться другим перегруженным методом GetGripPoints и там разобраться с точками.
Не-не-не, хватит! Очень капризны и непостоянны эти "гриппоинты".
Код - C# [Выбрать]
  1. // Если видовой экран стандартный прямоугольный
  2. if (!viewport.NonRectClipOn)
  3. {
  4.     Point3d center = viewport.CenterPoint;
  5.     Vector3d
  6.         left = new Vector3d(viewport.Width / 2.0, 0.0, 0.0),
  7.         up = new Vector3d(0.0, viewport.Height / 2.0, 0.0);
  8.  
  9.     psVpPnts.Add(center - left - up);
  10.     psVpPnts.Add(center + left - up);
  11.     psVpPnts.Add(center + left + up);
  12.     psVpPnts.Add(center - left + up);
  13. }
  14.  
Для прямоугольного - однозначно.
А для подрезанного это неактуально - там же геометрия вытаскивается из объекта подрезки.

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

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