Select all "UI visible" instances

Select all "UI visible" instances

floretti
Advocate Advocate
1,209 Views
8 Replies
Message 1 of 9

Select all "UI visible" instances

floretti
Advocate
Advocate

One of my users came up with an interesting question of whether or not it's possible to create a "Select All Instances > Visible in View" command taking into consideration the view's zoom level, meaning that everything outside the user's field of view is "not visible" and it wouldn't be part of the selection.

 

I've tried to find references in the API and online articles on the below topics and ran some UI tests and compared values via the Revit Lookup but no success.

  • Active view zoom level
  • Active view window size
  • Bounding boxes XYZ and UV and whether they change under different zoom levels
0 Likes
Accepted solutions (1)
1,210 Views
8 Replies
Replies (8)
Message 2 of 9

jeremy_tammik
Alumni
Alumni

Well, the first thing to try out is the filtered element collector taking a view element id:

  

  

The description says, Constructs a new FilteredElementCollector that will search and filter the visible elements in a view, which exactly matches your query. I would be surprised if the two exactly matching descriptions really mean exactly the same thing, but who knows, you may be in luck. 

  

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

floretti
Advocate
Advocate

Thanks, Jeremy. Unfortunately that overload of the FilteredElementCollector doesn't do what I'm after. The definition of "visible" to the API is different to the definition of what a user considers visible. The example below shows what I mean.

 

View B shows 8x wall elements. If I decrease the size of a view/window or simply zoom in or pan I won't be able to see all the 8x walls anymore like shown on View A. Regardless of whether or not I use the FilteredElementCollector and pass the view Id as a 2nd parameter or use the UI command Select All Instances > Visible in View, Revit will select all 8x wall instances.

 

floretti_0-1725258558909.png

 

0 Likes
Message 4 of 9

jeremy_tammik
Alumni
Alumni

Yup, that is what I thought. Here is an article on retrieving elements visible in view that might help:

  

  

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

floretti
Advocate
Advocate

Thanks again, Jeremy. I just tested that approach and these are the results.

 

This is View A showing all 8x wall instances and its ViewPlan.CropBox values underneath as recommended by the article.

floretti_0-1725260516091.png

 

I then panned across View A so only 4x wall instances are shown in the UI and again the ViewPlan.CropBox values underneath.

floretti_1-1725260576416.png

 

You probably noticed that the values didn't change and based on that I'm not expecting the outcome to be different if I turn this into code. I noticed that the API has two boolean properties to indicate whether the CropBox is either active and visible and you can see that in my case neither of them are true. Based on that, my assumption is that the recommended approach in the article you shared can only work via the cropbox use and not by zooming in/out and panning across a view.

floretti_2-1725260796000.png

 

0 Likes
Message 6 of 9

jeremy_tammik
Alumni
Alumni
Accepted solution

Yes, tricky. Here are two specific solutions for other situations:

  

  

In your case, maybe the UIView can help:

  

  

The View element is part of the document and lives in the database. It maybe does not know how it is currently being "looked at". The UIView may know that and provides the current zoom corners from which you can determine wihether an element is currently within them or not. However, for non-planar views, you will have some intersting calculations to perform.

  

I used the UIView to implement a tooltip that detects which elements are visible under the cursor:

  

  

Oh, and it also uses the ReferenceIntersector, also used by one of the solutions I pointed out above.

  

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

floretti
Advocate
Advocate

Amazing, thanks Jeremy. It's end of shift here in Australia but I'll check those out tomorrow as soon as I can.

0 Likes
Message 8 of 9

floretti
Advocate
Advocate
Amazing, thanks Jeremy. The GetZoomCorners() method is exactly what I need. Much appreciated. 😊😊😊
0 Likes
Message 9 of 9

floretti
Advocate
Advocate

Just giving back.  😉

 

Note this only works with family instances and it won't work with system families.

// Get active view's zoom
var zoomCorners = new List<XYZ>();

var openUIviews = uidoc.GetOpenUIViews();
foreach (var uiView in openUIviews)
{
	if(uiView.ViewId == doc.ActiveView.Id) zoomCorners = uiView.GetZoomCorners().ToList();
}

// Get selection and expand it
var selIds = uidoc.Selection.GetElementIds();
var finalSelectionIds = new List<ElementId>();

foreach (ElementId id in selIds)
{
	Outline viewExtents = new Outline(new XYZ(zoomCorners.First().X, zoomCorners.First().Y, -1000),
									  new XYZ(zoomCorners.Last().X, zoomCorners.Last().Y, 1000));
	var filter = new BoundingBoxIntersectsFilter(viewExtents);

	var famInst = doc.GetElement(id) as FamilyInstance;
	var allFamInst = new FilteredElementCollector(doc, doc.ActiveView.Id)
						.WherePasses(filter)
						.OfClass(typeof(FamilyInstance))
						.Cast<FamilyInstance>()
						.Where(x => x.Symbol.Family.Name.Equals(famInst.Symbol.Family.Name)) // family
						.Where(x => x.Name.Equals(famInst.Name)); // family type

	foreach (FamilyInstance item in allFamInst)
	{
		finalSelectionIds.Add(item.Id);
	}
}

uidoc.Selection.SetElementIds(finalSelectionIds);

 

0 Likes