Building Coder(Revit 二次開發) - 創建與牆體平行的剖視圖

原文鏈接:Create Section View Parallel to Wall

先插兩句題外話,在建的全世界最高最綠色的建築“上海中心”(Shanghai Tower)中大量使用了 Autodesk BIM 解決方案。


譯者注:我旁聽了上海中心的負責人在去年的北京AU大師會上做的關於 Autodesk BIM 在上海中心設計和建造中應用的主題演講。會後我向他問了些 Revit 具體的使用情況。上海中心前期的設計多數還是用AutoCAD和犀牛等傳統工具完成的。Revit 更多得是在整體方案設計階段體現出它的數據一致性優勢。估計他們那時候使用的是 Revit 2010。相信如果使用 Revit 2013 的話,更多的工作將會被直接拿到 Revit 中完成了。今年的AU大師會在上海,希望能聽到更多關於 Revit 實際應用的介紹。另外我也會和東南大學的一位教授共同做“基於BIM技術的工業化住宅產業聯盟數字設計與管理平臺開發”的報告。


回到今天的主題:如何創建一個與牆體平行的剖視圖?實際上基本要點可以在 SDK 例程 CreateViewSection 中找到。而且我的幾篇博客也多次討論過相關問題:
1. section view creation
2. elevation and section views
3. crop a 3D view to a room

當然上面這些例子都是使用 Autodesk.Revit.Creation.Document.NewViewSection() 方法。Revit 2013 已經使用 ViewSection.CreateSection() 取代了 Document.NewViewSection()。目前我只有一篇博文structural plan view 中使用了這個最新的靜態方法。爲了彌補這個不足,我新創建了一個外部命令 CreateWallSectionView 來展示 ViewSection.CreateSection() 的詳細用法。

1. 使用牆體的 Location Line 作爲幾何信息源(決定了牆體的方向、長度)
2. 通過牆體的 BoundingBox 獲取牆高
3. 通過牆體類型的 Width 屬性獲取牆體厚度
4. 剖視圖的線性轉換(Transform)使用牆體方向
5. 全局座標系的Z軸方向作爲剖視圖的上方向


譯者注:剖視圖中座標系和 Revit 模型座標系是不一樣的。以與牆體平行的剖視圖爲例:X方向是牆體的水平方向;Y方向是牆體的垂直方向(即Revit模型座標系中的Z軸方向);Z方向是與牆面垂直的方向。


	[Transaction( TransactionMode.Manual )]
	public class Command : IExternalCommand
	{
		public Result Execute( ExternalCommandData commandData, ref string message, ElementSet elements )
		{
			UIApplication uiapp = commandData.Application;
			UIDocument uidoc = uiapp.ActiveUIDocument;
			Document doc = uidoc.Document;

			// 獲取選中牆體
			Selection sel = uidoc.Selection;
			SelElementSet set = sel.Elements;


			Wall wall = null;
			if( 1 == set.Size )
			{
				foreach( Element e in set )
				{
					wall = e as Wall;
				}
			}
			if( null == wall )
			{
				message = "Please select exactly one wall element.";
				return Result.Failed;
			}

			// 確認是直線牆
			LocationCurve lc = wall.Location as LocationCurve;
			Line line = lc.Curve as Line;
			if( null == line )
			{
				message = "Unable to retrieve wall location line.";
				return Result.Failed;
			}

			// 獲取視圖類型對象
			ViewFamilyType vft = new FilteredElementCollector( doc )
				.OfClass( typeof( ViewFamilyType ) )
				.Cast<ViewFamilyType>()
				.FirstOrDefault<ViewFamilyType>( x => ViewFamily.Section == x.ViewFamily );

			// 計算視圖區域

			XYZ p = line.get_EndPoint( 0 );
			XYZ q = line.get_EndPoint( 1 );
			XYZ v = q - p;

			BoundingBoxXYZ bb = wall.get_BoundingBox( null );
			double minZ = bb.Min.Z;
			double maxZ = bb.Max.Z;

			double w = v.GetLength();
			double h = maxZ - minZ;
			double d = wall.WallType.Width;
			double offset = 0.1 * w;

			XYZ min = new XYZ( -w, minZ - offset, -offset );
			XYZ max = new XYZ( w, maxZ + offset, 0 );

			XYZ midpoint = p + 0.5 * v;
			XYZ walldir = v.Normalize();
			XYZ up = XYZ.BasisZ;
			XYZ viewdir = walldir.CrossProduct( up );

			Transform t = Transform.Identity;
			t.Origin = midpoint;
			t.BasisX = walldir;
			t.BasisY = up;
			t.BasisZ = viewdir;

			BoundingBoxXYZ sectionBox = new BoundingBoxXYZ();
			sectionBox.Transform = t;
			sectionBox.Min = min;
			sectionBox.Max = max;

			// 創建牆體剖視圖
			using( Transaction tx = new Transaction( doc ) )
			{
				tx.Start( "Create Wall Section View" );
				ViewSection.CreateSection( doc, vft.Id, sectionBox );
				tx.Commit();
			}
			return Result.Succeeded;
		}
	}
