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

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