Filter PointOnElement with ISelectionFilter

Background: Trying to select a surface of a wall in a linked model. I used some python code from a packaged node by Dimitar Venkov and began modifying it to work with how I wanted it to work.

Inputs: IN(0) is a Link Instance

Current result: nothing is able to be selected, If I remove the ‘selection_filter’ from the PickObject I can pick a point on any object, not just those in the linked document.

Desired Outcome: Be able to select a point (or face) on a wall in the instance link and nothing else (don’t want to be able to pick items in the main document by accident). I am not the only one who uses these codes so I want to make it very user-friendly.

Thanks for any help you can give!

Current Code:

import clr

clr.AddReference("RevitAPIUI")
from  Autodesk.Revit.UI import *
from  Autodesk.Revit.UI.Selection import *

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument
uidoc=DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

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

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import RevitLinkInstance, FamilyInstance


def output1(x):
	if len(x) == 1: return x[0]
	else : return x


sel1 = uidoc.Selection
ot2 = ObjectType.PointOnElement
link1 = UnwrapElement(IN[0])
linkDoc = link1.GetLinkDocument()
class MySelectionFilter(ISelectionFilter):
	def __init__(self):
		pass
	def AllowReference(self, element):
		if Reference.ElementReferenceType.Equals("REFERENCE_TYPE_FOREIGN"):
			return True
		else:
			return False
	def AllowReference(self, element):
		return False
selection_filter = MySelectionFilter()
tf1 = link1.GetTotalTransform()
face_ref = sel1.PickObject(ot2,selection_filter,"Pick a face.")
el1 = linkDoc.GetElement(face_ref.LinkedElementId)
face_ref2 = face_ref.CreateReferenceInLink()
sf0 = el1.GetGeometryObjectFromReference(face_ref2)
if isinstance(el1, FamilyInstance):
	tf1 = el1.GetTotalTransform()
sf1 = sf0.Convert(face_ref2, tf1.ToCoordinateSystem(True) )
for s in sf1:	
	s.Tags.AddTag("RevitFaceReference", face_ref)
OUT = output1(sf1), face_ref.GlobalPoint.ToPoint(True)

AllowReference method seems to be stated twice in the MySelectionFilter class for some reason. Classes inheriting ISelectionFilter must have two methods, AllowElement() and AllowReference() as documented here…

The ISelectionFilter’s purpose is to customise the filtering of the user selection, within each of the interfaces methods, you can add your own conditional logic. For example, if you want to only filter wall elements, then get the category of the Element being passed into AllowElement(Element element) method and return true if it is of the BuiltInCategory OST_WALLS. AllowReference() should return true if reference type is REFERENCE_TYPE_FOREIGN.

2 Likes

Thank you for your response. I’m new to python coding so learning by cannibalizing things from online and other codes. Based on your response, I adjusted the ISelectionFilter to the below for testing purpose but it’s still not letting me select the PointOnElement.

Updated Code with true on both returns for testing:
image

View of elevation code is running on (mouse is showing with the cross through it, unable to select any objects):
image

Couple things I have checked:

  1. The wall is definitely a wall type
  2. There is only one linked model so there is definitely no conflict with a different document/linked instance.
  3. I tried category “OST_WALLS, OST_Walls, Walls, and WALLS”

Hi,
a solution without checking the type of reference of the linked element

import clr
import sys
import System
clr.AddReference("RevitAPIUI")
from  Autodesk.Revit.UI import *
from  Autodesk.Revit.UI.Selection import *

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument
uidoc=DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

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

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import RevitLinkInstance, FamilyInstance


class CustomLinkSelection(ISelectionFilter):
	def  AllowElement(self, e):
		return True		

	def	AllowReference(self, refer, point):
		elemSelected = doc.GetElement(refer)
		if isinstance(elemSelected, RevitLinkInstance):
			return True	
		else:
			return False	
TaskDialog.Show("Selection", "Pick a Linked Face")
face_ref = uidoc.Selection.PickObject(ObjectType.PointOnElement,  CustomLinkSelection(), "Pick a Linked Face")
OUT = face_ref.GlobalPoint.ToPoint()

Note:
AllowReference method has 2 parameters

1 Like

This is great! is there any way to add the wall type to the filter as well? This already has a significant benefit but that would be the cherry on top.

Thanks!

Disregard, I solved it with this:

Thanks for the help all.

image

1 Like