原文链接:
Picking 3D points using Revit API
作为 Revit 二次开发人员,我们很熟悉如何使用 Selection.PickPoint() 在二维平面上选取一个点。由于 Revit API 并不直接支持在三维坐标系中选取一个点,我们需要采用稍微复杂一点儿的方法来实现:
1. 首先借助 View.SketchPlane 属性设置当前工作平面;
2. 然后使用 Selection.PickPoint() 在当前工作平面上选取点
代码如下:
作为 Revit 二次开发人员,我们很熟悉如何使用 Selection.PickPoint() 在二维平面上选取一个点。由于 Revit API 并不直接支持在三维坐标系中选取一个点,我们需要采用稍微复杂一点儿的方法来实现:
1. 首先借助 View.SketchPlane 属性设置当前工作平面;
2. 然后使用 Selection.PickPoint() 在当前工作平面上选取点
代码如下:
[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>
/// 返回一个三维坐标系中的点
// 用户首先被要求选取某个元素的一个面(工作平面),然后用户在这个面上选取一个点
/// </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;
// 译者注:这段代码应该是基于 Revit 2012。在 Revit 2013 中,geoEle 本身就实现了 IEnumerable 接口,所以直接使用 geoEle 遍历即可
foreach (GeometryObject gObj in geoEle.Objects)
{
GeometryInstance gInst = gObj as GeometryInstance;
if (null != gInst)
{
transform = gInst.Transform;
}
}
if (face != null)
{
Plane plane = null;
// 译者注:这个 transform 很关键。它是表示元素自身的坐标系和当前文档的坐标系是否有差异。
// 因为面的法线向量和面的原点的值都是基于元素自身的坐标系的。如果元素自身的坐标系和当前文档的坐标系有差异,则我们必须使用
// 坐标系差异(transform)来将面的法线向量和面的原点的值转换成基于当前文档坐标系的值。
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)
{
}
// 译者注:回滚事务意味着之前创建的草图平面(SketchPlane)也自动被删除了
t.RollBack();
}
}
return null != point_in_3d;
}