应用程序:ReferencePlane

Revit平台:所有版本

Revit版本:2011.0

首次发布日期:9.1

编程语言:C

技能等级:中等

类别:基础知识,几何

类型:ExternalCommand

主题:创建参考平面。

摘要:

此示例展示了如何通过Revit API创建参考平面。

相关类:

Autodesk.Revit.DB.Document

Autodesk.Revit.DB.Floor

Autodesk.Revit.DB.Wall

Autodesk.Revit.DB.Options

Autodesk.Revit.DB.Line

Autodesk.Revit.DB.Solid

Autodesk.Revit.DB.Mesh

Autodesk.Revit.Creation.Document

项目文件:

Command.cs

此文件包含一个继承自IExternalCommand接口并实现Execute方法的Command类。

 

ReferencePlaneMgr.cs

此文件包含一个ReferencePlaneMgr类,其中包含有关参考平面的一些方法,例如在墙壁(或地板)上创建参考平面,获取参考平面的参数以及获取用于创建参考平面的墙壁(或地板)坐标。

 

ReferencePlaneForm.cs

此文件包含一个从Form类继承的ReferencePlaneForm类;该窗体包含一个DataGridView,用于显示项目中所有参考平面的一些参数。

 

GeomHelper.cs

此文件包含一个GeomHelper类,提供了用于创建墙壁或地板上的参考平面所使用的几何数据的实用方法,例如确定面是否垂直,找出构成平面的三个点以及计算两个点之间的距离。

描述:

此示例提供以下功能:

- 报告当前项目中的所有参考平面,并显示其ID、气泡端、自由端和法线。

- 允许用户创建参考平面:

- 如果用户在Revit中选择了墙壁,则在墙壁的左侧面上创建参考平面。

- 如果用户在Revit中选择了地板,则在地板底部创建参考平面。

说明:

