Revit API provides a variety of ways to pick objects including whole elements and some visible geometry components such as edges and faces/surfaces.
They are wrapped in the class Autodesk.Revit.UI.Selection and the most useful and typical ones are PickObject, PickObjects and PickElementsByRectangle. There are some other obsolete ones as well such as PickOne and WindowSelect but people should not be interested in them anymore.
The PickObjects can prompt users to select some elements or geometry components, limit the selection to a special object type (ObjectType), filter objects under cursor based on some rules through an instance of the ISelectionFilter derivative, and even pre-select something.
It has five signatures:
PickObjects(ObjectType)
PickObjects(ObjectType, ISelectionFilter)
PickObjects(ObjectType, String)
PickObjects(ObjectType, ISelectionFilter, String)
PickObjects(ObjectType, ISelectionFilter, String, IList<(Of <(Reference>)>))
The two without String argument ones may be good for testing purposes as they save one input but it’s unlikely that some final code will use them in a commercial and professional application, needless to say, in localizable software products. All of the five require an ObjectType, which can restrict the selection to Nothing, Element, PointOnElement, Edge, or Face.
Thoughtful readers may wonder how to select something through picking either an Edge or a Face in a single PickObjects call. The answer is NO, not possible. If you do not believe, you can try something like ObjectType.Edge | ObjectType.Face for the first argument of the method. As can be imagined or not, an exception (more specifically, ArgumentOutOfRangeException) would be thrown out.
Another common feature all the signatures share is the return type IList<Reference>. It is a list of Reference instances and each of them includes necessary information for the picked object such as reference type, picked point (if applicable), and the underlying element.
Ok, now let’s focus on the fourth, most typical, signature of the PickObjects method.
If we’d like to pick some wall faces we can provide the ObjectType.Face to the first argument, an instance of the SelectionFilter as we introduced in earlier posts to the second, and any meaningful string in either language to the third.
The returned Reference will tell us what object has been picked by its ElementReferenceType property, which is ElementReferenceType.REFERENCE_TYPE_SURFACE in this case as can be imagined. The Element property will give us the underlying element in case some more information is needed or we’d like to operate on the whole element rather than its visible components.
If we’d like to pick some wall edges we can provide the ObjectType.Edge to the first argument, an instance of the same SelectionFilter as we introduced in earlier posts to the second, and any meaningful string in either language to the third. The returned Reference is ElementReferenceType.REFERENCE_TYPE_LINEAR in this case as somewhat can be imagined.
If we’d like to pick some walls through points on them, what shall we do?
Similar to the two cases we talked about above we can provide the ObjectType.PointOnElement to the first argument, an instance of the same SelectionFilter to the second, and any meaningful string in either language to the third.
However something different also happens this time both in the picking behavior and the returned Reference value. Wherever the cursor is hovering on a wall (e.g. on an edge or even a corner) a face/surface will be highlighted. This may not be something as can be easily imagined. The good part is at least the returned ReferenceType (ElementReferenceType.REFERENCE_TYPE_SURFACE) is consistent with the picking behavior. There is not such a thing like ElementReferenceType.REFERENCE_TYPE_POINT anyway.
By the way, it would not have changed the situation if the Point GeometryObject type were added to the AllowReference() method of our SelectionFilter:
if (refer.GeometryObject is Autodesk.Revit.DB.Point) return true;
The expected picked point can be retrieved back from the Reference.GlobalPoint property of the returned value though.
Now what about picking some whole walls? It is the simplest and the most popular case. We can provide the ObjectType.Element to the first argument, an instance of the same SelectionFilter which allows Wall elements to pass through to the second, and any meaningful string to the third.
The returned Reference will have type of ElementReferenceType.REFERENCE_TYPE_NONE as somehow can be expected.
Here are some code snippets to demonstrate these cases in detail:
public static IList<Reference> SelectWallsThroughPickingFaces(Selection selection)
{
IList<Reference> picked = selection.PickObjects(ObjectType.Face, new SelectionFilter1(), "Pick wall faces to select walls");
MessageBox.Show(string.Format("{0} objects have been picked back.", picked.Count));
return picked;
}
public static IList<Reference> SelectWallsThroughPickingEdges(Selection selection)
{
IList<Reference> picked = selection.PickObjects(ObjectType.Edge, new SelectionFilter1(), "Pick wall edges to select walls");
MessageBox.Show(string.Format("{0} objects have been picked back.", picked.Count));
return picked;
}
public static IList<Reference> SelectWallsThroughPickingPoints(Selection selection)
{
IList<Reference> picked = selection.PickObjects(ObjectType.PointOnElement, new SelectionFilter1(), "Pick wall points to select walls");
MessageBox.Show(string.Format("{0} objects have been picked back.", picked.Count));
return picked;
}
public static IList<Reference> SelectWallsThroughPickingWholeElements(Selection selection)
{
IList<Reference> picked = selection.PickObjects(ObjectType.Element, new SelectionFilter1(), "Pick whole elements to select walls");
MessageBox.Show(string.Format("{0} objects have been picked back.", picked.Count));
return picked;
}
The test calling code is also appended for convenience:
public Result Execute(ExternalCommandData cmdData, ref string msg, ElementSet elemSet)
{
_cachedCmdData = cmdData;
try
{
SelectWallsThroughPickingFaces(CachedUiApp.ActiveUIDocument.Selection);
SelectWallsThroughPickingEdges(CachedUiApp.ActiveUIDocument.Selection);
SelectWallsThroughPickingPoints(CachedUiApp.ActiveUIDocument.Selection);
SelectWallsThroughPickingWholeElements(CachedUiApp.ActiveUIDocument.Selection);
return Result.Succeeded;
}
catch (Exception ex)
{
msg = ex.ToString();
return Result.Failed;
}
}
Object Picker of RevitAddinWizard can help take care of all these cases regarding the PickObjects, its signatures excluding the two without string arguments, and every possible combination of these arguments.
Our Software http://netspiderstudio.com/Software.html
Support: mailto:support@netspiderstudio.com
Query: mailto:info@netspiderstudio.com
Blog: http://spiderinnet.typepad.com
More: http://netspiderstudio.com
Links to some related articles:
Object Picking of Revit API - PickObject And ObjectType
Object Picking of Revit API - PickObjects And ObjectType
Recent Comments