Filter Element from Linked Model only if visible in active view

It’s seem related to the Element binding process
2 ways to solve:

  • use Dynamo Player
  • close and re-open the dyn file in Dynamo UI

see here

1 Like

I’ve tried your script on section, but it doesn’t work:

Hi @PiotrB

The code work only for FloorPlan, I’ll look when I have a little more time, but you can get inspiration from this code

Here an updated code for ViewPlans and SectionViews

Python Code (compatible all engines)
Edit 25/04/2024 : code updated → add input list view

import clr
import sys
import System
from System.Collections.Generic import List
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.GeometryConversion)

def gen_PairPts(*args):
    """generator for point pair loop
    """
    for idx, pt in enumerate(args):
        try: yield pt, args[idx + 1]
        except : yield pt, args[0]

def solid_fromBBX(bbox):
    pt0 = XYZ( bbox.Min.X, bbox.Min.Y, bbox.Min.Z )
    pt1 = XYZ( bbox.Max.X, bbox.Min.Y, bbox.Min.Z )
    pt2 = XYZ( bbox.Max.X, bbox.Max.Y, bbox.Min.Z )
    pt3 = XYZ( bbox.Min.X, bbox.Max.Y, bbox.Min.Z )
    #create generator
    pairPts = gen_PairPts(pt0, pt1, pt2, pt3) 
    #Create loop, still in BBox coords
    edges = List[Curve]()
    for pt1, pt2 in pairPts:
        edges.Add(Line.CreateBound( pt1, pt2 ))

    height = bbox.Max.Z - bbox.Min.Z
    baseLoop = CurveLoop.Create( edges )
    loopList = List[CurveLoop]()
    loopList.Add( baseLoop )
    preTransformBox = GeometryCreationUtilities.CreateExtrusionGeometry( loopList, XYZ.BasisZ, height )
    transformBox = SolidUtils.CreateTransformed( preTransformBox, bbox.Transform )
    return transformBox

def toList(x):
    if isinstance(x, (list, dict)) or \
            (hasattr(x, "GetType") and x.GetType().GetInterface("ICollection") is not None):
        return x
    else : return [x]
    
lst_View = toList(UnwrapElement(IN[0]))
catList = toList(UnwrapElement(IN[1]))
catBiplst = [ System.Enum.ToObject(BuiltInCategory, int(x.Id.ToString()) ) for x in catList]
linkInstances = FilteredElementCollector(doc).OfClass(DB.RevitLinkInstance)
out = []

for view_ in lst_View:
    temp = []
    if view_.ViewType  == ViewType.Section:
        for lnkInstance in linkInstances:
            lnk_doc = lnkInstance.GetLinkDocument()
            transf = lnkInstance.GetTotalTransform()
            bbxView = view_.CropBox 
            solidbbx = solid_fromBBX(bbxView)
            # apply link instance transform and create Filters (Solid + Categories)
            solidbbx = DB.SolidUtils.CreateTransformed(solidbbx, transf.Inverse)
            filterSolid = ElementIntersectsSolidFilter(solidbbx)
            cats = List[BuiltInCategory](catBiplst)
            filtercat = ElementMulticategoryFilter(cats)
            elemIntersect = FilteredElementCollector(lnk_doc).WherePasses(filterSolid).WherePasses(filtercat).WhereElementIsNotElementType().ToElements()
            # FOR DEBUG
            #out.append([lnkInstance.Name, elemIntersect, solidbbx.ToProtoType()])
            temp.append([lnkInstance.Name, elemIntersect])
            
        
    elif view_.ViewType in [ViewType.CeilingPlan, ViewType.FloorPlan]:
        #get bootom and top Elevation of active viewrange 
        viewRange = view_.GetViewRange()
        topClipPlaneId = viewRange.GetLevelId(PlanViewPlane.TopClipPlane) 
        topClipPlane = doc.GetElement(topClipPlaneId)
        topOffset = viewRange.GetOffset(PlanViewPlane.TopClipPlane)
        
        bttmClipPlaneId = viewRange.GetLevelId(PlanViewPlane.BottomClipPlane) 
        bttmClipPlane = doc.GetElement(bttmClipPlaneId)
        bttmOffset = viewRange.GetOffset(PlanViewPlane.BottomClipPlane)
        
        for lnkInstance in linkInstances:
            lnk_doc = lnkInstance.GetLinkDocument()
            transf = lnkInstance.GetTotalTransform()
            # get min and max from active ViewRange
            bbxActView = view_.CropBox 
            bbxActView.Min = XYZ(bbxActView.Min.X, bbxActView.Min.Y, bttmClipPlane.ProjectElevation + bttmOffset)
            bbxActView.Max = XYZ(bbxActView.Max.X, bbxActView.Max.Y, topClipPlane.ProjectElevation + topOffset)
            bbxActView.Transform = transf.Inverse
            # create Solid Filter
            solidbbx = solid_fromBBX(bbxActView)
            filterSolid = ElementIntersectsSolidFilter(solidbbx)
            # create categories filter
            cats = List[BuiltInCategory](catBiplst)
            filtercat = ElementMulticategoryFilter(cats)
            elemIntersect = FilteredElementCollector(lnk_doc).WherePasses(filterSolid).WherePasses(filtercat).WhereElementIsNotElementType().ToElements()
            # FOR DEBUG
            #out.append([lnkInstance.Name, elemIntersect, solidbbx.ToProtoType(), bbxActView.Min.ToPoint(), bbxActView.Max.ToPoint()])
            temp.append([lnkInstance.Name, elemIntersect])
    out.append([view_, temp])
OUT = out
3 Likes

Hey, your Python code works for a single view. When it got a list o views there is an error:
image

You’ll need to append a loop into the code. something like for view in views: and then offset the rest of the actions in that section below it.

2 Likes

code upaded in previous post

1 Like

The script works well on some view, but on some there is an error

@PiotrB

try to implement an Exception Handling with try except to identify the view cause error and check the view limits

I’ve checked that the issue is because of linked but not loaded Revit files, but don’t know how to fix the issue.

If the file are not loaded you cannot access the stuff therein. Force the reload before you start.

I don’t want to access elements in not loaded links, there are some other linked models loaded that I’d like to access. I meant the python code doesn’t work is there are any not loaded links.

Right - the way things are structured you cannot access things in link B if link A isn’t loaded. So ensure that links A to Z are loaded before you start accessing things in link B.

Alternatively you’ll have to find an alternative way to structure the Python above to pass over links which aren’t loaded without throwing the error.