Determining the Size and Location of Viewports on a Sheet

Today, let's look at how to determine the size and location of a sheet and the views displayed by it.

This is part of the first and most Revit-related of the three enhancement goals for my simplified 2D BIM editor:

In previous versions of Revit, determining the size and locations of views on a sheet was a pretty challenging undertaking.

Here are some related explorations:

A quote from the third: "The View class has a very important property Outline. The Outline property will return the Max and Min point of the closest bounding box, which includes all elements in this view. The value in this Max and Min the result of the legend view's real Max and Min coordinates subdivided by the view scale. For more information about Outline property, please refer to the Revit SDK developer guide 'Revit 2011 API Developer Guide.pdf'. Approximately, the outline Max point is mapping the same Max point of the viewport in view sheet."

Nowadays, the Viewport class provides an Outline property that considerably simplifies this task.

Here is a sheet 'A101 - Level 0, 1 and 3D' displaying three views:

Sheet displaying three views

My GeoSnoop utility dynamically generates this temporary form displaying the outlines of the sheet and the three views it contains:

GeoSnoop displaying the sheet and vieport outlines

The top level code in the CmdUploadSheets external command implementation retrieving the sheet and viewport loops and displaying them in a temporary modeless form basically just consists of two lines of code, calling the new GetSheetViewportLoops and the existing GeoSnoop.DisplayLoops methods:

  foreach( ViewSheet sheet in sheets )
  {
    JtLoops sheetViewportLoops
      = GetSheetViewportLoops( sheet );
 
    string sheet_number = sheet.get_Parameter(
      BuiltInParameter.SHEET_NUMBER )
        .AsString();
 
    caption = string.Format(
      "Sheet and Viewport Loops - {0} - {1}",
      sheet_number, sheet.Name );
 
    GeoSnoop.DisplayLoops( revit_window,
      caption, false, sheetViewportLoops );
  }

The GeoSnoop.DisplayLoops method is pretty much unchanged from its last incarnation for displaying room and furniture loops using symbols, except that the family instances and symbol geometry arguments now are optional and default to null.

The interesting new code to retrieve the sheet and viewport rectangles is short and sweet, making use of a couple of extensions I added to the existing Point2dInt and JtLoop classes:

  /// <summary>
  /// Return polygon loops representing the size 
  /// and location of given sheet and the viewports 
  /// it contains.
  /// </summary>
  static JtLoops GetSheetViewportLoops(
    ViewSheet sheet )
  {
    Document doc = sheet.Document;
 
    List<Viewport> viewports = sheet
      .GetAllViewports()
      .Select<ElementId,Viewport>(
        id => doc.GetElement( id ) as Viewport )
      .ToList<Viewport>();
 
    int n = viewports.Count;
 
    JtLoops sheetViewportLoops = new JtLoops( n + 1 );
 
    BoundingBoxUV bb = sheet.Outline; // (0,0), (2.76,1.95)
 
    JtBoundingBox2dInt ibb = new JtBoundingBox2dInt(); // (0,0),(840,...)
 
    ibb.ExpandToContain( new Point2dInt( bb.Min ) );
    ibb.ExpandToContain( new Point2dInt( bb.Max ) );
 
    JtLoop loop = new JtLoop( 4 );
 
    loop.Add( ibb.Corners );
 
    sheetViewportLoops.Add( loop );
 
    foreach( Viewport vp in viewports )
    {
      XYZ center = vp.GetBoxCenter();
      Outline outline = vp.GetBoxOutline();
 
      ibb.Init();
 
      ibb.ExpandToContain(
        new Point2dInt( outline.MinimumPoint ) );
 
      ibb.ExpandToContain(
        new Point2dInt( outline.MaximumPoint ) );
 
      loop = new JtLoop( 4 );
 
      loop.Add( ibb.Corners );
 
      sheetViewportLoops.Add( loop );
    }
    return sheetViewportLoops;
  }

The updated RoomEditorApp source code, Visual Studio solution and add-in manifest live in the RoomEditorApp GitHub repository.

The version discussed above is release 2015.0.2.8.