Three wall sections    Wall section view

問題


上面的代碼創建的虛線部分與牆體位置線重合了。我希望剖視圖區域邊界對稱地位於牆體兩側。


Dotted line in wall center

Jeremy


剖視圖區域邊界的虛線部分的位置是由這兩行代碼確定的:

	XYZ min = new XYZ( -w, minZ - offset, -offset );
	XYZ max = new XYZ( w, maxZ + offset, 0 );

你只要將 max 點的座標做如下修改就可以滿足要求:

	XYZ min = new XYZ( -w, minZ - offset, -offset );
	XYZ max = new XYZ( w, maxZ + offset, offset );


Dotted line offset from wall center

問題

我如何創建與牆體垂直(而不是平行)且位於牆體中心點的剖視圖?

Jeremy

只要對上面的代碼做些調整就可以了。不過有一個值得注意的地方時:我們可以利用 ComputeDerivatives() 方法來獲取與牆體位置線的正切線和牆體的中心點,而不用通過對牆體位置線的兩個端點進行計算來獲取。這種方案還適用於非直線牆體。

以下是 GetSectionViewPerpendiculatToWall() 方法的代碼。它返回一個與指定牆體的位置線垂直的,且位於指定牆體中心點的剖視圖區域。

	BoundingBoxXYZ GetSectionViewPerpendiculatToWall( Wall wall )
	{
		LocationCurve lc = wall.Location as LocationCurve;

		// 使用 0.5 和 "true" 保證 Transform 的原點在牆體中心點且向量是規範化的。

		Transform curveTransform = lc.Curve.ComputeDerivatives( 0.5, true );

		// Transform 包含了位置線的中心點和正切線,這樣我們就能獲取其位於 XY 平面的法線了。

		XYZ origin = curveTransform.Origin;
		XYZ viewdir = curveTransform.BasisX.Normalize();
		XYZ up = XYZ.BasisZ;
		XYZ right = up.CrossProduct( viewdir );

		// 設置視圖 Transform,假設牆體是垂直方向的。對於非垂直方向牆體(例如:有斜坡的地板),我們需要其表面的法線

		Transform transform = Transform.Identity;
		transform.Origin = origin;
		transform.BasisX = right;
		transform.BasisY = up;
		transform.BasisZ = viewdir;

		BoundingBoxXYZ sectionBox = new BoundingBoxXYZ();
		sectionBox.Transform = transform;

		// Min & Max X 值定義位於牆體兩側的剖線長度;
		// Max Y 是剖視區域的高度;
		// Max Z (5) 是遠端剪裁偏移

		double d = wall.WallType.Width;
		BoundingBoxXYZ bb = wall.get_BoundingBox( null );
		double minZ = bb.Min.Z;
		double maxZ = bb.Max.Z;
		double h = maxZ - minZ;

		sectionBox.Min = new XYZ( -2 * d, -1, 0 );
		sectionBox.Max = new XYZ( 2 * d, h + 1, 5 );

		return sectionBox;
	}
Section view perpendicular to wall

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