Как выбрать объекты для показа в видовом экране?

Автор Тема: Как выбрать объекты для показа в видовом экране?  (Прочитано 6508 раз)

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

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

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

  • ADN OPEN
  • Сообщений: 25
  • Карма: 3
Доброго времени суток!
Вопрос простой, как сделать в видовом экране приближение на нужные объекты в модели и вычислить масштаб отображения? Перечитал много забугорных статей и форумов - пока безрезультатно. Надеюсь на помощь знающих людей :)
Мой код (ObjectIdCollection ids - это ObjectId нужных объектов, посылаются из другой функции):
Код - C# [Выбрать]
  1. public static void test(ObjectIdCollection ids)
  2.  {
  3.     Document doc = Application.DocumentManager.MdiActiveDocument;
  4.     Editor ed = doc.Editor;
  5.     Database db = doc.Database;
  6.    
  7.    Transaction tr = doc.TransactionManager.StartTransaction();
  8.     using (tr)
  9.     {   //инициализируем диспетчер листов
  10.        LayoutManager acLayoutMgr = LayoutManager.Current;
  11.       //достаем справочник листов
  12.        DBDictionary layoutDic = tr.GetObject(db.LayoutDictionaryId, OpenMode.ForWrite, false) as DBDictionary;
  13.       //вычисляем общие границы всех объетков
  14.         Extents3d ext = new Extents3d();
  15.         foreach (ObjectId id in ids)
  16.         {
  17.            var ent = tr.GetObject(id, OpenMode.ForRead) as Entity;
  18.            if (ent != null)
  19.            {
  20.               ext.AddExtents(ent.GeometricExtents);
  21.            }
  22.         }
  23.       //находим и устанавливаем нужный лист
  24.        foreach (DBDictionaryEntry entry in layoutDic)
  25.        {
  26.           ObjectId layoutId = entry.Value;
  27.           Layout layout = tr.GetObject(layoutId, OpenMode.ForWrite) as Layout;
  28.  
  29.           if (layout.LayoutName == "Чертеж")
  30.           {
  31.             //фокусируемся на нём
  32.              acLayoutMgr.CurrentLayout=layout.LayoutName;
  33.             //открываем его BTR
  34.              BlockTableRecord btr = (BlockTableRecord)tr.GetObject(layout.BlockTableRecordId, OpenMode.ForWrite);
  35.             //достаём видовой экран
  36.             Viewport vp=(Viewport)tr.GetObject(layout.CurrentViewportId,OpenMode.ForRead);
  37.             //открываем под запись
  38.             vp.UpgradeOpen();
  39. //////нужно сделать зум в видовом экране к границам всех объектов ids; перепробовал много способов, устаналивал разные значения vp.ViewTarget, vp.CenterPoint - всё не то... также, необходимо вычислить масштаб, в котором будут показываться объекты (в зависимости от размера границ и зума); в моем случае можно использовать границы объектов ext для показа их в видовом экране.
  40.             doc.Editor.SwitchToModelSpace();
  41.             Application.SetSystemVariable("CVPORT", vp.Number);
  42.           }
  43.        }
  44.        tr.Commit();
  45.     }
  46.  }
Чертеж с примером видового экрана прилагаю.
Заранее спасибо!


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

  • ADN OPEN
  • Сообщений: 25
  • Карма: 3
Спасибо, проходил, и не только эту, а ещё много других статей. Не смог перестроить её под свои нужды + ни слова про масштаб. В ближайшее время снова внедрю это в свой код и скажу где затык.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
geosys,
Приветствую на форуме!
Александр Пекшев aka Modis прав. Только в том примере вместо db.Extmin и db.Extmax нужно использовать твои ext.MinPoint и ext.MaxPoint. Ну и масштаб равный 1 (или чуть больше, чтобы точно всё влезло).
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

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

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

  • ADN OPEN
  • Сообщений: 25
  • Карма: 3
