How to get only visible elements in active view

How to get only visible elements in active view

kimhjDGFZX
Contributor Contributor
725 Views
8 Replies
Message 1 of 9

How to get only visible elements in active view

kimhjDGFZX
Contributor
Contributor

Hello,

 

I’d like to know the best way to retrieve visible elements within the active view.

 

For example, when using a feature that displays elements inside a crop box, is there a method to get only those elements?

kimhjDGFZX_0-1737425077301.png

 

I already use the below method, but these return all elements in the current view.

VisibleInViewFilterWhereElementIsViewIndependent


Is there any alternative approach to get only the visible elements?
Looking forward to helps.

 

0 Likes
726 Views
8 Replies
Replies (8)
Message 2 of 9

scgq425
Advocate
Advocate

Hi @kimhjDGFZX :

if you want to filter element not contains hidden element , you can add this api function to  the code :

Element(id).IsHidden(view)

LanHui Xu 徐兰辉
Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.

Blog
LinkedIn
Revit/CAD Development | Steel Product Manager

EESignature

0 Likes
Message 3 of 9

kimhjDGFZX
Contributor
Contributor

Hello, @scgq425 

 

However, when I use the IsHidden() API, it includes elements outside the crop box.

For example, the gray element at the bottom left is included even though it is not visible. I expected the return value to be true because elements outside the crop box should be considered hidden.

Do you have any other thoughts or suggestions?

0 Likes
Message 4 of 9

scgq425
Advocate
Advocate

Hi @kimhjDGFZX :

not has  easy flow to solve this issue  , so if you want to get the inner crop-box elements , you can get the crop-box boundingBox , and use this api function to get the elements

BoundingBoxIsInsideFilter()

 

LanHui Xu 徐兰辉
Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.

Blog
LinkedIn
Revit/CAD Development | Steel Product Manager

EESignature

0 Likes
Message 5 of 9

jeremy_tammik
Alumni
Alumni

The Building Coder discussed this in 2017:

  

  

Basically, the same suggestion as above. Please let us know whether it helps, and if you can find an improvement or a better solution. Thank you.

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 6 of 9

kimhjDGFZX
Contributor
Contributor

Hello @scgq425 !

Sorry for the late reply and thank you for your suggesion.

When I use BoundingBoxIsInsideFilter(), it doesn't work for me that I wanted.

 

But thank you for your helps!

0 Likes
Message 7 of 9

kimhjDGFZX
Contributor
Contributor

Hello @jeremy_tammik !

 

Thank you for your help.

It was difficult to solve my problem with what you sent me.

 

I will continue to look for other ways.

 

But thank you for your helps!

 

0 Likes
Message 8 of 9

jeremy_tammik
Alumni
Alumni

Oh dear, sorry that it remains tricky. I asked Gemini for you, as described in my blog, and it replies:

   

Let's dive into efficiently retrieving visible elements in the active Revit view. You're right, VisibleInViewFilter and WhereElementIsViewIndependent alone aren't sufficient when crop regions or other visibility overrides are in play. They indicate potential visibility, not actual, rendered visibility within the current view's context. We need a more robust approach.

Here's a breakdown of the problem and a practical solution, combining best practices and leveraging the Revit API:

The Challenge:

The Revit API doesn't offer a single, direct method to get precisely what's visually rendered in the active view, especially considering crop regions, temporary view templates, and element overrides. VisibleInViewFilter only checks if an element could be visible in some view, not the current one with its specific settings. WhereElementIsViewIndependentfilters elements that are view-specific, but it doesn't filter based on visibility.

The Solution: Combining Filters and Bounding Box Intersections

