In other case, given a point, or an entity, in ModelSpace, we may want to determine which viewport or viewports on a layout the point/entity can be seen.
Note: there is a post in Autodesk's user forum on this topic.
I began with code that collects Viewport information on a given layout. The information is used to determine which entities in ModelSpace are visible through each Viewport, and is collected in one single transaction. Here is the code:
1 using Autodesk.AutoCAD.ApplicationServices;
2 using Autodesk.AutoCAD.DatabaseServices;
3 using Autodesk.AutoCAD.EditorInput;
4 using Autodesk.AutoCAD.Geometry;
5 using System;
6 using System.Collections.Generic;
7
8 namespace EntitiesInsideViewport
9 {
10 //Class to hold Viewport information, obtained
11 //in single Transaction
12 public class ViewportInfo
13 {
14 public ObjectId ViewportId { set; get; }
15 public ObjectId NonRectClipId { set; get; }
16 public Point3dCollection BoundaryInPaperSpace { set; get; }
17 public Point3dCollection BoundaryInModelSpace { set; get; }
18 }
19
20 public class CadHelper
21 {
22 //Get needed Viewport information
23 public static ViewportInfo[] SelectLockedViewportInfoOnLayout(
24 Document dwg, string layoutName)
25 {
26 List<ViewportInfo> lst = new List<ViewportInfo>();
27 TypedValue[] vals = new TypedValue[]{
28 new TypedValue((int)DxfCode.Start, "VIEWPORT"),
29 new TypedValue((int)DxfCode.LayoutName,layoutName)
30 };
31
32 PromptSelectionResult res =
33 dwg.Editor.SelectAll(new SelectionFilter(vals));
34 if (res.Status==PromptStatus.OK)
35 {
36 using (Transaction tran=
37 dwg.TransactionManager.StartTransaction())
38 {
39 foreach (ObjectId id in res.Value.GetObjectIds())
40 {
41 Viewport vport = (Viewport)tran.GetObject(
42 id, OpenMode.ForRead);
43 if (vport.Number!=1 && vport.Locked)
44 {
45 ViewportInfo vpInfo = new ViewportInfo();
46 vpInfo.ViewportId = id;
47 vpInfo.NonRectClipId = vport.NonRectClipEntityId;
48 if (!vport.NonRectClipEntityId.IsNull &&
49 vport.NonRectClipOn)
50 {
// //Polyline2d pl = (Polyline2d)tran.GetObject(
// // vport.NonRectClipEntityId, OpenMode.ForRead);
52 Polyline pl = (Polyline)tran.GetObject(
52 vport.NonRectClipEntityId, OpenMode.ForRead);
53 vpInfo.BoundaryInPaperSpace =
54 GetNonRectClipBoundary(pl, tran);
55 }
56 else
57 {
58 vpInfo.BoundaryInPaperSpace =
59 GetViewportBoundary(vport);
60 }
61
62 Matrix3d mt = PaperToModel(vport);
63 vpInfo.BoundaryInModelSpace =
64 TransformPaperSpacePointToModelSpace(
65 vpInfo.BoundaryInPaperSpace, mt);
66
67 lst.Add(vpInfo);
68 }
69 }
70
71 tran.Commit();
72 }
73 }
74
75 return lst.ToArray();
76 }
77
78 private static Point3dCollection GetViewportBoundary(Viewport vport)
79 {
80 Point3dCollection points = new Point3dCollection();
81
82 Extents3d ext = vport.GeometricExtents;
83 points.Add(new Point3d(ext.MinPoint.X, ext.MinPoint.Y, 0.0));
84 points.Add(new Point3d(ext.MinPoint.X, ext.MaxPoint.Y, 0.0));
85 points.Add(new Point3d(ext.MaxPoint.X, ext.MaxPoint.Y, 0.0));
86 points.Add(new Point3d(ext.MaxPoint.X, ext.MinPoint.Y, 0.0));
87
88 return points;
89 }
90
91 private static Point3dCollection GetNonRectClipBoundary(
92 Polyline polyline, Transaction tran)
93 {
94 Point3dCollection points = new Point3dCollection();
95
// foreach (ObjectId vxId in polyline)
// {
// Vertex2d vx = (Vertex2d)tran.GetObject(vxId, OpenMode.ForRead);
// points.Add(polyline.VertexPosition(vx));
// }
96 for (int i = 0; i < polyline.NumberOfvertices; i++)
97 {
98
99 points.Add(polyline.GetPoint3dAt(i);
100 }
101
102 return points;
103 }
104
105 private static Point3dCollection TransformPaperSpacePointToModelSpace(
106 Point3dCollection paperSpacePoints, Matrix3d mt)
107 {
108 Point3dCollection points = new Point3dCollection();
109
110 foreach (Point3d p in paperSpacePoints)
111 {
112 points.Add(p.TransformBy(mt));
113 }
114
115 return points;
116 }
117
118 #region
119 //**********************************************************************
120 //Create coordinate transform matrix
121 //between modelspace and paperspace viewport
122 //The code is borrowed from
123 //http://www.theswamp.org/index.php?topic=34590.msg398539#msg398539
124 //*********************************************************************
125 public static Matrix3d PaperToModel(Viewport vp)
126 {
127 Matrix3d mx = ModelToPaper(vp);
128 return mx.Inverse();
129 }
130
131 public static Matrix3d ModelToPaper(Viewport vp)
132 {
133 Vector3d vd = vp.ViewDirection;
134 Point3d vc = new Point3d(vp.ViewCenter.X, vp.ViewCenter.Y, 0);
135 Point3d vt = vp.ViewTarget;
136 Point3d cp = vp.CenterPoint;
137 double ta = -vp.TwistAngle;
138 double vh = vp.ViewHeight;
139 double height = vp.Height;
140 double width = vp.Width;
141 double scale = vh / height;
142 double lensLength = vp.LensLength;
143 Vector3d zaxis = vd.GetNormal();
144 Vector3d xaxis = Vector3d.ZAxis.CrossProduct(vd);
145 Vector3d yaxis;
146
147 if (!xaxis.IsZeroLength())
148 {
149 xaxis = xaxis.GetNormal();
150 yaxis = zaxis.CrossProduct(xaxis);
151 }
152 else if (zaxis.Z < 0)
153 {
154 xaxis = Vector3d.XAxis * -1;
155 yaxis = Vector3d.YAxis;
156 zaxis = Vector3d.ZAxis * -1;
157 }
158 else
159 {
160 xaxis = Vector3d.XAxis;
161 yaxis = Vector3d.YAxis;
162 zaxis = Vector3d.ZAxis;
163 }
164 Matrix3d pcsToDCS = Matrix3d.Displacement(Point3d.Origin - cp);
165 pcsToDCS = pcsToDCS * Matrix3d.Scaling(scale, cp);
166 Matrix3d dcsToWcs = Matrix3d.Displacement(vc - Point3d.Origin);
167 Matrix3d mxCoords = Matrix3d.AlignCoordinateSystem(
168 Point3d.Origin, Vector3d.XAxis, Vector3d.YAxis,
169 Vector3d.ZAxis, Point3d.Origin,
170 xaxis, yaxis, zaxis);
171 dcsToWcs = mxCoords * dcsToWcs;
172 dcsToWcs = Matrix3d.Displacement(vt - Point3d.Origin) * dcsToWcs;
173 dcsToWcs = Matrix3d.Rotation(ta, zaxis, vt) * dcsToWcs;
174
175 Matrix3d perspectiveMx = Matrix3d.Identity;
176 if (vp.PerspectiveOn)
177 {
178 double vSize = vh;
179 double aspectRatio = width / height;
180 double adjustFactor = 1.0 / 42.0;
181 double adjstLenLgth = vSize * lensLength *
182 Math.Sqrt(1.0 + aspectRatio * aspectRatio) * adjustFactor;
183 double iDist = vd.Length;
184 double lensDist = iDist - adjstLenLgth;
185 double[] dataAry = new double[]
186 {
187 1,0,0,0,0,1,0,0,0,0,
188 (adjstLenLgth-lensDist)/adjstLenLgth,
189 lensDist*(iDist-adjstLenLgth)/adjstLenLgth,
190 0,0,-1.0/adjstLenLgth,iDist/adjstLenLgth
191 };
192
193 perspectiveMx = new Matrix3d(dataAry);
194 }
195
196 Matrix3d finalMx =
197 pcsToDCS.Inverse() * perspectiveMx * dcsToWcs.Inverse();
198
199 return finalMx;
200 }
201
202 #endregion
203 }
204 }
Now the following code does 2 things we want to do very often: finding out which entities in ModelSpace are visible in which Viewport; and determining a given entity in ModelSpace is visible in which Viewports:
1 using System.Collections.Generic;
2 using Autodesk.AutoCAD.ApplicationServices;
3 using Autodesk.AutoCAD.DatabaseServices;
4 using Autodesk.AutoCAD.EditorInput;
5 using Autodesk.AutoCAD.Geometry;
6 using Autodesk.AutoCAD.Runtime;
7
8 [assembly: CommandClass(typeof(EntitiesInsideViewport.MyCommands))]
9
10 namespace EntitiesInsideViewport
11 {
12 public class MyCommands
13 {
14 //Use viewport boundary as selecting window/polygon
15 //to find entities in modelspace visible in each viewport
16 [CommandMethod("VpSelect")]
17 public static void SelectByViewport()
18 {
19 Document dwg = Application.DocumentManager.MdiActiveDocument;
20 Editor ed = dwg.Editor;
21
22 //Save current layout name
23 string curLayout = LayoutManager.Current.CurrentLayout;
24
25 try
26 {
27 //Get viewport information on current layout
28 ViewportInfo[] vports = GetViewportInfoOnCurrentLayout();
29 if (vports == null) return;
30
31 //Switch to modelspace
32 LayoutManager.Current.CurrentLayout = "Model";
33
34 //Select entities in modelspace that are visible
35 foreach (ViewportInfo vInfo in vports)
36 {
37 ObjectId[] ents = SelectEntitisInModelSpaceByViewport(
38 dwg, vInfo.BoundaryInModelSpace);
39 ed.WriteMessage("\n{0} entit{1} found via Viewport \"{2}\"",
40 ents.Length,
41 ents.Length > 1 ? "ies" : "y",
42 vInfo.ViewportId.ToString());
43 }
44
45 Autodesk.AutoCAD.Internal.Utils.PostCommandPrompt();
46 }
47 catch (System.Exception ex)
48 {
49 ed.WriteMessage("\nCommand \"VpSelect\" failed:");
50 ed.WriteMessage("\n{0}\n{1}", ex.Message, ex.StackTrace);
51 }
52 finally
53 {
54 //Restore back to original layout
55 if (LayoutManager.Current.CurrentLayout!=curLayout)
56 {
57 LayoutManager.Current.CurrentLayout = curLayout;
58 }
59
60 Autodesk.AutoCAD.Internal.Utils.PostCommandPrompt();
61 }
62 }
63
64 //Determine a given entity in modelspace is visible in
65 //which viewports
66 [CommandMethod("GetViewports")]
67 public static void FindContainingViewport()
68 {
69 Document dwg = Application.DocumentManager.MdiActiveDocument;
70 Editor ed = dwg.Editor;
71
72 //Switch to modelspace
73 string curLayout = LayoutManager.Current.CurrentLayout;
74
75 try
76 {
77 //Get viewport information on current layout
78 ViewportInfo[] vports = GetViewportInfoOnCurrentLayout();
79 if (vports == null) return;
80
81 //Pick an entity in modelspace
82 LayoutManager.Current.CurrentLayout = "Model";
83 ObjectId entId = PickEntity(ed);
84 if (entId.IsNull)
85 {
86 ed.WriteMessage("\n*Cancel*");
87 }
88 else
89 {
90 //Find viewport in which the selected entity is visible
91 List<ObjectId> lst = new List<ObjectId>();
92 foreach (ViewportInfo vpInfo in vports)
93 {
94 if (IsEntityInsideViewportBoundary(
95 dwg, entId, vpInfo.BoundaryInModelSpace))
96 {
97 lst.Add(vpInfo.ViewportId);
98 ed.WriteMessage(
99 "\nSelected entity is visible in viewport \"{0}\"",
100 vpInfo.ViewportId.ToString());
101 }
102 }
103
104 if (lst.Count == 0)
105 ed.WriteMessage(
106 "\nSelected entity is not visible in all viewports");
107 else
108 ed.WriteMessage(
109 "\nSelected entity is visible in {0} viewport{1}.",
110 lst.Count, lst.Count > 1 ? "s" : "");
111 }
112
113 Autodesk.AutoCAD.Internal.Utils.PostCommandPrompt();
114 }
115 catch (System.Exception ex)
116 {
117 ed.WriteMessage("\nCommand \"GetViewports\" failed:");
118 ed.WriteMessage("\n{0}\n{1}", ex.Message, ex.StackTrace);
119 }
120 finally
121 {
122 //Restore back to original layout
123 if (LayoutManager.Current.CurrentLayout != curLayout)
124 {
125 LayoutManager.Current.CurrentLayout = curLayout;
126 }
127
128 Autodesk.AutoCAD.Internal.Utils.PostCommandPrompt();
129 }
130 }
131
132 private static ViewportInfo[] GetViewportInfoOnCurrentLayout()
133 {
134 string layoutName = LayoutManager.Current.CurrentLayout;
135 if (layoutName.ToUpper() == "MODEL")
136 {
137 Application.ShowAlertDialog("Please set a layout as active layout!");
138 return null;
139 }
140 else
141 {
142 Document dwg = Application.DocumentManager.MdiActiveDocument;
143 ViewportInfo[] vports =
144 CadHelper.SelectLockedViewportInfoOnLayout(dwg, layoutName);
145 if (vports.Length == 0)
146 {
147 Application.ShowAlertDialog(
148 "No locked viewport found on layout \"" + layoutName + "\".");
149 return null;
150 }
151 else
152 {
153 return vports;
154 }
155 }
156 }
157
158 private static ObjectId[] SelectEntitisInModelSpaceByViewport(
159 Document dwg, Point3dCollection boundaryInModelSpace)
160 {
161 ObjectId[] ids = null;
162
163 using (Transaction tran=dwg.TransactionManager.StartTransaction())
164 {
165 //Zoom to the extents of the viewport boundary in modelspace
166 //before calling Editor.SelectXxxxx()
167 ZoomToWindow(boundaryInModelSpace);
168
169 PromptSelectionResult res =
170 dwg.Editor.SelectCrossingPolygon(boundaryInModelSpace);
171 if (res.Status==PromptStatus.OK)
172 {
173 ids = res.Value.GetObjectIds();
174 }
175
176 //Restored to previous view (view before zoomming)
177 tran.Abort();
178 }
179
180 return ids;
181 }
182
183 private static void ZoomToWindow(Point3dCollection boundaryInModelSpace)
184 {
185 Extents3d ext =
186 GetViewportBoundaryExtentsInModelSpace(boundaryInModelSpace);
187
188 double[] p1 = new double[] { ext.MinPoint.X, ext.MinPoint.Y, 0.00 };
189 double[] p2 = new double[] { ext.MaxPoint.X, ext.MaxPoint.Y, 0.00 };
190
191 dynamic acadApp = Application.AcadApplication;
192 acadApp.ZoomWindow(p1, p2);
193 }
194
195 private static Extents3d GetViewportBoundaryExtentsInModelSpace(
196 Point3dCollection points)
197 {
198 Extents3d ext = new Extents3d();
199 foreach (Point3d p in points)
200 {
201 ext.AddPoint(p);
202 }
203
204 return ext;
205 }
206
207 private static ObjectId PickEntity(Editor ed)
208 {
209 PromptEntityOptions opt =
210 new PromptEntityOptions("\nSelect an entity:");
211 PromptEntityResult res = ed.GetEntity(opt);
212 if (res.Status==PromptStatus.OK)
213 {
214 return res.ObjectId;
215 }
216 else
217 {
218 return ObjectId.Null;
219 }
220 }
221
222 private static bool IsEntityInsideViewportBoundary(
223 Document dwg, ObjectId entId, Point3dCollection boundaryInModelSpace)
224 {
225 bool inside = false;
226 using (Transaction tran = dwg.TransactionManager.StartTransaction())
227 {
228 //Zoom to the extents of the viewport boundary in modelspace
229 //before calling Editor.SelectXxxxx()
230 ZoomToWindow(boundaryInModelSpace);
231
232 PromptSelectionResult res =
233 dwg.Editor.SelectCrossingPolygon(boundaryInModelSpace);
234 if (res.Status == PromptStatus.OK)
235 {
236 foreach (ObjectId id in res.Value.GetObjectIds())
237 {
238 if (id==entId)
239 {
240 inside = true;
241 break;
242 }
243 }
244 }
245
246 //Restored to previous view (before zoomming)
247 tran.Abort();
248 }
249
250 return inside;
251 }
252 }
253 }
Following picture shows the drawing I test the code against:
Update on 2019-12-27:
Code has been updated, referring to latest comment below. Grayed lines were removed, yellowed lines were replacement.