geosys,
Приветствую на форуме!
Александр Пекшев aka Modis прав. Только в том примере вместо db.Extmin и db.Extmax нужно использовать твои ext.MinPoint и ext.MaxPoint. Ну и масштаб равный 1 (или чуть больше, чтобы точно всё влезло).
Спасибо! Да, я так и делал, сейчас повторю и скажу в каком месте у меня косяк :)
+ ни слова про масштаб
В смысле???
В смысле не сказано как вычислить нужный масштаб, исходя из границ (ext) и размера листа. Или я чего-то непонимаю? :) Чтобы масштаб автоматически ставился на нужный. Насколько я понял, за это отвечает vp.CustomScale.

upd.: вроде vp.ViewHeight это и есть масштаб, вопрос, как его вычислить автоматически и привести к понятному виду? (например 1:200)

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

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

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

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

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

  • ADN OPEN
  • Сообщений: 25
  • Карма: 3
Переписал код, после его выполнения вид на листе отлетает очень далеко от самого листа. После зумирования листа (посредством нажатия средней кнопки мыши) видовой экран остается пустым. В этом и есть затык.
Код:
Код - C# [Выбрать]
  1. public static void test(ObjectIdCollection ids)
  2.  {
  3.         Document doc = Application.DocumentManager.MdiActiveDocument;
  4.         Editor ed = doc.Editor;
  5.         Database db = doc.Database;
  6.        
  7.         Transaction tr = doc.TransactionManager.StartTransaction();
  8.         using (tr)
  9.         {       //инициализируем диспетчер листов
  10.                 LayoutManager acLayoutMgr = LayoutManager.Current;
  11.                 //достаем справочник листов
  12.                 DBDictionary layoutDic = tr.GetObject(db.LayoutDictionaryId, OpenMode.ForWrite, false) as DBDictionary;
  13.                 //вычисляем общие границы всех объетков
  14.         Extents3d ext = new Extents3d();
  15.         foreach (ObjectId id in ids)
  16.         {
  17.                 var ent = tr.GetObject(id, OpenMode.ForRead) as Entity;
  18.                 if (ent != null)
  19.                 {
  20.                         ext.AddExtents(ent.GeometricExtents);
  21.                 }
  22.         }
  23.                 double mScrRatio;
  24.                 //находим и устанавливаем нужный лист
  25.                 foreach (DBDictionaryEntry entry in layoutDic)
  26.                 {
  27.                         ObjectId layoutId = entry.Value;
  28.                         Layout layout = tr.GetObject(layoutId, OpenMode.ForWrite) as Layout;
  29.  
  30.                         if (layout.LayoutName == "Чертеж")
  31.                         {
  32.                                 acLayoutMgr.CurrentLayout=layout.LayoutName;
  33.                                 BlockTableRecord btr = (BlockTableRecord)tr.GetObject(layout.BlockTableRecordId, OpenMode.ForWrite);
  34.                                 Viewport vp=(Viewport)tr.GetObject(layout.CurrentViewportId,OpenMode.ForRead);
  35.                                 mScrRatio = (vp.Width / vp.Height);
  36.                                 // prepare Matrix for DCS to WCS transformation
  37.                                 Matrix3d matWCS2DCS;
  38.                                 matWCS2DCS = Matrix3d.PlaneToWorld(vp.ViewDirection);
  39.                                 matWCS2DCS = Matrix3d.Displacement(vp.ViewTarget - Point3d.Origin)* matWCS2DCS;
  40.                                 matWCS2DCS = Matrix3d.Rotation(-vp.TwistAngle, vp.ViewDirection,vp.ViewTarget) * matWCS2DCS;
  41.                                 matWCS2DCS = matWCS2DCS.Inverse();
  42.                                  ext.TransformBy(matWCS2DCS);
  43.               // width of the extents in current view
  44.               double mWidth;
  45.               mWidth = (ext.MaxPoint.X - ext.MinPoint.X);
  46.               // height of the extents in current view
  47.               double mHeight;
  48.               mHeight = (ext.MaxPoint.Y - ext.MinPoint.Y);
  49.               // get the view center point
  50.               Point2d mCentPt = new Point2d(
  51.                 ((ext.MaxPoint.X + ext.MinPoint.X) * 0.5),
  52.                 ((ext.MaxPoint.Y + ext.MinPoint.Y) * 0.5));
  53.               // check if the width 'fits' in current window,
  54.               // if not then get the new height as
  55.               // per the viewports aspect ratio
  56.               vp.UpgradeOpen();
  57.               if (mWidth > (mHeight * mScrRatio))
  58.                 mHeight = mWidth / mScrRatio;
  59.               vp.ViewHeight = mHeight * 1.01;
  60.                 // set the view center
  61.                 vp.ViewCenter = mCentPt;
  62.                 vp.Visible = true;
  63.                 vp.On = true;
  64.                                 vp.UpdateDisplay();
  65.                                 doc.Editor.SwitchToModelSpace();
  66.                                 Application.SetSystemVariable("CVPORT", vp.Number);
  67.                         }
  68.                 }
  69.                 tr.Commit();
  70.         }
  71.  }

