Revit API provides a variety of ways to pick objects including whole elements and a few visible geometry parts 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 PickObject can prompt users to select an element or geometry part, limit it to a special object type (ObjectType), and filter things under cursor through an instance of the ISelectionFilter derivative.
It has four signatures:
PickObject(ObjectType)
PickObject(ObjectType, ISelectionFilter)
PickObject(ObjectType, String)
PickObject(ObjectType, ISelectionFilter, String)
The two signatures without String arguments 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 them 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 PickObject 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 Reference. It 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 PickObject method.
If we’d like to pick a wall face 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 argument.
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 a wall edge 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 a wall through a point on it, 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 a whole wall? 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 Reference PickAWallFace(Selection selection)
{
Reference picked = selection.PickObject(ObjectType.Face, new SelectionFilter(), "Pick a wall face");
MessageBox.Show(string.Format("Reference: {0}\nElement: {1}",
picked.ElementReferenceType, picked.Element.GetType())); //ElementReferenceType.REFERENCE_TYPE_SURFACE
return picked;
}
public static Reference PickAWallEdge(Selection selection)
{
Reference picked = selection.PickObject(ObjectType.Edge, new SelectionFilter(), "Pick a wall edge");
MessageBox.Show(string.Format("Reference: {0}\nElement: {1}",
picked.ElementReferenceType, picked.Element.GetType())); //ElementReferenceType.REFERENCE_TYPE_LINEAR
return picked;
}
public static Reference PickAWallPoint(Selection selection)
{
Reference picked = selection.PickObject(ObjectType.PointOnElement, new SelectionFilter(), "Pick a wall point");
MessageBox.Show(string.Format("Reference: {0}\nElement: {1}",
picked.ElementReferenceType, picked.Element.GetType())); //ElementReferenceType.REFERENCE_TYPE_SURFACE
return picked;
}
public static Reference PickAWallElement(Selection selection)
{
Reference picked = selection.PickObject(ObjectType.Element, new SelectionFilter(), "Pick a wall");
MessageBox.Show(string.Format("Reference: {0}\nElement: {1}",
picked.ElementReferenceType, picked.Element.GetType())); //ElementReferenceType.REFERENCE_TYPE_NONE
return picked;
}
The test calling code is also appended for convenience:
public Result Execute(ExternalCommandData cmdData, ref string msg, ElementSet elemSet)
{
_cachedCmdData = cmdData;
try
{
PickAWallFace(CachedUiApp.ActiveUIDocument.Selection);
PickAWallEdge(CachedUiApp.ActiveUIDocument.Selection);
PickAWallPoint(CachedUiApp.ActiveUIDocument.Selection);
PickAWallElement(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 PickObject and many more.
Our Software http://netspiderstudio.com/Software.html
Support: mailto:[email protected]
Query: mailto:[email protected]
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