Many of our partners and API users have often wondering how we can possibly make use of the Revit API to prompt users to pick 3D points. As all who have worked with Revit API are aware, the Selection.PickPoint() is only limited to points on the active 2D workplane.
The solution to this is to set the work plane using the View.SketchPlane property and then use the Selection.PickPoint() method on that workplane. The code below shows how to set an active sketch plane for a view which allows us to select points in 3D.
using System;
using System.Collections.Generic;
using System.Text;
using Autodesk.Revit;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.ApplicationServices;
using System.Linq;
namespace Select3DPoint
{
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
public class Command : IExternalCommand
{
public Autodesk.Revit.UI.Result Execute(ExternalCommandData commandData,
ref string message, Autodesk.Revit.DB.ElementSet elements)
{
UIApplication uiapp = commandData.Application;
UIDocument uidoc = uiapp.ActiveUIDocument;
Application app = uiapp.Application;
Document doc = uidoc.Document;
XYZ point_in_3d;
if (SetWorkPlaneAndPickObject(uidoc, out point_in_3d))
{
TaskDialog.Show("3D Point Selected",
"3D point picked on the plane"
+ " defined by the selected face: "
+ "X: " + point_in_3d.X.ToString()
+ ", Y: " + point_in_3d.Y.ToString()
+ ", Z: " + point_in_3d.Z.ToString());
return Result.Succeeded;
}
else
{
message = "3D point selection failed";
return Result.Failed;
}
}
/// <summary>
/// Return a 3D point. First, the user is prompted
/// to pick a face on an element. This defines a
/// work plane, on which a second point can be
/// picked.
/// </summary>
public bool SetWorkPlaneAndPickObject(
UIDocument uidoc,
out XYZ point_in_3d)
{
point_in_3d = null;
Document doc = uidoc.Document;
Reference r = uidoc.Selection.PickObject(
Autodesk.Revit.UI.Selection.ObjectType.Face,
"Please select a planar face to define work plane");
Element e = doc.GetElement(r.ElementId);
if (null != e)
{
PlanarFace face = e.GetGeometryObjectFromReference(r)
as PlanarFace;
GeometryElement geoEle = e.get_Geometry(new Options());
Transform transform = null;
foreach (GeometryObject gObj in geoEle.Objects)
{
GeometryInstance gInst = gObj as GeometryInstance;
if (null != gInst)
transform = gInst.Transform;
}
if (face != null)
{
Plane plane = null;
if (null != transform)
{
plane = new Plane(transform.OfVector(face.Normal),
transform.OfPoint(face.Origin));
}
else
{
plane = new Plane(face.Normal, face.Origin);
}
Transaction t = new Transaction(doc);
t.Start("Temporarily set work plane"
+ " to pick point in 3D");
SketchPlane sp = doc.Create.NewSketchPlane(
plane);
uidoc.ActiveView.SketchPlane = sp;
uidoc.ActiveView.ShowActiveWorkPlane();
try
{
point_in_3d = uidoc.Selection.PickPoint(
"Please pick a point on the plane"
+ " defined by the selected face");
}
catch (OperationCanceledException)
{
}
t.RollBack();
}
}
return null != point_in_3d;
}
}
}