Building Coder(Revit 二次开发)- 关于楼板边界的重新思考

原文链接: Slab Boundary Revisited

问题

如何使用 Revit API 获取楼板边界?


Jeremy

我2008年时就实现了一个名为 CmdSlabBoundary 的外部命令用于获取楼板边界。这个命令识别一块楼板的边界(包括门洞),然后沿着边界创建一组高亮的模型曲线。

针对你的问题,我重新检查了这个命令,并将其代码更新到 Revit 2013。

[Transaction( TransactionMode.Manual )]
class CmdSlabBoundary : IExternalCommand
{
  /// <summary>
  /// 新创建的边界多边形曲线和楼板边缘之间的偏移
  /// </summary>
  const double _offset = 0.1;
 
  /// <summary>
  /// 获取指定实体的最下方水平表面的边界多边形
  /// </summary>
  /// <param name="polygons">最下方水平表面的边界多边形(包括孔洞)</param>
  /// <param name="solid">实体(例如:楼板 Floor)</param>
  /// <returns>最下方水平表面是否能找到</returns>
  static bool GetBoundary(
		List<List<XYZ>> polygons, 
		Solid solid )
  {
    PlanarFace lowest = null;
    FaceArray faces = solid.Faces;
    foreach( Face f in faces )
    {
			// 比较表面原点的 Z 坐标来确定最下方的表面
      PlanarFace pf = f as PlanarFace;
      if( null != pf && Util.IsHorizontal( pf ) )
      {
        if( ( null == lowest ) || ( pf.Origin.Z < lowest.Origin.Z ) )
        {
          lowest = pf;
        }
      }
    }
		
    if( null != lowest )
    {
      XYZ p, q = XYZ.Zero;
      bool first;
      int i, n;
      EdgeArrayArray loops = lowest.EdgeLoops;
      foreach( EdgeArray loop in loops )
      {
        List<XYZ> vertices = new List<XYZ>();
        first = true;
        foreach( Edge e in loop )
        {
          IList<XYZ> points = e.Tessellate();
          p = points[0];
          if( !first )
          {
            Debug.Assert( p.IsAlmostEqualTo( q ), "expected subsequent start point to equal previous end point" );
          }
          n = points.Count;
          q = points[n - 1];
          for( i = 0; i < n - 1; ++i )
          {
            XYZ v = points[i];
            v -= _offset * XYZ.BasisZ;	// 使用楼板边界的所有顶点加上偏移创建曲线顶点
            vertices.Add( v );
          }
        }
	// 比较最后一个顶点和第一个顶点是否相等来判断是否是闭合多边形
        q -= _offset * XYZ.BasisZ;
        Debug.Assert( q.IsAlmostEqualTo( vertices[0] ), "expected last end point to equal first start point" );
        polygons.Add( vertices );
      }
    }
    return null != lowest;
  }
 
  /// <summary>
  /// 返回所有楼板边界多边形
  /// </summary>
  static public List<List<XYZ>> GetFloorBoundaryPolygons(
    List<Element> floors,
    Options opt )
  {
    List<List<XYZ>> polygons = new List<List<XYZ>>();
 
    foreach( Floor floor in floors )
    {
      GeometryElement geo = floor.get_Geometry( opt );
 
      //GeometryObjectArray objects = geo.Objects; // 2012
      //foreach( GeometryObject obj in objects ) // 2012
 
      foreach( GeometryObject obj in geo ) // 2013
      {
        Solid solid = obj as Solid;
        if( solid != null )
        {
          GetBoundary( polygons, solid );
        }
      }
    }
    return polygons;
  }
 
  public Result Execute(
    ExternalCommandData commandData,
    ref string message,
    ElementSet elements )
  {
    UIApplication app = commandData.Application;
    UIDocument uidoc = app.ActiveUIDocument;
    Document doc = uidoc.Document;

    //
    // 获取指定的楼板(使用适合你的场景的方式)

    List<Element> floors = new List<Element>();
 
    if( !Util.GetSelectedElementsOrAll(
      floors, uidoc, typeof( Floor ) ) )
    {
      Selection sel = uidoc.Selection;
 
      message = ( 0 < sel.Elements.Size )
        ? "Please select some floor elements."
        : "No floor elements found.";
 
      return Result.Failed;
    }
 
    Options opt = app.Application.Create.NewGeometryOptions();
 
    List<List<XYZ>> polygons = GetFloorBoundaryPolygons( floors, opt );
 
    int n = polygons.Count;
 
    Debug.Print( "{0} boundary loop{1} found.", n, Util.PluralSuffix( n ) );
 
    Creator creator = new Creator( doc );
 
    using( Transaction t = new Transaction( doc ) )
    {
      t.Start( "Draw Slab Boundaries" );
 
      creator.DrawPolygons( polygons );
 
      t.Commit();
    }
 
    return Result.Succeeded;
  }
}

我使用了一块包含两个孔洞的楼板做了测试,结果如下图:





这里有一个我还没搞清楚的问题:椭圆形的孔洞边界曲线没有显示为虚线。我猜测是 Revit 的显示机制将虚线优化成实线了。

 包含更新后的 CmdSlabBoundary 命令的 Building Coder 例程可以在这里下载: version 2013.0.99.4 

你可能感兴趣的:(优化,String,api,null,Class,loops)