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

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

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

Оффлайн Александр Пекшев 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