upd.: вроде vp.ViewHeight это и есть масштаб, вопрос, как его вычислить автоматически и привести к понятному виду? (например 1:200)
Это не масштаб. Проанализируй его при помощи MGDDBG.
С масштабом так и не понял, вопрос остаётся открытым

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
С кодом я особенно не разбирался, но обрати внимание, что на листе Чертеж есть два Viewport'а. Похоже ты работаешь не с тем:



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

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Вдогонку почитай эту тему: http://adn-cis.org/forum/index.php?topic=228.0
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Отмечено как Решение geosys 23-05-2018, 11:50:18

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Итак. Вот код:
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.Runtime;
  2. using Autodesk.AutoCAD.ApplicationServices;
  3. using Autodesk.AutoCAD.DatabaseServices;
  4. using Autodesk.AutoCAD.Geometry;
  5. using Autodesk.AutoCAD.EditorInput;
  6.  
  7. // This line is not mandatory, but improves loading performances
  8. [assembly: CommandClass(typeof(ZoomViewport.Utils))]
  9.  
  10. namespace ZoomViewport
  11. {
  12.  
  13.   public class Utils
  14.   {
  15.     [CommandMethod("TestZoom")]
  16.     public void TestZoom()
  17.     {
  18.       Document doc = Application.DocumentManager.MdiActiveDocument;
  19.       if (doc == null) return;
  20.       Editor ed = doc.Editor;
  21.       Database db = doc.Database;
  22.       PromptSelectionResult rs = ed.GetSelection();
  23.       if (rs.Status != PromptStatus.OK) return;
  24.       ObjectIdCollection ids = new ObjectIdCollection(rs.Value.GetObjectIds());
  25.       test(ref ids);
  26.     }
  27.  
  28.     public static void test(ref ObjectIdCollection ids)
  29.     {
  30.       Document doc = Application.DocumentManager.MdiActiveDocument;
  31.       Editor ed = doc.Editor;
  32.       Database db = doc.Database;
  33.  
  34.       using (Transaction tr = doc.TransactionManager.StartTransaction())
  35.       {
  36.         Extents3d ext = new Extents3d();
  37.         foreach (ObjectId id in ids)
  38.         {
  39.           var ent = tr.GetObject(id, OpenMode.ForRead) as Entity;
  40.           if (ent != null)
  41.           {
  42.             ext.AddExtents(ent.GeometricExtents);
  43.           }
  44.         }
  45.  
  46.         LayoutManager layman = LayoutManager.Current;
  47.  
  48.         DBDictionary layoutDic = tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead) as DBDictionary;
  49.  
  50.         double mScrRatio;
  51.         // Проходимся по всем листам (модель пропускаем)
  52.         foreach (DBDictionaryEntry entry in layoutDic)
  53.         {
  54.           Layout layout = tr.GetObject(entry.Value, OpenMode.ForRead) as Layout;
  55.  
  56.           if (!layout.ModelType) // Это не модель
  57.           {
  58.             layman.CurrentLayout = layout.LayoutName;
  59.             ObjectIdCollection idsVports = layout.GetViewports();
  60.             // Проходимся по всем видовым экранам (кроме основного видового экрана листа)
  61.             for (int i = 1; i < idsVports.Count; i++)
  62.             {
  63.               Viewport vp = (Viewport)tr.GetObject(idsVports[i], OpenMode.ForRead);
  64.               mScrRatio = (vp.Width / vp.Height);
  65.               // prepare Matrix for DCS to WCS transformation
  66.               Matrix3d matWCS2DCS;
  67.               matWCS2DCS = Matrix3d.PlaneToWorld(vp.ViewDirection);
  68.               matWCS2DCS = Matrix3d.Displacement(vp.ViewTarget - Point3d.Origin) * matWCS2DCS;
  69.               matWCS2DCS = Matrix3d.Rotation(-vp.TwistAngle, vp.ViewDirection, vp.ViewTarget) * matWCS2DCS;
  70.               matWCS2DCS = matWCS2DCS.Inverse();
  71.               ext.TransformBy(matWCS2DCS);
  72.               // width of the extents in current view
  73.               double mWidth;
  74.               mWidth = (ext.MaxPoint.X - ext.MinPoint.X);
  75.               // height of the extents in current view
  76.               double mHeight;
  77.               mHeight = (ext.MaxPoint.Y - ext.MinPoint.Y);
  78.               // get the view center point
  79.               Point2d mCentPt = new Point2d(
  80.                 ((ext.MaxPoint.X + ext.MinPoint.X) * 0.5),
  81.                 ((ext.MaxPoint.Y + ext.MinPoint.Y) * 0.5));
  82.               vp.UpgradeOpen();
  83.               if (mWidth > (mHeight * mScrRatio))  mHeight = mWidth / mScrRatio;
  84.               vp.ViewHeight = mHeight * 1.01;
  85.               // set the view center
  86.               vp.ViewCenter = mCentPt;
  87.               vp.Visible = true;
  88.               vp.On = true;
  89.               vp.UpdateDisplay();
  90.               doc.Editor.SwitchToModelSpace();
  91.               Application.SetSystemVariable("CVPORT", vp.Number);
  92.             }
  93.           }
  94.         }
  95.         tr.Commit();
  96.       }
  97.     }
  98.   }
  99. }

