FilteredElementCollector - Unreferenced Sections Only

FilteredElementCollector - Unreferenced Sections Only

62BJW
Advocate Advocate
2,052 Views
10 Replies
Message 1 of 11

FilteredElementCollector - Unreferenced Sections Only

62BJW
Advocate
Advocate

I have a FilteredElementCollector for sections (ViewSection). Can it be modified to get only sections that are not referenced? Thanks

 

var secIds = new FilteredElementCollector(doc)
.OfClass(typeof(ViewSection))
.ToElementIds();
f.Refresh();
0 Likes
2,053 Views
10 Replies
Replies (10)
Message 2 of 11

recepagah12
Advocate
Advocate

I don't know what referenced section means but you can search Revit Lookup for this. If that means section view depend on another view you can check the dependent views of the element. Here is the code snippet.

This collector collects if section view has no dependent view.

var viewSections = new FilteredElementCollector(doc)
    .OfClass(typeof(ViewSection))
    .Cast<ViewSection>()
    .Where(q => q.GetDependentViewIds().Count == 0);

I hope this helps,

Recep.

0 Likes
Message 3 of 11

62BJW
Advocate
Advocate

Thanks for the reply. I may be using the wrong terminology. I'm trying to get Sections that are not on sheets.

0 Likes
Message 4 of 11

recepagah12
Advocate
Advocate

Sorry, I misunderstood your question. Here is a code snippet that shows which building section views didn't add to sheets. You can restrict to the specified sheet to as you wish. I tried myself this code in Visual Studio 2019 and Revit 2020 and it worked.

// Collect all building section views
var sectionViews = new FilteredElementCollector(doc) .OfClass(typeof(ViewSection)) .Cast<ViewSection>() // This filter restrict the filter for only building sections. // You can obtain parameter and value from Revit LookUp. .Where(q => q.get_Parameter(BuiltInParameter.ELEM_FAMILY_AND_TYPE_PARAM).AsValueString() == "Section: Building Section") .GetEnumerator(); // Collect all sheets var sheets = new FilteredElementCollector(doc) .OfClass(typeof(ViewSheet)) .Cast<ViewSheet>() .GetEnumerator(); while (sheets.MoveNext()) { var sheet = sheets.Current; foreach (var viewId in sheet.GetAllPlacedViews()) { var view = doc.GetElement(viewId) as View;
// Check if view is section view if (view.ViewType == ViewType.Section) { while (sectionViews.MoveNext()) { ViewSection sectionView = sectionViews.Current; // If views in sheet don't contain if (sectionView.Id != viewId) { TaskDialog.Show("Missing Section View", sectionView.Name + " isn't added"); }
// If sheet contains nothing if (viewId == null) TaskDialog.Show("Missing Section View", sectionView.Name + " isn't added"); } } } }

I hope this helps,

Recep.

0 Likes
Message 5 of 11

jeremytammik
Autodesk
Autodesk

Dear Bernie,

 

Thank you for your query, and many thanks to Recep for his very helpful answers.

 

I have a suggestion based on a slightly more abstract view of the task which may help implement a more optimised solution for both this and other purging tasks.

 

By the way, looking back at your original question: What is `f`, that you call `Refresh` on? I guess that does not matter?

 

I believe this can indeed be easily solved.

 

The trick is to find some characteristic feature to test on the ViewSection class that let us determine whether it is referenced or not, or how many references to it exist.

 

What is a reference to a section view, and where can it be determined?

 

Is it always a reference from a sheet view?

 

Can it always be determined by calling the ViewSheet GetAllPlacedViews method?

 

http://www.revitapidocs.com/2020/af2ee879-173d-df3a-9793-8d5750a17b49.htm

 

If so, then here is my suggestion:

 

The Revit API GetAllPlacedViews method defines a relationship mapping a ViewSheet to all views placed on it, including ViewSection objects.

 

This relationship can easily be inverted to map the ViewSection objects (or all placed views) to all ViewSheet objects referencing it.

 

I discussed a simple relationship inverter in one of the first blog posts, number 16, in 2008:

 

http://thebuildingcoder.typepad.com/blog/2008/10/relationship-in.html

 

It is maintained as part of The Building Coder samples, in the module CmdRelationshipInverter.cs.

 

Later, in 2009, The Building Coder also discussed the relationship between viewports and sheets:

 

http://thebuildingcoder.typepad.com/blog/2009/01/viewports-and-sheets.html

 

The discussion there and the command that it implements is too convoluted and gets into too much detail for me to understand fully right here and now. I am either too lazy, busy or obtuse. So, instead, I'll start again from scratch.

 

