I trust it is possible to filter elements visible in a viewport, but it requires some calculations. The process involves:
- Getting the viewport outline – Retrieve the viewport's bounding box on the sheet.
- Projecting to model space – Convert the outline points to model coordinates using the viewport’s transform.
- Applying view range offsets – Adjust for top and bottom clipping to define a proper 3D selection box.
- Creating a bounding filter – Use the computed 3D outline to filter elements inside the viewport.
- Applying a tolerance buffer – This ensures elements exactly on the edges, like thick floors, are included.
I'm a bit confused about the OutLine class. Its constructor accepts minimum and maximum points, which makes it seem similar to of BoundingBoxXYZ class. I'm having trouble understanding the difference and why a BoundingBoxXYZIsInsideFitler requires an OutLine instead of a BoundingBoxXYZ. Even though the word "outline" typically, "at least for me" refers to a 2D shape, the OutLine class seems to be used in a 3D context here.

Here’s the final implementation:
public static XYZ ConvertToModelSpace(this XYZ pointOnSheet, Viewport viewPort)
{
var Doc = viewPort.Document;
var modelSpaceView = (View)Doc.GetElement(viewPort.ViewId);
var viewTransform = modelSpaceView.CropBox.Transform;
BoundingBoxUV modelSpaceOutline = modelSpaceView.Outline;
var cgModelSpaceUV = (modelSpaceOutline.Min + modelSpaceOutline.Max) / 2;
var cgModelSpace = new XYZ(cgModelSpaceUV.U, cgModelSpaceUV.V, 0);
Outline vportOutLine = viewPort.GetBoxOutline();
var cgVportOutline = (vportOutLine.MinimumPoint + vportOutLine.MaximumPoint) / 2;
var offset = cgVportOutline.Subtract(cgModelSpace);
int Scale = modelSpaceView.Scale;
return viewTransform.OfPoint((pointOnSheet - offset) * Scale);
}
var outline = viewPort.GetBoxOutline();
var p0 = outline.MinimumPoint.ConvertToModelSpace(viewPort);
var p1 = outline.MaximumPoint.ConvertToModelSpace(viewPort);
var view = viewPort.ViewId.GetElement<View>() as ViewPlan;
var range = view.GetViewRange();
var maxZ = range.GetOffset(PlanViewPlane.TopClipPlane);
var minZ = range.GetOffset(PlanViewPlane.ViewDepthPlane);
double tolerance = 2;
p0 = new XYZ(p0.X, p0.Y, minZ - tolerance);
p1 = new XYZ(p1.X, p1.Y, maxZ + tolerance);
outline = new Outline(p0, p1);
var bbxFilter = new BoundingBoxIsInsideFilter(outline);
var elements = new FilteredElementCollector(Doc, view.Id)
.WherePasses(bbxFilter)
.WhereElementIsNotElementType()
.Where(x => x.Category != null && x.Category.HasMaterialQuantities)
.Where(x => x.Category != null && x.Category.CategoryType != CategoryType.Internal)
.Where(x => x.Category != null && x.Category.CategoryType != CategoryType.AnalyticalModel);
List<ElementId> ids = elements.Select(o => o.Id).ToList();
UiDoc.Selection.SetElementIds(ids);
I have added more details of how this works in case any one likes the details.
Hope this helps.
Moustafa Khalil