Вот результат:

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

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

  • ADN OPEN
  • Сообщений: 25
  • Карма: 3
Александр Ривилис, спасибо большое за затраченное время и отдельное спасибо за код, надеюсь он будет полезен не только мне :) Проблема действительно была в том, что я находил не то видовое окно.
Может у Вас и про масштаб будут идеи? Мне бы его просто вытащить в числовом виде из какой-то переменной или рассчитать. А пока я пробую адаптировать этот пример http://adndevblog.typepad.com/autocad/2012/06/viewport-zoom-scale-factor-.html

p.s. вот здесь https://forums.autodesk.com/t5/net/how-to-fit-entities-to-layout-s-paper-size/m-p/8019328/highlight/false у меня немного другая задача - здесь я копирую объекты на лист без видового экрана (мне нужно сделать один лист с видовым а остальные без), могу продублировать тему здесь :)

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

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


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

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Если есть вероятность того, что среди объектов будут динамические блоки, то их границы надо особым образом находить: http://adn-cis.org/forum/index.php?topic=2933.0
И по своему опыту, я бы предложил ещё немного расширить полученные границы - либо на определённое фиксированное значение (например, на 5 ед.чертежа), либо на относительную величину от вычисленных размеров ВЭ (например, на 1%). Выглядит более симпатично, чем когда объект примыкает к границе видового экрана. Не заметил, в коде это уже учтено :)