Filtered element collector to get elements of category on view in docs

python

#1

Hi!

What I tried: I am trying to reteive all the walls that appear in a list of floorplans views, but I also want to get the walls from linked documents.

What I expeted: A list of list of walls in this format Docs>View>WallElement

What I got: An Emty lists and no errors! in the right format.

Comment: I am not all too familiar with the filter element collectors and mostly “Frankensteining” things toghether. Something must be happening during the collector because I get as many sublists as I have views. I guess nothing passes the filter and I don’t know why.

import System
import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager

doc = DocumentManager.Instance.CurrentDBDocument

cats = IN[0]
views = UnwrapElement(IN[1])
Doclist = IN[2]
Doclist.append(doc)

doc_elementlist = list()
for Docs in Doclist:
	elementlist = []
	for cat in cats:
		catlist = list()
		for view in views:
			collector = FilteredElementCollector(Docs)
			filter = ElementOwnerViewFilter(view.Id)
			bic = System.Enum.ToObject(BuiltInCategory, cat.Id)
			catlist.append(collector.WherePasses(filter).OfCategory(bic).ToElements())
		elementlist.append(catlist)
	doc_elementlist.append(elementlist)
OUT = doc_elementlist

I can assure you all of my documents have walls, the views are in the current doc.


#2

I don’t believe you can get elements from a linked model by using a view in the current document. The views need to come from the document used in the collector.

You might be able to modify the Data-Shapes node GetLinkedElement.InHostViewAndCategory to work with your process though. I believe the node filters out elements within the bounding region of the view. Just use that node alongside the filtered elements from your current document.


#3

You will have to get the linked elements. Try to use the “RevitLinkType”.

Here is a C# sample that I have used. The code should be very similar because this is mostly all Revit API.

   IList<Element> elems = collector
            .OfCategory(BuiltInCategory.OST_RvtLinks)
            .OfClass(typeof(RevitLinkType))
            .ToElements();

http://www.revitapidocs.com/2018.1/9888db7d-00d0-4fd7-a1a9-cdd1fb5fce16.htm?enumeration=RevitLinkType

Check the linked model if you have many models linked by

foreach(Element e in elems)
// cast element to RevitLinkType
RevitLinkType linkType = e as RevitLinkType;
            //loop over linked documents 
            foreach (Document linkedDoc in uiApp.Application.Documents)
            {
                //Check the linked model by name. 
                if (linkedDoc.Title.Equals(linkType.Name))
                {

#4

@Nick_Boyts You are right, the filtered element collector need to use a a view that is within it’s document.

@Mostafa_El_Ayoubi I also found the thread where GetLinkedElement.InHostViewAndCategory was born from:How to collect elements from links visible on a view in the host model? And modified it like so to get it to use lists documents. And changed the VERY SUBTLE “Elev” parameter call to “Elév.” because french. I just combine it with a Select.ByCategoryAndView to get the current document, then AddItemToFront with funny lacing.

As a side note, ElementOwnerViewFilter only considers 2d elements, wish explains my empty lists.

#Copyright (c) mostafa el ayoubi ,  2017
#Data-Shapes www.data-shapes.net , elayoubi.mostafa@gmail.com

import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import*
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument
import System
from System.Collections.Generic import *

clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import*
doc = DocumentManager.Instance.CurrentDBDocument

#Inputs
if isinstance(IN[2],list):
	categories = IN[2]
else:
	categories = [UnwrapElement(IN[2])]
linkdocs = IN[1]
if isinstance(IN[0],list):
	views = UnwrapElement(IN[0])
else:
	views = [UnwrapElement(IN[0])]

collector = []

#getting project base point elevation
basepointfilter = ElementCategoryFilter(BuiltInCategory.OST_ProjectBasePoint)
basepoint = FilteredElementCollector(doc).WherePasses(basepointfilter).ToElements()
bpelevation = [b.ParametersMap.get_Item('Elév.').AsDouble() for b in basepoint]

#Category filter
catfilter = []
for i in categories:
	catfilter.append(ElementCategoryFilter(System.Enum.ToObject(BuiltInCategory, int(str(i.Id)))))

catfilterlist = List[ElementFilter](catfilter)
filter = LogicalOrFilter(catfilterlist)

UIunit = Document.GetUnits(doc).GetFormatOptions(UnitType.UT_Length).DisplayUnits
level = []
for v in views:

	#creating a boundingbox for each view from it's crop box and view range
	bb = v.CropBox
	vr = v.GetViewRange()
	topclip = PlanViewPlane.TopClipPlane
	bottomclip = PlanViewPlane.BottomClipPlane
	cutclip = PlanViewPlane.CutPlane
	toplevel = (doc.GetElement(vr.GetLevelId(topclip)))
	topoffset = vr.GetOffset(topclip)
	cutlevel = (doc.GetElement(vr.GetLevelId(cutclip)))
	cutoffset = vr.GetOffset(cutclip)
	try:
		topZ = toplevel.Elevation + topoffset - bpelevation[0]
	except:
		topZ = cutlevel.Elevation + cutoffset - bpelevation[0]
	bottomlevel = (doc.GetElement(vr.GetLevelId(bottomclip)))
	bottomoffset = vr.GetOffset(bottomclip)
	try:
		bottomZ = bottomlevel.Elevation + bottomoffset - bpelevation[0]
	except :
		bottomZ = cutlevel.Elevation - bpelevation[0]
	min = bb.Min
	max = bb.Max
	newmin = XYZ(min.X,min.Y,bottomZ)
	newmax = XYZ(max.X,max.Y,topZ)
	ol = Outline(newmin,newmax)

	#combining boundingbox and category filters
	bbfilter = BoundingBoxIntersectsFilter(ol)
	andfilter = LogicalAndFilter(filter,bbfilter)

	#collecting elements
	collectordoc = []
	for linkdoc in linkdocs:
		collectordoc.append(FilteredElementCollector(linkdoc).WherePasses(andfilter).ToElements())
	collector.append(collectordoc)

OUT = collector

#5

I am trying to do something very similar, but with Rooms and only the current document. However, I too am getting an empty list when feeding it multiple views. I have tried to change the lacing, but that doesn’t help.


#6

The last post by @slepagetrudeau allowed me to work it out along with using @2 Levels for the Create Annotation Tag Node.