The most reliable approach involves a combination of filtering and geometric checks. We'll use the view's crop box (or its equivalent if it's not rectangular) to define the visible region and then check if element bounding boxes intersect with this region. This approach is accurate and handles crop boxes effectively.

C#
 
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System.Collections.Generic;
using System.Linq;

public class VisibleElementsInView
{
    public static List<Element> GetVisibleElements(Document doc, View activeView)
    {
        List<Element> visibleElements = new List<Element>();

        // 1. Get the View's Crop Box (or its equivalent for non-rectangular crops)
        // For simplicity, assuming a rectangular crop box here.  Adapt as needed for more complex shapes.
        BoundingBoxXYZ cropBox = activeView.CropBox;
        XYZ minPt = cropBox.Min;
        XYZ maxPt = cropBox.Max;
        // Create an outline for the cropbox.
        Outline cropOutline = new Outline(minPt, maxPt);

        // 2. Collect all elements in the view (filtering can improve performance)
        // You can add more specific filters here if you know element categories you are interested in.
        FilteredElementCollector collector = new FilteredElementCollector(doc, activeView.Id);
        // Example: Filter for model elements only:
        collector.OfClass(typeof(FamilyInstance)); // Or other relevant classes

        // 3. Iterate and check for intersection
        foreach (Element element in collector)
        {
            // Get the element's bounding box (handles various element geometries)
            BoundingBoxXYZ elementBox = element.get_BoundingBox(activeView);

            if (elementBox != null) // Handle cases where bounding box is null
            {
                // Check for intersection with the crop box
                if (cropOutline.Intersects(new Outline(elementBox.Min, elementBox.Max)))
                {
                    visibleElements.Add(element);
                }

            }
        }

        return visibleElements;
    }



    // Example usage (in an external command or application):
    public void Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
    {
        Document doc = commandData.Application.ActiveUIDocument.Document;
        View activeView = doc.ActiveView;

        List<Element> visibleElements = GetVisibleElements(doc, activeView);

        TaskDialog.TaskDialog.Show("Visible Elements", $"Found {visibleElements.Count} visible elements.");


        // Do something with the visibleElements list...
    }
}

Explanation and Key Improvements:

  1. Crop Box Retrieval: We retrieve the CropBox of the active view. For non-rectangular crop regions, you'll need to get the CurveLoop representing the crop boundary and use more advanced geometric intersection methods.

  2. Efficient Element Collection: The FilteredElementCollector with the activeView.Id is crucial. This limits the initial collection to elements in the view, significantly improving performance compared to collecting all elements in the model. You can further refine this collector with additional filters (e.g., OfClass, OfCategory) to target specific element types for even better performance.

  3. Bounding Box Intersection: The core logic uses Outline.Intersects. This checks if the element's bounding box intersects with the view's crop box. This is a robust way to determine visibility within the cropped region.

  4. Null Bounding Box Handling: The code now includes a check for elementBox != null. Some elements (like annotation elements far from the view) might have null bounding boxes. Handling this prevents exceptions.

  5. Example Usage: The provided Execute method demonstrates how to use the GetVisibleElements function within a Revit command.

Further Considerations:

  • Performance: For extremely large models, you might consider spatial partitioning techniques (e.g., using the SpatialElement classes) to further optimize the intersection checks.

  • Non-Rectangular Crops: For complex crop shapes, you'll need to work with the CurveLoop of the crop region and implement more sophisticated geometric intersection tests (e.g., using the XYZ.DistanceTo method or other geometric utilities).

  • Temporary View Modes: Be aware that temporary view modes (like Reveal Hidden Elements) can affect visibility. You might need to adjust your logic based on the current view's temporary view mode if your add-in needs to handle these cases.

This approach provides a practical and reliable way to get truly visible elements in the active Revit view, addressing the limitations of simpler visibility filters. Remember to adapt the crop region handling for non-rectangular shapes if needed. Let me know if you have any other questions!

  

I hope that this explanation can prove useful in your further research. Please let us know how it goes. Thank you and good luck! 

   

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 9 of 9

ctm_mka
Collaborator
Collaborator

as Jeremy's code suggests, perhaps using the active view is what your want, you don't even need the bounding box, something like this:

List<Element> somecollection = new FilteredElementCollector(_doc, _uidoc.ActiveView.Id).OfCategory(BuiltInCategory.OST_StructuralColumns)
                            .WherePasses(new StructuralMaterialTypeFilter(StructuralMaterialType.Steel))
                            .WhereElementIsNotElementType().ToList();

 

This example grabs all the Structural Columns in the Active View, that are defined as steel.

0 Likes