AEC DevBlog(Revit 二次開發)- 使用 Revit API 選取三維點

原文鏈接:Picking 3D points using Revit API

作爲 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;
	}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章