using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
using Autodesk.Windows;
namespace Test
{
public class VPTest
{
[CommandMethod("ForVPTest", CommandFlags.NoBlockEditor)]
public void Run()
{
Document adoc = Application.DocumentManager.MdiActiveDocument;
Database db = adoc.Database;
Editor ed = adoc.Editor;
// ID модели текущего чертежа
ObjectId mSpaceId = SymbolUtilityServices.GetBlockModelSpaceId(db);
// Менеджер листов текущего документа
LayoutManager layoutMgr = LayoutManager.Current;
//Коллекция ID листов документа
Dictionary<ObjectId, string> layouts = new Dictionary<ObjectId, string>();
using (Transaction tr = db.TransactionManager.StartTransaction())
using (DBDictionary layoutDict = tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead) as DBDictionary)
{
foreach (DBDictionaryEntry dbDictEnt in layoutDict)
if (dbDictEnt.Key != "Model") layouts.Add(dbDictEnt.Value, dbDictEnt.Key);
tr.Commit();
}
string[] selLayouts = layouts.Values.ToArray();
if (selLayouts.Length > 0)
{
// Запоминаем текущий лист
string startLayout = layoutMgr.CurrentLayout;
#region Пробегаем по листам
foreach (KeyValuePair<ObjectId, string> layout in layouts)
{
if (selLayouts.Contains(layout.Value))
{
//Устанавливаем текущим новый лист
layoutMgr.CurrentLayout = layout.Value;
// Обновляем вид приложения
System.Windows.Forms.Application.DoEvents();
string curLayoutName = layout.Value;
ObjectId curLayoutId = layout.Key;
using (Transaction tr = db.TransactionManager.StartTransaction())
// Блок модели текущего чертежа
using (BlockTableRecord mSpace = tr.GetObject(mSpaceId, OpenMode.ForWrite) as BlockTableRecord)
// Таблица блоков текущего чертежа
using (BlockTable blkTable = tr.GetObject(db.BlockTableId, OpenMode.ForWrite) as BlockTable)
using (DBDictionary layoutDict = tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead) as DBDictionary)
using (Layout curLay = tr.GetObject(curLayoutId, OpenMode.ForRead) as Layout)
using (BlockTableRecord blkTabRec = tr.GetObject(curLay.BlockTableRecordId, OpenMode.ForRead) as BlockTableRecord)
{
// Проверяем наличие видовых экранов на листе
// Переменная для коллекции ID видовых экранов
ObjectIdCollection vPortsIds = new ObjectIdCollection();
// Получение коллекции видовых экранов на текущем листе
vPortsIds = curLay.GetViewports();
// Исключаем из коллекции главный видовой экран листа
vPortsIds.RemoveAt(0);
// Если есть ВЭ - ищем границы в модели
if (vPortsIds.Count > 0)
{
// Переключаемся в пространство листа
ed.SwitchToPaperSpace();
// Сохраняем исходный вид
using (ViewTableRecord curLayoutView = ed.GetCurrentView())
{
// Проходим по видовым экранам в листе
foreach (ObjectId vPortId in vPortsIds)
{
// Получаем ссылку на объект ВЭ
Viewport viewport = tr.GetObject(vPortId, OpenMode.ForRead) as Viewport;
// Коллекция объектов в текущем ВЭ
DBObjectCollection vpDbObjCol = new DBObjectCollection();
// Номер текущего видового экрана
short vpNumber = (short)viewport.Number;
// Границы области ВЭ
Extents3d vpExts;
// Коллекция для точек видового экрана
Point3dCollection psVpPnts = new Point3dCollection();
// Получаем границы его области
vpExts = viewport.GeometricExtents;
#region Получаем координаты границы текущего ВЭ
// Если видовой экран стандартный прямоугольный
if (!viewport.NonRectClipOn)
{
// Получаем его точки
viewport.GetGripPoints(psVpPnts, new IntegerCollection(), new IntegerCollection());
// Выстраиваем точки в правильном порядке, по умолчанию они крест-накрест
Point3d tmp = psVpPnts[2];
psVpPnts[2] = psVpPnts[1];
psVpPnts[1] = tmp;
}
// Если видовой экран подрезанный - получаем примитив, по которому он подрезан
else
{
using (Entity ent = tr.GetObject(viewport.NonRectClipEntityId, OpenMode.ForRead) as Entity)
{
//vpExts = ent.GeometricExtents;
// Если это полилиния - извлекаем ее точки
if (ent is Polyline)
{
Polyline pline = ent as Polyline;
for (int i = 0; i < pline.NumberOfVertices; i++) psVpPnts.Add(pline.GetPoint3dAt(i));
}
else if (ent is Polyline2d)
{
Polyline2d pline2d = ent as Polyline2d;
foreach (ObjectId vertId in pline2d)
{
using (Vertex2d vert = tr.GetObject(vertId, OpenMode.ForRead) as Vertex2d)
{
if (!psVpPnts.Contains(vert.Position)) psVpPnts.Add(vert.Position);
}
}
}
else if (ent is Curve)
{
Curve curve = ent as Curve;
double
startParam = curve.StartParam,
endParam = curve.EndParam,
delParam = (endParam - startParam) / 100;
for (double curParam = startParam; curParam < endParam; curParam += delParam)
{
Point3d curPt = curve.GetPointAtParameter(curParam);
psVpPnts.Add(curPt);
curParam += delParam;
}
}
else
{
Application.ShowAlertDialog("Видовой экран подрезан необрабатываемым объектом!"
+ string.Format("\nЛист: {0}, видовой экран №{1}, объект подрезки: {2}\n", curLayoutName, vpNumber, ent.ToString()));
}
}
}
#endregion Получаем координаты границы текущего ВЭ
#region Переводим в модель граничные точки текущего ВЭ
// Зуммируем ВЭ
ed.ZoomWin(vpExts);
// Обновляем вид
ed.UpdateScreen();
// Переходим внутрь активного ВЭ
ed.SwitchToModelSpace();
// Проверяем состояние ВЭ
if (viewport.Number > 0)
{
// Переключаемся в обрабатываемый ВЭ
Application.SetSystemVariable("CVPORT", vpNumber);
// Преобразование точки из PS в MS
ResultBuffer rbPSDCS = new ResultBuffer(new TypedValue(5003, 3));
ResultBuffer rbDCS = new ResultBuffer(new TypedValue(5003, 2));
ResultBuffer rbWCS = new ResultBuffer(new TypedValue(5003, 0));
double[] retPoint = new double[] { 0, 0, 0 };
// loop the ps points
Point3dCollection msVpPnts = new Point3dCollection();
Point2dCollection msVpPnts2d = new Point2dCollection();
foreach (Point3d pnt in psVpPnts)
{
// преобразуем из DCS пространства Листа (PSDCS) RTSHORT=3
// в DCS пространства Модели текущего Видового Экрана RTSHORT=2
Support.acedTrans(pnt.ToArray(), rbPSDCS.UnmanagedObject, rbDCS.UnmanagedObject, 0, retPoint);
// Преобразуем из DCS пространства Модели текущего Видового Экрана RTSHORT=2
// в WCS RTSHORT=0
Support.acedTrans(retPoint, rbDCS.UnmanagedObject, rbWCS.UnmanagedObject, 0, retPoint);
// Добавляем точку в коллекцию
Point3d newPt = new Point3d(retPoint);
if (!msVpPnts.Contains(newPt)) msVpPnts.Add(newPt);
Point2d newPt2d = newPt.ConvertTo2D();
msVpPnts2d.Add(newPt2d);
}
#endregion Переводим в модель граничные точки текущего ВЭ
}
// Переключаемся в лист
ed.SwitchToPaperSpace();
}
ed.SetCurrentView(curLayoutView);
}
}
tr.Commit();
}
}
}
#endregion
layoutMgr.CurrentLayout = startLayout;
}
}
}
static class Support
{
/// <summary>
/// http://through-the-interface.typepad.com/through_the_interface/2008/06/zooming-to-a-wi.html
/// </summary>
/// <param name="ed">Редактор документа</param>
/// <param name="min">Первая точка ограничивающей рамки</param>
/// <param name="max">Вторая точка ограничивающей рамки</param>
public static void ZoomWin(this Editor ed, Point3d min, Point3d max)
{
Point2d min2d = new Point2d(min.X, min.Y);
Point2d max2d = new Point2d(max.X, max.Y);
ViewTableRecord view = (ViewTableRecord)ed.GetCurrentView().Clone();
view.CenterPoint = min2d + ((max2d - min2d) / 2.0);
view.Height = max2d.Y - min2d.Y;
view.Width = max2d.X - min2d.X;
ed.SetCurrentView(view);
}
public static void ZoomWin(this Editor ed, Extents3d ext3d)
{
ed.ZoomWin(ext3d.MinPoint, ext3d.MaxPoint);
}
/// <summary>
/// http://adndevblog.typepad.com/autocad/2013/page/41/
/// </summary>
/// <param name="point">Точки на листе</param>
/// <param name="fromRb">Система координат "ИЗ"</param>
/// <param name="toRb">Система координат "В"</param>
/// <param name="disp"></param>
/// <param name="result"></param>
/// <returns></returns>
[DllImport("accore.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedTrans")]
public static extern int acedTrans(double[] point, IntPtr fromRb, IntPtr toRb, int disp, double[] result);
/// <summary>
/// Преобразование 3Д точки в 2Д путем отсекания координаты Z.
/// </summary>
/// <param name="point3d">3Д точка</param>
/// <returns>2Д точка</returns>
public static Point2d ConvertTo2D(this Point3d point3d)
{
return new Point2d(point3d.X, point3d.Y);
}
}
}