Setting a Default 3D View Orientation

Here is a nice little explanation by Alexander Ignatovich of Investicionnaya Venchurnaya Companiya (that sounds like a venture investment company to me) on how to export an image file for a family or project.

One issue that cropped up was how to set the default view orientation for a newly created 3D view:

Question: In versions prior to Revit 2014, I used this code to create a new 3D view with a default view direction:

  var direction = new XYZ( -1, 1, -1 );
  var view3D = doc.IsFamilyDocument
    ? doc.FamilyCreate.NewView3D( direction )
    : doc.Create.NewView3D( direction );

I am having difficulty obtaining the same result in Revit 2014, though, using the View3D CreateIsometric and SetOrientation methods.

I tried the following, but with no success:

  var direction = new XYZ(-1, 1, -1);
  var collector = new FilteredElementCollector(doc);
  var viewFamilyType = collector
    .OfClass<ViewFamilyType>()
    .Cast<ViewFamilyType>()
    .FirstOrDefault(x => x.ViewFamily
      == ViewFamily.ThreeDimensional);
 
  // . . . 
 
  var view3D = View3D.CreateIsometric(
    doc, viewFamilyType.Id);
 
  // . . .
 
  view3D.SetOrientation( new ViewOrientation3D(
    direction, new XYZ(0, 1, 1), new XYZ(0, 1, -1)));

The result differs from the old obsolete code.

What parameters should I use to get the same result?

Answer: I solved my issue trying to generate pictures of families and project documents looking like the default 3D views in Revit.

I think I found the simplest way to do this, and maybe it will be useful not only for me.

When I initially tried to convert my code to the new way, I called the method

  view3D.SetOrientation(
    new ViewOrientation3D(
      direction,
      new XYZ( 0, 1, 1 ),
      new XYZ( 0, 1, -1 ) ) );

I just removed the call to invoke the SetOrientation method and it now works perfectly.

It generates very nice pictures :-) Here are two of them:

Sample image
Sample image

In my code, I make use of the following filtered element collector extension methods:

public static class FilteredElementCollectorExtensions
{
  public static FilteredElementCollector OfClass<T>(
    this FilteredElementCollector collector )
      where T : Element
  {
    return collector.OfClass( typeof( T ) );
  }
 
  public static IEnumerable<T> OfType<T>(
    this FilteredElementCollector collector )
      where T : Element
  {
    return Enumerable.OfType<T>(
      collector.OfClass<T>() );
  }
}

Then I can generate the views using the following:

static string ExportToImage( Document doc )
{
  var tempFileName = Path.ChangeExtension(
    Path.GetRandomFileName(), "png" );
 
  string tempImageFile;
 
  try
  {
    tempImageFile = Path.Combine(
      Path.GetTempPath(), tempFileName );
  }
  catch( IOException )
  {
    return null;
  }
 
  IList<ElementId> views = new List<ElementId>();
 
  try
  {
 
#if !VERSION2014
    var direction = new XYZ(-1, 1, -1);
    var view3D = doc.IsFamilyDocument
      ? doc.FamilyCreate.NewView3D(direction)
      : doc.Create.NewView3D(direction);
#else
    var collector = new FilteredElementCollector(
      doc );
 
    var viewFamilyType = collector
      .OfClass( typeof( ViewFamilyType ) )
      .OfType<ViewFamilyType>()
      .FirstOrDefault( x =>
        x.ViewFamily == ViewFamily.ThreeDimensional );
 
    var view3D = ( viewFamilyType != null )
      ? View3D.CreateIsometric( doc, viewFamilyType.Id )
      : null;
 
#endif // VERSION2014
 
    if( view3D != null )
    {
      views.Add( view3D.Id );
 
      var graphicDisplayOptions
        = view3D.get_Parameter(
          BuiltInParameter.MODEL_GRAPHICS_STYLE );
 
      // Settings for best quality
 
      graphicDisplayOptions.Set( 6 );
    }
  }
  catch( Autodesk.Revit.Exceptions
    .InvalidOperationException )
  {
  }
 
  var ieo = new ImageExportOptions
  {
    FilePath = tempImageFile,
    FitDirection = FitDirectionType.Horizontal,
    HLRandWFViewsFileType = ImageFileType.PNG,
    ImageResolution = ImageResolution.DPI_150,
    ShouldCreateWebSite = false
  };
 
  if( views.Count > 0 )
  {
    ieo.SetViewsAndSheets( views );
    ieo.ExportRange = ExportRange.SetOfViews;
  }
  else
  {
    ieo.ExportRange = ExportRange
      .VisibleRegionOfCurrentView;
  }
 
  ieo.ZoomType = ZoomFitType.FitToPage;
  ieo.ViewName = "tmp";
 
  if( ImageExportOptions.IsValidFileName(
    tempImageFile ) )
  {
    // If ExportRange = ExportRange.SetOfViews 
    // and document is not active, then image 
    // exports successfully, but throws
    // Autodesk.Revit.Exceptions.InternalException
 
    try
    {
      doc.ExportImage( ieo );
    }
    catch
    {
      return string.Empty;
    }
  }
  else
  {
    return string.Empty;
  }
 
  // File name has format like 
  // "tempFileName - view type - view name", e.g.
  // "luccwjkz - 3D View - {3D}.png".
  // Get the first image (we only listed one view
  // in views).
 
  var files = Directory.GetFiles(
    Path.GetTempPath(),
    string.Format( "{0}*.*", Path
      .GetFileNameWithoutExtension(
        tempFileName ) ) );
 
  return files.Length > 0
    ? files[0]
    : string.Empty;
}

Many thanks to Alexander for sharing this!

Addendum – ImageExportOptions.GetFileName

Maxence points out in his comment below:

Since Revit 2015 you can use the static method ImageExportOptions.GetFileName() to get the file name (without path and without extension) that will be produced when exporting a view to an image.