1. 画出一些参考平面。(或打开ReferencePlane.rvt

2. 画一个板条或一堵墙,并选择它。

3. 运行此命令。

4. 用户可以在表格中看到所有参考平面的ID、气泡端、自由端和法线。

5. 单击“创建”按钮以创建新的参考平面。

源代码:

完整的源代码请加入QQ群649037449,在群文件中下载RevitSDK.exe,解压后在文件夹中搜索本文中应用程序名称即可获得完整源码

GeoHelper.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//
using System;
using System.Collections.Generic;
using Autodesk.Revit;
using Autodesk.Revit.DB;
using Element = Autodesk.Revit.DB.Element;
using GElement = Autodesk.Revit.DB.GeometryElement; 
    
namespace Revit.SDK.Samples.ReferencePlane.CS
{
    /// <summary>
    /// A object to help locating with geometry data.
    /// </summary>
    public class GeoHelper
    {
        //Defined the precision.
        private const double Precision = 0.0001;
        /// <summary>
        /// Find the bottom face of a face array.
        /// </summary>
        /// <param name="faces">A face array.</param>
        /// <returns>The bottom face of a face array.</returns>
        static public Face GetBottomFace(FaceArray faces)
        {
            Face face = null;
            double elevation = 0;
            double tempElevation = 0;
            Mesh mesh = null;
            foreach (Face f in faces)
            {
                if (IsVerticalFace(f))
                {
                    // If this is a vertical face, it cannot be a bottom face to a certainty.
                    continue;
                }
                tempElevation = 0;
                mesh = f.Triangulate();
                foreach (Autodesk.Revit.DB.XYZ xyz in mesh.Vertices)
                {
                    tempElevation = tempElevation + xyz.Z;
                }
                tempElevation = tempElevation / mesh.Vertices.Count;
                if (elevation > tempElevation || null == face)
                {
                    // Update the bottom face to which's elevation is the lowest.
                    face = f;
                    elevation = tempElevation;
                }
            }
            // The bottom face is consider as which's average elevation is the lowest, except vertical
            // face.
            return face;
        }
        /// <summary>
        /// Find out the three points which made of a plane.
        /// </summary>
        /// <param name="mesh">A mesh contains many points.</param>
        /// <param name="startPoint">Create a new instance of ReferencePlane.</param>
        /// <param name="endPoint">The free end apply to reference plane.</param>
        /// <param name="thirdPnt">A third point needed to define the reference plane.</param>
        static public void Distribute(Mesh mesh, ref Autodesk.Revit.DB.XYZ startPoint, ref Autodesk.Revit.DB.XYZ endPoint, ref Autodesk.Revit.DB.XYZ thirdPnt)
        {
            int count = mesh.Vertices.Count;
            startPoint = mesh.Vertices[0];
            endPoint = mesh.Vertices[(int)(count / 3)];
            thirdPnt = mesh.Vertices[(int)(count / 3 * 2)];
        }
        /// <summary>
        /// Calculate the length between two points.
        /// </summary>
        /// <param name="startPoint">The start point.</param>
        /// <param name="endPoint">The end point.</param>
        /// <returns>The length between two points.</returns>
        static public double GetLength(Autodesk.Revit.DB.XYZ startPoint, Autodesk.Revit.DB.XYZ endPoint)
        {
            return Math.Sqrt(Math.Pow((endPoint.X - startPoint.X), 2) +
                Math.Pow((endPoint.Y - startPoint.Y), 2) +
                Math.Pow((endPoint.Z - startPoint.Z), 2));
        }
        /// <summary>
        /// The distance between two value in a same axis.
        /// </summary>
        /// <param name="start">start value.</param>
        /// <param name="end">end value.</param>
        /// <returns>The distance between two value.</returns>
        static public double GetDistance(double start, double end)
        {
            return Math.Abs(start - end);
        }
        /// <summary>
        /// Get the vector between two points.
        /// </summary>
        /// <param name="startPoint">The start point.</param>
        /// <param name="endPoint">The end point.</param>
        /// <returns>The vector between two points.</returns>
        static public Autodesk.Revit.DB.XYZ GetVector(Autodesk.Revit.DB.XYZ startPoint, Autodesk.Revit.DB.XYZ endPoint)
        {
            return new Autodesk.Revit.DB.XYZ (endPoint.X - startPoint.X,
                endPoint.Y - startPoint.Y, endPoint.Z - startPoint.Z);
        }
        /// <summary>
        /// Determines whether a face is vertical.
        /// </summary>
        /// <param name="face">The face to be determined.</param>
        /// <returns>Return true if this face is vertical, or else return false.</returns>
        static private bool IsVerticalFace(Face face)
        {
            foreach (EdgeArray ea in face.EdgeLoops)
            {
                foreach (Edge e in ea)
                {
                    if (IsVerticalEdge(e))
                    {
                        return true;
                    }
                }
            }
            return false;            
        }
        /// <summary>
        /// Determines whether a edge is vertical.
        /// </summary>
        /// <param name="edge">The edge to be determined.</param>
        /// <returns>Return true if this edge is vertical, or else return false.</returns>
        static private bool IsVerticalEdge(Edge edge)
        {
            List<XYZ> polyline = edge.Tessellate() as List<XYZ>;
            Autodesk.Revit.DB.XYZ verticalVct = new Autodesk.Revit.DB.XYZ (0, 0, 1);
            Autodesk.Revit.DB.XYZ pointBuffer = polyline[0];
            for (int i = 1; i < polyline.Count; i = i + 1)
            {
                Autodesk.Revit.DB.XYZ temp = polyline[i];
                Autodesk.Revit.DB.XYZ vector = GetVector(pointBuffer, temp);
                if (Equal(vector, verticalVct))
                {
                    return true;
                }
                else
                {
                    continue;                    
                }
            }
            return false;
        }
        /// <summary>
        /// Determines whether two vector are equal in x and y axis.
        /// </summary>
        /// <param name="vectorA">The vector A.</param>
        /// <param name="vectorB">The vector B.</param>
        /// <returns>Return true if two vector are equals, or else return false.</returns>
        static private bool Equal(Autodesk.Revit.DB.XYZ vectorA, Autodesk.Revit.DB.XYZ vectorB)
        {
            bool isNotEqual = (Precision < Math.Abs(vectorA.X - vectorB.X)) ||
                (Precision < Math.Abs(vectorA.Y - vectorB.Y));
            return isNotEqual ? false : true;
        }
    }
}

ReferencePlaneMgr.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//
using System;
using System.Diagnostics;
using System.Data;
using System.Collections.Generic;

using Autodesk.Revit;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;

using Element = Autodesk.Revit.DB.Element;
using GElement = Autodesk.Revit.DB.GeometryElement;

namespace Revit.SDK.Samples.ReferencePlane.CS
{
/// <summary>
/// A object to manage reference plane.
/// </summary>
public class ReferencePlaneMgr
{
private UIDocument m_document; //the currently active project
private Options m_options; //User preferences for parsing of geometry.
//The datasource for a DataGridView control.
private DataTable m_referencePlanes;
//A dictionary for create reference plane with different host element.
private Dictionary<Type, CreateDelegate> m_createHandler;

/// <summary>
/// The datasource for a DataGridView control.
/// </summary>
public DataTable ReferencePlanes
{
get
{
GetAllReferencePlanes();
return m_referencePlanes;
}
}

//A delegate for create reference plane with different host element.
private delegate void CreateDelegate(Element host);

/// <summary>
/// A ReferencePlaneMgr object constructor.
/// </summary>
/// <param name="commandData">The ExternalCommandData object for the active
/// instance of Autodesk Revit.</param>
public ReferencePlaneMgr(ExternalCommandData commandData)
{
Debug.Assert(null != commandData);

m_document = commandData.Application.ActiveUIDocument;

//Get an instance of this class from Application. Create
m_options = commandData.Application.Application.Create.NewGeometryOptions();
//Set your preferences and pass it to Element.Geometry or Instance.Geometry.
m_options.ComputeReferences = true;
//m_options.DetailLevel = DetailLevels.Fine;
m_options.View = m_document.Document.ActiveView;

m_createHandler = new Dictionary<Type, CreateDelegate>();
m_createHandler.Add(typeof(Wall), new CreateDelegate(OperateWall));
m_createHandler.Add(typeof(Floor), new CreateDelegate(OperateSlab));

InitializeDataTable();
}

/// <summary>
/// Create reference plane with the selected element.
/// the selected element must be wall or slab at this sample code.
/// </summary>
public void Create()
{
foreach (ElementId eId in m_document.Selection.GetElementIds())
{
Element e = m_document.Document.GetElement(eId);
try
{
CreateDelegate createDelegate = m_createHandler[e.GetType()];
createDelegate(e);
}
catch (Exception)
{
continue;
}
}
}

/// <summary>
/// Initialize a DataTable object which is datasource of a DataGridView control.
/// </summary>
private void InitializeDataTable()
{
m_referencePlanes = new DataTable("ReferencePlanes");
// Declare variables for DataColumn and DataRow objects.
DataColumn column;

// Create new DataColumn, set DataType,
// ColumnName and add to DataTable.
column = new DataColumn();
column.DataType = System.Type.GetType("System.Int32");
column.ColumnName = "ID";
// Add the Column to the DataColumnCollection.
m_referencePlanes.Columns.Add(column);

// Create second column.
column = new DataColumn();
column.DataType = System.Type.GetType("System.String");
column.ColumnName = "BubbleEnd";
// Add the column to the table.
m_referencePlanes.Columns.Add(column);

// Create third column.
column = new DataColumn();
column.DataType = System.Type.GetType("System.String");
column.ColumnName = "FreeEnd";
// Add the column to the table.
m_referencePlanes.Columns.Add(column);

// Create fourth column.
column = new DataColumn();
column.DataType = System.Type.GetType("System.String");
column.ColumnName = "Normal";
// Add the column to the table.
m_referencePlanes.Columns.Add(column);

// Make the ID column the primary key column.
DataColumn[] PrimaryKeyColumns = new DataColumn[1];
PrimaryKeyColumns[0] = m_referencePlanes.Columns["ID"];
m_referencePlanes.PrimaryKey = PrimaryKeyColumns;
}

/// <summary>
/// Format the output string for a point.
/// </summary>
/// <param name="point">A point to show in UI.</param>
/// <returns>The display string for a point.</returns>
private string Format(Autodesk.Revit.DB.XYZ point)
{
return "(" + Math.Round(point.X, 2).ToString() +
", " + Math.Round(point.Y, 2).ToString() +
", " + Math.Round(point.Z, 2).ToString() + ")";
}

/// <summary>
/// Get all reference planes in current revit project.
/// </summary>
/// <returns>The number of all reference planes.</returns>
private int GetAllReferencePlanes()
{
m_referencePlanes.Clear();
DataRow row;

FilteredElementIterator itor = (new FilteredElementCollector(m_document.Document)).OfClass(typeof(Autodesk.Revit.DB.ReferencePlane)).GetElementIterator();
Autodesk.Revit.DB.ReferencePlane refPlane = null;

itor.Reset();
while (itor.MoveNext())
{
refPlane = itor.Current as Autodesk.Revit.DB.ReferencePlane;
if (null == refPlane)
{
continue;
}
else
{
row = m_referencePlanes.NewRow();
row["ID"] = refPlane.Id.IntegerValue;
row["BubbleEnd"] = Format(refPlane.BubbleEnd);
row["FreeEnd"] = Format(refPlane.FreeEnd);
row["Normal"] = Format(refPlane.Normal);
m_referencePlanes.Rows.Add(row);
}
}

return m_referencePlanes.Rows.Count;
}

/// <summary>
/// Create reference plane for a wall.
/// </summary>
/// <param name="host">A wall element.</param>
private void OperateWall(Element host)
{
Wall wall = host as Wall;
Autodesk.Revit.DB.XYZ bubbleEnd = new Autodesk.Revit.DB.XYZ();
Autodesk.Revit.DB.XYZ freeEnd = new Autodesk.Revit.DB.XYZ();
Autodesk.Revit.DB.XYZ cutVec = new Autodesk.Revit.DB.XYZ();

LocateWall(wall, ref bubbleEnd, ref freeEnd, ref cutVec);
m_document.Document.Create.NewReferencePlane(bubbleEnd, freeEnd, cutVec, m_document.Document.ActiveView);
}

/// <summary>
/// Create reference plane for a slab.
/// </summary>
/// <param name="host">A floor element.</param>
private void OperateSlab(Element host)
{
Floor floor = host as Floor;
Autodesk.Revit.DB.XYZ bubbleEnd = new Autodesk.Revit.DB.XYZ();
Autodesk.Revit.DB.XYZ freeEnd = new Autodesk.Revit.DB.XYZ();
Autodesk.Revit.DB.XYZ thirdPnt = new Autodesk.Revit.DB.XYZ();
LocateSlab(floor, ref bubbleEnd, ref freeEnd, ref thirdPnt);
m_document.Document.Create.NewReferencePlane2(bubbleEnd, freeEnd, thirdPnt, m_document.Document.ActiveView);
}

/// <summary>
/// Located the exterior of a wall object.
/// </summary>
/// <param name="wall">A wall object</param>
/// <param name="bubbleEnd">The bubble end of new reference plane.</param>
/// <param name="freeEnd">The free end of new reference plane.</param>
/// <param name="cutVec">The cut vector of new reference plane.</param>
private void LocateWall(Wall wall, ref Autodesk.Revit.DB.XYZ bubbleEnd, ref Autodesk.Revit.DB.XYZ freeEnd, ref Autodesk.Revit.DB.XYZ cutVec)
{
LocationCurve location = wall.Location as LocationCurve;
Curve locaCurve = location.Curve;

//Not work for wall without location.
if (null == locaCurve)
{
throw new Exception("This wall has no location.");
}

//Not work for arc wall.
Line line = locaCurve as Line;
if (null == line)
{
throw new Exception("Just work for straight wall.");
}

//Calculate offset by law of cosines.
double halfThickness = wall.Width / 2;
double length = GeoHelper.GetLength(locaCurve.GetEndPoint(0), locaCurve.GetEndPoint(1));
double xAxis = GeoHelper.GetDistance(locaCurve.GetEndPoint(0).X, locaCurve.GetEndPoint(1).X);
double yAxis = GeoHelper.GetDistance(locaCurve.GetEndPoint(0).Y, locaCurve.GetEndPoint(1).Y);

double xOffset = yAxis * halfThickness / length;
double yOffset = xAxis * halfThickness / length;

if (locaCurve.GetEndPoint(0).X < locaCurve.GetEndPoint(1).X
&& locaCurve.GetEndPoint(0).Y < locaCurve.GetEndPoint(1).Y)
{
xOffset = -xOffset;
}
if (locaCurve.GetEndPoint(0).X > locaCurve.GetEndPoint(1).X
&& locaCurve.GetEndPoint(0).Y > locaCurve.GetEndPoint(1).Y)
{
yOffset = -yOffset;
}
if (locaCurve.GetEndPoint(0).X > locaCurve.GetEndPoint(1).X
&& locaCurve.GetEndPoint(0).Y < locaCurve.GetEndPoint(1).Y)
{
xOffset = -xOffset;
yOffset = -yOffset;
}

//Three necessary parameters for generate a reference plane.
bubbleEnd = new Autodesk.Revit.DB.XYZ(locaCurve.GetEndPoint(0).X + xOffset,
locaCurve.GetEndPoint(0).Y + yOffset, locaCurve.GetEndPoint(0).Z);
freeEnd = new Autodesk.Revit.DB.XYZ(locaCurve.GetEndPoint(1).X + xOffset,
locaCurve.GetEndPoint(1).Y + yOffset, locaCurve.GetEndPoint(1).Z);
cutVec = new Autodesk.Revit.DB.XYZ(0, 0, 1);
}

/// <summary>
/// Located the buttom of a slab object.
/// </summary>
/// <param name="floor">A floor object.</param>
/// <param name="bubbleEnd">The bubble end of new reference plane.</param>
/// <param name="freeEnd">The free end of new reference plane.</param>
/// <param name="thirdPnt">The third point of new reference plane.</param>
private void LocateSlab(Floor floor, ref Autodesk.Revit.DB.XYZ bubbleEnd, ref Autodesk.Revit.DB.XYZ freeEnd, ref Autodesk.Revit.DB.XYZ thirdPnt)
{
//Obtain the geometry data of the floor.
GElement geometry = floor.get_Geometry(m_options);
Face buttomFace = null;

//foreach (GeometryObject go in geometry.Objects)
IEnumerator<GeometryObject> Objects = geometry.GetEnumerator();
while (Objects.MoveNext())
{
GeometryObject go = Objects.Current;

Solid solid = go as Solid;
if (null == solid)
{
continue;
}
else
{
//Get the bottom face of this floor.
buttomFace = GeoHelper.GetBottomFace(solid.Faces);
}
}

Mesh mesh = buttomFace.Triangulate();
GeoHelper.Distribute(mesh, ref bubbleEnd, ref freeEnd, ref thirdPnt);
}
}
}