Hey folks!
My program loops through all the sheets in a document (open in the background - no UI) to get some info such as name, number, "approved by" etc.
Why does Revit, during the looping, say "Generating graphics for Sheet: -nameofsheet-" with a loading bar, at the very bottom-left corner of the Revit window? (image below) What is it doing?
It seems to me like it's more time consuming than simply accessing the sheets in the document (as it does for, for example, model elements, etc.)
Is it possible to avoid this and just get the info I need without "generating graphics"?
Thanks!
Andrea
Solved! Go to Solution.
Solved by jeremytammik. Go to Solution.
Can you share the code that is looping through the sheets?
Sure! Sorry I didn't put it here straight away!
// Sheets foreach (Element sheetElement in CollectSheetElements(currentDoc)) { ViewSheet sheet = sheetElement as ViewSheet; // Get titleblock FilteredElementCollector titleblock = new FilteredElementCollector(currentDoc, sheet.Id) .OfCategory(BuiltInCategory.OST_TitleBlocks); Element titleblockElement = titleblock.First(); // Get id of titlebloc type int? titleblockDbId = GetTypeIdDb(currentDoc, titleblockElement, types); RevitSheet revitSheet = new RevitSheet( file.FileId, sheet.ViewName, sheet.SheetNumber, GetParameterValueByName(sheetElement, "Approved By"), GetParameterValueByName(sheetElement, "Designed By"), GetParameterValueByName(sheetElement, "Checked By"), GetParameterValueByName(sheetElement, "Drawn By"), GetParameterValueByName(sheetElement, "Sheet Issue Date"), titleblockDbId); // Write sheets connection.Execute(DbSqlCommands.sheetsSql, revitSheet, transaction: transaction); }
where RevitSheet is a custom class that I created to write into a db. And there a few other custom method but I don't think they would matter here (but happy to copy them too if they do)
And this is how I collect the sheets:
internal static List<Element> CollectSheetElements(Document doc) { FilteredElementCollector views = new FilteredElementCollector(doc) .OfCategory(BuiltInCategory.OST_Sheets); return views.ToElements().ToList(); }
Thanks,
Andrea
First of all, a small comment on enhancing performance:
You can completely eliminate two expensive method calls from CollectSheetElements; both ToElements and ToList serve no purpose whatsoever. Change the return type from List<Element> to IEnumerable<Element> and eliminate those two calls. That will save you time and space, twice over.
Unfortunately, I have no idea what could be causing the graphics regeneration.
I'll ask the development team about that for you.
Cheers,
Jeremy
Thank you so much for your advice @jeremytammik ! That's really appreciated!
In regards to the regeneration: Could it be due to the bit of code where I'm taking the titleblock assigned to the sheet?
new FilteredElementCollector(currentDoc, sheet.Id).OfCategory(BuiltInCategory.OST_TitleBlocks);
Where I do this? (it still wouldn't explain the regeneration of the graphics to me...)
Thank you for passing my question on to the dev team.
Please let me know if they can figure out why.
Andrea
My initial reaction was 'no'...
However, maybe the sheet is indeed regenerated to determine which elements to return for that collector, since the view id is specified... ?
I asked the devteam and hope they will be able to reply fast.
That was my same train of thought.
Yeah hopefully they will reply soon! That would help a lot as I'm really curious to understand what's going on there now!
Please let me know.
Thanks,
Andrea
Thank you Jeremy for following up!!
Now that's a great solution and it works great!
If I get all the titleblocks from the document and then take the one with the same OwnerViewId property as the Id of the sheet it doesn't generate the sheet!
snippet here:
FilteredElementCollector allTitleBlocks = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_TitleBlocks); foreach (Element sheetElement in CollectSheetElements(currentDoc)) { // Get sheet's titleblock Element titleblock = allTitleblocks.Where(t => t.OwnerViewId == sheet.Id).First(); }
Unfortunately that doesn't speed up the process as much as I thought, weirdly enough. The script was taking 6.77 minutes with the old method and takes now 6.32 minutes now.
Although, it needs to be considered that the program doesn't only taking into account the sheets.
Thanks again,
Andrea
... and you suppress the annoying regeneration message 🙂
You could improve this by implementing a dictionary inverting the relationship:
FilteredElementCollector allTitleBlocks = new FilteredElementCollector(doc) .OfCategory(BuiltInCategory.OST_TitleBlocks); // Map sheet to title block: Dictionary<ElementId, ElementId> map_sheet_to_title_block ... for each title block t in allTitleBlocks: map_sheet_to_title_block.Add( t.OwnerId, t.Id )
After that, use map_sheet_to_title_block(sheet.Id, t.Id) to get the title block.
No more need for a call to Where in each loop iteration.
Yeah that's actually a great idea!
Thanks for all the advice @jeremytammik !!
I'll use this same strategy for when I extract the parameters too! Should make it better too!
My pleasure entirely.
Yes.
Seven minutes is a long time.
You should definitely benchmark your entire add-in to discover what is taking so much time.
It could be built-in Revit operations. However, with obvious optimisation possibilities like that, you may be able to speed it up a lot.
Good luck!
Cheers,
Jeremy
Yes, I actually benchmarked the process and the thing that takes 80% of the processing time (5 min of the total 6 and a bit) is extracting all the instance parameters of the model elements...I guess it makes sense, a few thousands elements with 20/30 parameters each makes it a lot of parameters 😄
I'll probably write another question here on the forum at some point to see if anyone sees a faster way to do that.
Thanks again!
Andrea