- UID
 - 658062
 
- 积分
 - 2147
 
- 精华
 
- 贡献
 -  
 
- 威望
 -  
 
- 活跃度
 -  
 
- D豆
 -  
 
- 在线时间
 -  小时
 
- 注册时间
 - 2008-10-22
 
- 最后登录
 - 1970-1-1
 
 
 
 
 
  
 | 
 
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册 
 
 
 
 
×
 
Selecting Entities In ModelSpace Through Viewport  
 
Very often, we need to select entities in ModelSpace, which are visible in a given Viewport on a layout. That is, we want to project the viewport's boundary (as a rectangle, or as a non-rectangle polygon) into ModelSpace and find all entities inside, fully or partially. 
 
 In other case, given a point, or an entity, in ModelSpace, we may want to determine which viewport or viewports on a layer 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                             { 
   51                                 Polyline2d pl = (Polyline2d)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             Polyline2d polyline, Transaction tran) 
   93         { 
   94             Point3dCollection points = new Point3dCollection(); 
   95  
   96             foreach (ObjectId vxId in polyline) 
   97             { 
   98                 Vertex2d vx = (Vertex2d)tran.GetObject(vxId, OpenMode.ForRead); 
   99                 points.Add(polyline.VertexPosition(vx)); 
  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} fond 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: 
 
 
  
 
 
 
[url=http://drive-cad-with-code.blogspot.com/search?updated-min=2014-01-01T00:00:00-08:00&updated-max=2015-01-01T00:00:00-08:00&max-results=5]http://drive-cad-with-code.blogspot.com/search?updated-min=2014-01-01T00:00:00-08:00&updated-max=2015-01-01T00:00:00-08:00&max-results=5 
 |   
 
 
 
 |