A few days ago when I update an existing CAD application, I was asked to select certain entities visible in current view, be them in modelspace layout or paperspace layout, or in a active viewport of paperspace layout. I thought, "OK, I can get the size of current view and then select everything in a window that is the size of the current view (or slightly smaller than the view size). Then I went on searching Object Browser in Visual Studio for View, Viewport, ViewTableRecord, ViewportTableRecord... to see how I can easily get the size of current view in AutoCAD.
Well, it turned out that it would be unnecessarily complicated if I tried to use these classes for this task and luckily I recalled in my old VBA code I used AutoCAD system variables for similar work: VIEWSIZE and VIEWCTR.
System variable VIEWCTR provides a Point3d value as current view's centre point, while VIEWSIZE is the height of current view, measured in drawing unit. The problem left is how to know the width of current view? Again, another system variable SCREENSIZE comes to rescue: it provides the current viewport's size, but in PIXELs. Here what the unit of the size from SCREENSIZE is does not matter, we can use the ratio of width-height to calculate the current view's width in drawing unit from its height, like this:
view_width=view_height * (screen_width/screen_height)
The other thing to be careful is that the view's centre from VIEWCTR is in UCS coordinate.
Here is the code to get current view's size and its extents:
1 using Autodesk.AutoCAD.ApplicationServices;
2 using Autodesk.AutoCAD.DatabaseServices;
3 using Autodesk.AutoCAD.Geometry;
4
5 namespace GetViewSize
6 {
7 public class ViewUtil
8 {
9 private Document _dwg;
10
11 public ViewUtil(Document dwg)
12 {
13 _dwg = dwg;
14 }
15
16 public Point2d GetCurrentViewSize()
17 {
18 //Get current view height
19 double h = (double)Application.GetSystemVariable("VIEWSIZE");
20
21 //Get current view width,
22 //by calculate current view's width-height ratio
23 Point2d screen = (Point2d)Application.GetSystemVariable("SCREENSIZE");
24 double w = h * (screen.X / screen.Y);
25
26 return new Point2d(w, h);
27 }
28
29 public Extents2d GetCurrentViewBound(
30 double shrinkScale=1.0, bool drawBoundBox=false)
31 {
32 //Get current view size
33 Point2d vSize = GetCurrentViewSize();
34
35 double w = vSize.X * shrinkScale;
36 double h = vSize.Y * shrinkScale;
37
38
39 //Get current view's centre.
40 //Note, the centre point from VIEWCTR is in UCS and
41 //need to be transformed back to World CS
42 Point3d cent = ((Point3d)Application.GetSystemVariable("VIEWCTR")).
43 TransformBy(_dwg.Editor.CurrentUserCoordinateSystem);
44
45 Point2d minPoint = new Point2d(cent.X - w / 2.0, cent.Y - h / 2.0);
46 Point2d maxPoint = new Point2d(cent.X + w / 2.0, cent.Y + h / 2.0);
47
48 if (drawBoundBox)
49 {
50 DrawBoundBox(minPoint, maxPoint);
51 }
52
53 return new Extents2d(minPoint, maxPoint);
54 }
55
56 private void DrawBoundBox(Point2d minPoint, Point2d maxPoint)
57 {
58 using (Transaction tran = _dwg.TransactionManager.StartTransaction())
59 {
60 //Get current space
61 BlockTableRecord space = (BlockTableRecord)tran.GetObject(
62 _dwg.Database.CurrentSpaceId, OpenMode.ForWrite);
63
64 //Create a polyline as bounding box
65 Polyline pl = new Polyline(4);
66
67 pl.AddVertexAt(0, minPoint, 0.0, 0.0, 0.0);
68 pl.AddVertexAt(1, new Point2d(minPoint.X, maxPoint.Y), 0.0, 0.0, 0.0);
69 pl.AddVertexAt(2, maxPoint, 0.0, 0.0, 0.0);
70 pl.AddVertexAt(3, new Point2d(maxPoint.X, minPoint.Y), 0.0, 0.0, 0.0);
71 pl.Closed = true;
72
73 pl.SetDatabaseDefaults(_dwg.Database);
74
75 space.AppendEntity(pl);
76 tran.AddNewlyCreatedDBObject(pl, true);
77
78 tran.Commit();
79 }
80 }
81 }
82 }
In the GetCurrentViewBound() method, the optional argument "shrinkScale" is used for getting a slight smaller bound than the view is (or slightly larger, if it is greater than 1.0). The second optional argument is mostly for debugging purpose: if set to "true", a polyline would be drawn as the bounding box of the current view.
Here is the command class to run the code:
1 using Autodesk.AutoCAD.ApplicationServices;
2 using Autodesk.AutoCAD.EditorInput;
3 using Autodesk.AutoCAD.Geometry;
4 using Autodesk.AutoCAD.Runtime;
5
6 [assembly: CommandClass(typeof(GetViewSize.MyCommands))]
7
8 namespace GetViewSize
9 {
10 public class MyCommands
11 {
12 [CommandMethod("GetViewSize")]
13 public static void RunMyCommand()
14 {
15 Document dwg = Application.DocumentManager.MdiActiveDocument;
16 Editor ed = dwg.Editor;
17
18 ViewUtil util = new ViewUtil(dwg);
19
20 try
21 {
22 //Get current view size
23 Point2d vSize = util.GetCurrentViewSize();
24 ed.WriteMessage("\nCurrent view size: " +
25 "H={0} W={1}", vSize.Y, vSize.X);
26
27 //Draw a bound box of current view, which
28 //is slightly smaller than current view
29 util.GetCurrentViewBound(0.95, true);
30
31 //Draw a bound box of current view, which
32 //is exactly the same size as current view
33 util.GetCurrentViewBound(1.0, true);
34 }
35 catch (System.Exception ex)
36 {
37 ed.WriteMessage("\nError: {0}", ex.ToString());
38 }
39
40 Autodesk.AutoCAD.Internal.Utils.PostCommandPrompt();
41 }
42 }
43 }
The code can be used to get current view's size. When in tiled multi-viewport modelspace, the view is the view in active viewport. When in paperspace layout, if there is no paperspace viewport active (after command "PS"), the view is the view of paperspace, while if there is a paperspace viewport active (after command "MS"), the view is the modelspace view seeing through the paperspace viewport.
Well, with paperspace viewport, one can use the size of the viewport and transform to size in modelspace in order to get the model view size seeing through the paperspace viewport. If the paperspace viewport has non-rectangular border, then the simple approach to get a rectangular view size shown in this article would be problematic (when the purpose is to selecting all entities visible in the view/viewport.
Well, with paperspace viewport, one can use the size of the viewport and transform to size in modelspace in order to get the model view size seeing through the paperspace viewport. If the paperspace viewport has non-rectangular border, then the simple approach to get a rectangular view size shown in this article would be problematic (when the purpose is to selecting all entities visible in the view/viewport.
2 comments:
Nice article. Thank you.
i'm having the same reference problem.
System.Windows.Point pointWindows = ed.PointToScreen(pickBoxCentre, 1);
System.Drawing.Point screenPt = new System.Drawing.Point((int) pointWindows.X, (int)pointWindows.Y) ;
this is what i did to solve. am i doing this right?
rgds
Post a Comment