Implement map_sheet_to_placed_views like this:

 

  •   Dictionary<int, List<int>> map_sheet_to_placed_views
  •   For each sheet, call GetAllPlacedViews
  •   Add the integer values of the sheet and placed views element ids as key and value

 

To invert the relationship:

 

  •   Dictionary<int, List<int>> map_placed_view_to_sheets
  •   Iterate over all the placed sheet entries in the values in map_sheet_to_placed_views
  •   For each placed sheet, add its element id integer value as key to map_placed_view_to_sheets if it does not already exist, and the associated sheet int key to the associated list of int value

 

With that reverse relationship set up, you know that every placed view has an entry in map_placed_view_to_sheets pointing to the sheets it has been placed on.

 

An unplaced view has no such entry.

 

Therefore, you can simply add a post-processing step to the filtered element collector above to eliminate the placed views from the filter results and retain only unplaced views:

 

  var secIds = new FilteredElementCollector(doc)
    .OfClass(typeof(ViewSection))
    .ToElementIds()
    .Where<ElementId>( id => 
      !map_placed_view_to_sheets.ContainsKey(id.IntegerValue) );

 

One big advantage of this approach is that you know exactly what you are doing, and that each step is performant:

 

  • One single filtered element collector call to retrieve all the sheets and create map_sheet_to_placed_views
  • The relationship inversion, a pretty fast operation
  • One single filtered element collector call to retrieve all section views

 

I hope this helps.

 

Best regards,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 6 of 11

62BJW
Advocate
Advocate

Thanks for the reply Jeremy, The "f' that I'm refreshing is a progress dialog. Something so the user doesn't think it's stalled. I'm attempting to delete various kinds of user selected (checkBox) annotations from all views. Here's the Section portion of the code.

 

        // Sections
        void DeleteSections(Document doc)
        {
            ProcessingForm f = new ProcessingForm();
            f.lblProcessing.Text = "Deleting sections... ";
            f.Show();
            f.Refresh();

            var secIds = new FilteredElementCollector(doc)
            .OfClass(typeof(ViewSection))
            .ToElementIds();
            f.Refresh();
            foreach (var sec_id in secIds)
            {
                try
                {
                    doc.Delete(sec_id);
                    secCount++;
                }
                catch
                {
                    f.Refresh();
                    f.lblProcessing.Text = "Deleting sections... " + secCount.ToString() + " deleted.";
                    f.Refresh();
                }
            }
            f.Close();
        }
0 Likes
Message 7 of 11

jeremytammik
Autodesk
Autodesk

You can probably speed it up significantly by not deleting the sections one at a time, but all at once, in one single call to Delete, passing in the whole list of element ids.

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 8 of 11

jeremytammik
Autodesk
Autodesk

Looking forward to hearing how it goes with the filtered retrieval of unplaced section views!

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 9 of 11

62BJW
Advocate
Advocate

Hi Jeremy,

I'm getting some errors when I use the snipit you sent me. I've added two attachments. Thanks for the help!

 

        // Sections
        void DeleteSections(Document doc)
        {
            ProcessingForm f = new ProcessingForm();
            f.lblProcessing.Text = "Deleting sections... ";
            f.Show();
            f.Refresh();

            var secIds = new FilteredElementCollector(doc)
              .OfClass(typeof(ViewSection))
              .ToElementIds()
              .Where<ElementId>(id =>
              !map_placed_view_to_sheets.ContainsKey(id.IntegerValue));

            f.Refresh();
            foreach (var sec_id in secIds)
            {
                try
                {
                    doc.Delete(sec_id);
                    secCount++;
                }
                catch
                {
                    f.Refresh();
                    f.lblProcessing.Text = "Deleting sections... " + secCount.ToString() + " deleted.";
                    f.Refresh();
                }
            }
            f.Close();
        }

 

 

0 Likes
Message 10 of 11

jeremytammik
Autodesk
Autodesk

Dear Bernie,

 

Thank you for your update.

 

Yes, of course.

 

I provided instructions explaining how to:

 

  • Implement the dictionary map_sheet_to_placed_views by iterating over the sheets and collecting the results from calling GetAllPlacedViews on each of them
  • Invert the relationship to define and populate map_placed_view_to_sheets

 

I tried to explain exactly how to achieve that. The blog post on inverting a relationship explains the second step, and the first is really trivial.

 

If you have not implemented those two steps, these dictionaries will not exist.

 

Best regards,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 11 of 11

62BJW
Advocate
Advocate

Thanks Jeremy,

I'm not sure I understand how to do that but will investigate further. Thanks for pointing me in the right direction.

0 Likes