Monday, March 23, 2009

Revit: How to print sheets in order.

I’ve had a bit of fun lately working with the Revit 2009/2010 API for printing views. There is a useful SDK sample, ‘ViewPrinter’ which shows you how to replicate the print menu in revit, but using the API.

I’ve created a customized version of this that links in with our companies document management systems, and does things like prints, renames, and copies PDFs to the correct directory all with the press of a button.

This has been working well for our drafters, and has sped things up, however there have been a few issues that I’ve run into whilst following the methods set out in ViewPrinter and in the SDK documentation. Most of them relate to selecting certain views (in this case, sheets) and printing them in the correct order, and with the correct amount of copies.

The way the SDK sample does this, is it gathers a list of the sheet names the user selected, compares their names with those in the PrintMan.ViewSheetSetting.AvailableViews list and selects ones that match. It then adds these into a ViewSet, and supplies that to PrintMan and calls SubmitPrint().

   1: //create Viewset store those you need to print
   2: ViewSet viewsToPrint = new ViewSet();
   3:  
   4: //Compare your list of sheets, to those in AvailableViews
   5: foreach (string name in selectedSheetNames) 
   6: {
   7:     foreach (View view in _printMan.ViewSheetSetting.AvailableViews)
   8:      {
   9:         if (view.ViewType == ViewType.DrawingSheet)
  10:         {
  11:             //cast to viewsheet
  12:             ViewSheet vs = view as ViewSheet;
  13:  
  14:             if (vs != null && name.Contains(vs.SheetNumber + " - " + vs.Name))
  15:             {
  16:                 viewsToPrint.Insert(vs);
  17:             }
  18:         }
  19:      }
  20: }
  21:  
  22: ViewSheetSet viewSheetSet = m_viewSheetSetting.CurrentViewSheetSet;
  23: viewSheetSet.Views = selectedViews;
  24: m_viewSheetSetting.Save();
  25:  
  26: //set copies
  27: _printMan.CopyNumber = numCopies;
  28:  
  29: //submit print
  30: _printMan.SubmitPrint(v); 
  31:  
  32:  

This works great ok normally, however there is a significant problem. The problem lies in how the views are stored. The views are placed into a ViewSet, which is an implementation of the Set collection type, ie, an unordered set of items. Unfortunately, this means that us coders have no say in how the prints get ordered.

My experimentation shows that revit seems to order them by ElementID, or, in the order they were created. So lets say you create Sheet 1, Sheet 2, Sheet 4, Sheet 3, in that order. That is exactly how they will come out of the printer, even though the user would assume otherwise.

My workaround for this, after much trial and error, is this:

   1: //create a list of view tp store those you need to print
   2: List<View> viewsToPrint = new List<View>();
   3:  
   4: //Compare your list of sheets, to those in AvailableViews
   5: foreach (string name in selectedSheetNames) 
   6: {
   7:     foreach (View view in _printMan.ViewSheetSetting.AvailableViews)
   8:      {
   9:         if (view.ViewType == ViewType.DrawingSheet)
  10:         {
  11:             //cast to viewsheet
  12:             ViewSheet vs = view as ViewSheet;
  13:  
  14:             if (vs != null && name.Contains(vs.SheetNumber + " - " + vs.Name))
  15:             {
  16:                 viewsToPrint.Add(vs);
  17:             }
  18:         }
  19:      }
  20: }
  21: //loop through copies 
  22: for (int i = 1; i <= numCopies; i++) 
  23: { 
  24:  //loop through each view 
  25:  foreach (View v in viewsToPrint) 
  26:  { 
  27:   //submit print of just 1 view 
  28:    _printMan.SubmitPrint(v); 
  29:   } 
  30: }

There are a number of steps behind the scenes (such as setting up _printMan aka my PrintManager to have the correct settings) but instead of supplying PrintManager with a ViewSet of views I want to print, and changing the CopyNumber to how many times I wish to print them, I’m printing one view at a time using the overload for SubmitPrint. This allows me to order my list of selectedSheetNames in the way I wish it to come out, including sorting and reversing it. I’ve also done a for loop to replicate the CopyNumber property.

Now, at long last, my prints are coming out in the correct order!

Note: This code was created for Revit 2010, not fully tested in 2009, though most of it should work the same.

Revit 2010 Kinks – BuiltInCategory.OST_DrawingSheets

In going through and converting my external tools, I stumbled across this problem. A few of my tools used a CategoryFilter on the category ‘BuiltInCategory.OST_DrawingSheets’, this was so I could get all of the sheets in the revit model. It appears this is not a category anymore.

A scroll through the categories revealed another category ‘BuiltInCategory.OST_Sheets’, that appears to achieve the same results.

I plan to continue posting any little changes like this that I’ve noticed in my Revit 2010 conversions.

Wednesday, March 11, 2009

Revit 2010 - More feedback on external commands errors

While Matt Mason has been blogging away furiously at the Revit 2010 platform/API enhancements, I've got a smaller feature to talk about.
If you're anything like me, you would have run into the situation where you create an external command, link it up in the ini file, and go to run it.. and get nothing, no error, no warnings, just nothing. While the journal file can sometimes offer a little bit of assistance, you really have very little to go on.
This has changed in 2010, with increased reporting of errors in API commands. One I noticed today is that if you link to a DLL file in the revit.ini that doesn't exist, you will get a popup warning alerting you that your dll doesn't exist and thus the command has been disabled. This is great, as often typos are made in the revit.ini, and this points you straight to it.
Another one is that when an unhandled exception occurs, a friendlier dialog box is now shown, alerting the user to the error, and allows them to view technical detail if they wish. Previously it was a standard .net dialog box which didn't mean much to the end user.
It's the little things that count, and this little thing is a worthy inclusion in Revit 2010!