应用程序:DoorSwing

Revit 平台:建筑

Revit 版本:2011.0

首次发布时间:2009.0

编程语言:C#

技能水平:中等

类别:房间/空间

类型:ExternalCommand、ExternalApplication

主题:管理门的开启和与门有关的房间。

摘要:本示例将演示如何创建和维护门开启参数、内部门参数、从/到房间参数,以及如何对这些参数进行编排。还提供了自定义国家标准的功能

相关类:

Autodesk.Revit.UI.IExternalCommand

Autodesk.Revit.UI.IExternalApplication

Autodesk.Revit.ApplicationServices.ControlledApplication

Autodesk.Revit.UI.RibbonPanel

Autodesk.Revit. UI.PushButton

Autodesk.Revit.DB.DocumentType.Family

Autodesk.Revit.DB.FamilyInstance

Autodesk.Revit.DB.GeometryElement

Autodesk.Revit.DB.BoundingBoxXYZ

Autodesk.Revit.DB.Options

Autodesk.Revit.DB.DefinitionFile

Autodesk.Revit.DB.Definition

Autodesk.Revit.DB.BindingMap

Autodesk.Revit.DB.ElementBinding

Autodesk.Revit.DB.InstanceBinding

Autodesk.Revit.DB.TypeBinding

Autodesk.Revit.DB.Parameter

Autodesk.Revit.DB.Events.DocumentSavingEventArgs

Autodesk.Revit.DB.Events.DocumentSavingAsEventArgs

项目文件:

Command.cs

该文件包括三个类InitializeCommand、UpdateParamsCommand和UpdateGeometryCommand。它们都实现了接口IExternalCommand。

ExternalApplication.cs

该文件包括一个类ExternalApplication,该类实现了接口IExternalApplication。该类将创建一个自定义的Ribbon面板,其中包含三个按钮,用于调用Command.cs文件中定义的三个外部命令。该类还订阅了一些应用级别事件,以更新门参数。这可以确保在保存、另存为等操作时文档是正确的。

DoorSwingData.cs

该文件包括一个类DoorSwingData,该类准备所需的数据并更新门开启、内部/外部门和从/到房间信息。

DoorFamily.cs

该文件包括一个类DoorFamily,该类维护每个门族的族名称、族几何和门开启表达式信息。它还根据每个门族的几何和国家标准自定义门开启表达式。

DoorFamilyGeometry.cs

该文件包括一个类DoorGeometry,该类用于将Revit几何数据转换为适合GDI的格式。

DoorSharedParameters.cs

该文件包括一个静态类DoorSharedParameters,该类用于向门添加三个共享参数,并将其命名为BasalOpening、InstanceOpening和Internal Door。

InitializeForm.cs

该文件包括一个窗体类InitializeForm,它包括一个DataGridView,用于显示当前Revit项目中存在的所有门族,还有一个pictureBox,用于显示门族的几何图形。用户可以根据每个门族的几何和国家标准在这里自定义门开启表达式。

DoorSwingResource.resx

一个资源文件,包含一些用于识别门开启的字符串。

描述

对于门的开启功能,用户可以调用外部命令“自定义门开启表达式”,添加所需的共享参数,并根据自己国家的标准和每个门族的几何形状自定义门开启表达式。当门被翻转或镜像时,用户可以调用外部命令“更新门属性”以更新参数值。这些参数的计划将从Revit UI中完成。

对于与门相关的房间功能,从Revit UI中用户可以在两个分别的计划表中调度内部和外部门的“到房间”和“从房间”信息,并且可以在计划表中更改门的方向。然后,用户将使用“更新门几何图形”命令,以在计划表中更改门的方向后更新门的几何形状。当在视图中翻转或镜像门时,用户可以调用外部命令“更新门属性”以更新“到房间”和“从房间”信息。

在关闭、保存或另存为项目文件时,参数更新过程也将被触发。

实施:

1. 准备Revit项目。

打开或新建一个Revit项目,并确保所有需要的房间都已放置。如果您的项目文件中有任何未定义房间的封闭墙回路,则示例将显示对话框,询问您是否将界定这些区域的门视为外部门。

样本项目文件DoorSwing.rvt可在样本文件夹中找到。

2. 自定义门开启表达式。

单击“自定义门开启表达式”命令(菜单项或Ribbon按钮)根据家族的几何形状和您的国家标准自定义每个门家族的开启表达式。这是该样本的第一个命令。如果列表中没有符合您国家标准的表达式,可以打开源代码项目并在以下3个区域中进行修改:

a. 编辑项目资源文件。

b. 编辑DoorSwingData.cs中的DoorSwingData静态构造函数。从资源文件中将更多门开启表达式添加到OpeningTypes列表中。

c. 编辑DoorSwingData.cs中的UpdateOpeningFeatureOfOneDoor函数。在“if(switchesOpeningValueFlag){...}”语句中添加更多else if来处理添加的门开启表达式。

希望创建本地化版本的用户可以按照上述步骤2.a进行操作。

3. 计划参数。

从Revit UI创建门计划。您可以安排“开口”、“内部门”参数和“从房间”/“到房间”的“房间编号”或任何其他需要的参数。

a. 创建内部门计划。

Revit按钮:视图选项卡->创建面板->计划/数量按钮;

类别:门;名称:内部门计划。

添加需要计划的参数。

• 添加现有参数:标记、内部门、InstanceOpening、FromRoom:Number、ToRoom:Number;

• 添加计算值:名称:Opening,选择:公式,学科:普通,类型:文本,公式:InstanceOpening。

• 将Opening参数移至InstanceOpening参数之前。

修改计划的外观,包括可见性、排序等。

• 如果需要,则隐藏内部门和InstanceOpening列:右键单击“内部门”列,然后单击“隐藏列”菜单;右键单击“InstanceOpening”列,然后单击“隐藏列”菜单;

• 按门的标记值排序项目:在计划中任何位置右键单击,然后单击“查看属性”菜单;在属性对话框中的“排序/分组”项目;按标记排序。

• 按内部门过滤:在属性对话框中的“过滤器”项目;按Internal Door等于Yes过滤。

b. 创建外部门计划。

按照创建内部门计划的相同步骤操作,只需进行Filter设置。按Internal Door等于No筛选。

4. 当翻转/镜像门时,更新门参数。

翻转/镜像任何门,然后单击“更新门属性”命令(菜单项或Ribbon按钮)。该命令将根据门的几何形状更新门参数。

5. 在计划中更改门的方向时,更新门的几何形状。

您甚至可以从计划中更改“从房间”/“到房间”的房间编号。之后,单击“更新门几何”命令将根据您在计划中所做的更改更改门的几何形状。

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

ExternalApplication.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.IO;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Windows.Media.Imaging;

using Autodesk.Revit;
using Autodesk.Revit.DB.Events;
using Autodesk.Revit.UI;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.DB;


namespace Revit.SDK.Samples.DoorSwing.CS
{
    /// <summary>
    /// A class inherited IExternalApplication interface.
    /// This class subscribes to some application level events and 
    /// creates a custom Ribbon panel which contains three buttons.
    /// </summary
    [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
    [Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
    [Autodesk.Revit.Attributes.Journaling(Autodesk.Revit.Attributes.JournalingMode.NoCommandData)]
    public class ExternalApplication : IExternalApplication
    {
        #region "Members"

        // An object that is passed to the external application which contains the controlled Revit application.
        UIControlledApplication m_controlApp;

        #endregion

        #region IExternalApplication Members

        /// <summary>
        /// Implement this method to implement the external application which should be called when 
        /// Revit starts before a file or default template is actually loaded.
        /// <param name="application">An object that is passed to the external application 
        /// which contains the controlled application.</param>
        /// <returns>Return the status of the external application. 
        /// A result of Succeeded means that the external application successfully started. 
        /// Cancelled can be used to signify that the user cancelled the external operation at 
        /// some point.
        /// If false is returned then Revit should inform the user that the external application 
        /// failed to load and the release the internal reference.</returns> 
        public Autodesk.Revit.UI.Result OnStartup(UIControlledApplication application)
        {
            m_controlApp = application;

            #region Subscribe to related events

            // Doors are updated from the application level events. 
            // That will insure that the doc is correct when it is saved.
            // Subscribe to related events.
            application.ControlledApplication.DocumentSaving += new EventHandler<DocumentSavingEventArgs>(DocumentSavingHandler);
            application.ControlledApplication.DocumentSavingAs += new EventHandler<DocumentSavingAsEventArgs>(DocumentSavingAsHandler);

            #endregion

            #region create a custom Ribbon panel which contains three buttons

            // The location of this command assembly
            string currentCommandAssemblyPath = System.Reflection.Assembly.GetExecutingAssembly().Location;

            // The directory path of buttons' images
            string buttonImageDir = Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName
                   (Path.GetDirectoryName(currentCommandAssemblyPath))));

            // begin to create custom Ribbon panel and command buttons.
            // create a Ribbon panel.
            RibbonPanel doorPanel = application.CreateRibbonPanel("Door Swing");

            // the first button in the DoorSwing panel, use to invoke the InitializeCommand.
            PushButton initialCommandBut = doorPanel.AddItem(new PushButtonData("Customize Door Opening",
                                                             "Customize Door Opening",
                                                             currentCommandAssemblyPath,
                                                             typeof(InitializeCommand).FullName))
                                                             as PushButton;
            initialCommandBut.ToolTip = "Customize the expression based on family's geometry and country's standard.";
            initialCommandBut.LargeImage = new BitmapImage(new Uri(Path.Combine(buttonImageDir, "InitialCommand_Large.bmp")));
            initialCommandBut.Image = new BitmapImage(new Uri(Path.Combine(buttonImageDir, "InitialCommand_Small.bmp")));

            // the second button in the DoorSwing panel, use to invoke the UpdateParamsCommand.
            PushButton updateParamBut = doorPanel.AddItem(new PushButtonData("Update Door Properties",
                                                          "Update Door Properties",
                                                          currentCommandAssemblyPath,
                                                          typeof(UpdateParamsCommand).FullName))
                                                          as PushButton;
            updateParamBut.ToolTip = "Update door properties based on geometry.";
            updateParamBut.LargeImage = new BitmapImage(new Uri(Path.Combine(buttonImageDir, "UpdateParameter_Large.bmp")));
            updateParamBut.Image = new BitmapImage(new Uri(Path.Combine(buttonImageDir, "UpdateParameter_Small.bmp")));

            // the third button in the DoorSwing panel, use to invoke the UpdateGeometryCommand.
            PushButton updateGeoBut = doorPanel.AddItem(new PushButtonData("Update Door Geometry",
                                                        "Update Door Geometry",
                                                        currentCommandAssemblyPath,
                                                        typeof(UpdateGeometryCommand).FullName))
                                                        as PushButton;
            updateGeoBut.ToolTip = "Update door geometry based on From/To room property.";
            updateGeoBut.LargeImage = new BitmapImage(new Uri(Path.Combine(buttonImageDir, "UpdateGeometry_Large.bmp")));
            updateGeoBut.Image = new BitmapImage(new Uri(Path.Combine(buttonImageDir, "UpdateGeometry_Small.bmp")));

            #endregion

            return Autodesk.Revit.UI.Result.Succeeded;
        }

        /// <summary>
        /// Implement this method to implement the external application which should be called when 
        /// Revit is about to exit, any documents must have been closed before this method is called.
        /// </summary>
        /// <param name="application">An object that is passed to the external application 
        /// which contains the controlled application.</param>
        /// <returns>Return the status of the external application. 
        /// A result of Succeeded means that the external application successfully shutdown. 
        /// Cancelled can be used to signify that the user cancelled the external operation at some point.
        /// If false is returned then the Revit user should be warned of the failure of the external 
        /// application to shut down correctly.</returns>
        public Autodesk.Revit.UI.Result OnShutdown(UIControlledApplication application)
        {
            return Autodesk.Revit.UI.Result.Succeeded;
        }

        #endregion

        /// <summary>
        /// This event is fired whenever a document is saved.
        /// Update door's information according to door's current geometry.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="args">An DocumentSavingEventArgs that contains the DocumentSaving event data.</param>
        private void DocumentSavingHandler(Object sender, DocumentSavingEventArgs args)
        {
            string message = "";
            Transaction tran = null;

            try
            {
                Document doc = args.Document;
                if (doc.IsModifiable)
                {
                    if (DoorSwingData.UpdateDoorsInfo(args.Document, false, false, ref message) != Autodesk.Revit.UI.Result.Succeeded)
                        TaskDialog.Show("Door Swing", message);
                }
                else
                {
                    tran = new Transaction(doc, "Update parameters in Saving event");
                    tran.Start();

                    if (DoorSwingData.UpdateDoorsInfo(args.Document, false, false, ref message) != Autodesk.Revit.UI.Result.Succeeded)
                        TaskDialog.Show("Door Swing", message);

                    tran.Commit();
                }
            }
            catch (Exception ex)
            {
                // if there are something wrong, give error information message.
                TaskDialog.Show("Door Swing", ex.Message);
                if (null != tran)
                {
                    if (tran.HasStarted() && !tran.HasEnded())
                    {
                        tran.RollBack();
                    }
                }
            }
        }

        /// <summary>
        /// This event is fired whenever a document is saved as.
        /// Update door's information according to door's current geometry.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="args">An DocumentSavingAsEventArgs that contains the DocumentSavingAs event data.</param>
        private void DocumentSavingAsHandler(Object sender, DocumentSavingAsEventArgs args)
        {
            string message = "";
            Transaction tran = null;
            try
            {
                Document doc = args.Document;
                if (doc.IsModifiable)
                {
                    if (DoorSwingData.UpdateDoorsInfo(args.Document, false, false, ref message) != Autodesk.Revit.UI.Result.Succeeded)
                        TaskDialog.Show("Door Swing", message);
                }
                else
                {
                    tran = new Transaction(doc, "Update parameters in Saving event");
                    tran.Start();

                    if (DoorSwingData.UpdateDoorsInfo(args.Document, false, false, ref message) != Autodesk.Revit.UI.Result.Succeeded)
                        TaskDialog.Show("Door Swing", message);

                    tran.Commit();
                }
            }
            catch (Exception ex)
            {
                // if there are something wrong, give error message.
                TaskDialog.Show("Door Swing", ex.Message);

                if (null != tran)
                {
                    if (tran.HasStarted() && !tran.HasEnded())
                    {
                        tran.RollBack();
                    }
                }
            }
        }
    }
}

DoorFamily.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 System.Text;

using Autodesk.Revit;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.ApplicationServices;


namespace Revit.SDK.Samples.DoorSwing.CS
{
   /// <summary>
   /// Left/Right feature based on family's actual geometry and country's standard.
   /// </summary>
   public class DoorFamily
   {
      #region "Members"

      // door family
      Family m_family;
      // opening value of one of this family's door which neither flipped nor mirrored.
      string m_basalOpeningValue;
      // one door instance of this family.
      FamilyInstance m_oneInstance;
      // Revit application
      UIApplication m_app;
      // the geometry of one of this family's door which neither flipped nor mirrored.
      DoorGeometry m_geometry;

      #endregion

      #region "Properties"

      /// <summary>
      /// Retrieval the name of this family.
      /// </summary>
      public string FamilyName
      {
         get
         {
            return m_family.Name;
         }
      }

      /// <summary>
      /// Retrieve opening value of one of this family's door which neither flipped nor mirrored.
      /// </summary>
      public string BasalOpeningValue
      {
         get
         {
            if (string.IsNullOrEmpty(m_basalOpeningValue))
            {
               string paramValue = DoorSwingResource.Undefined;

               // get current opening value.  
               System.Collections.Generic.List<FamilySymbol> fss = new System.Collections.Generic.List<FamilySymbol>(); 
               foreach (ElementId elementId in m_family.GetFamilySymbolIds())
               {
                  fss.Add((FamilySymbol)(m_app.ActiveUIDocument.Document.GetElement(elementId)));
               }
               FamilySymbol doorSymbol = fss[0]; 
               paramValue = doorSymbol.ParametersMap.get_Item("BasalOpening").AsString();

               // deal with invalid string.
               if (!DoorSwingData.OpeningTypes.Contains(paramValue))
               {
                  paramValue = DoorSwingResource.Undefined;
               }

               m_basalOpeningValue = paramValue;
            }

            return m_basalOpeningValue;
         }
         set
         {
            m_basalOpeningValue = value;
         }
      }

      /// <summary>
      /// Retrieve the geometry of one door which belongs to this family and 
      /// neither flipped nor mirrored.
      /// </summary>
      public DoorGeometry Geometry
      {
         get
         {
            if (null == m_geometry)
            {
               // create one instance of DoorFamilyGeometry class.
               m_geometry = new DoorGeometry(m_oneInstance);
            }

            return m_geometry;
         }
      }

      #endregion

      #region "Methods"

      /// <summary>
      ///  construct function.
      /// </summary>
      /// <param name="doorFamily"> one door family</param>
      /// <param name="app">Revit application</param>
      public DoorFamily(Family doorFamily, UIApplication app)
      {
         m_app = app;
         m_family = doorFamily;
         // one door instance which belongs to this family and neither flipped nor mirrored.
         m_oneInstance = CreateOneInstanceWithThisFamily();
      }

      /// <summary>
      /// Update Left/Right feature based on family's actual geometry and country's standard.
      /// </summary>
      public void UpdateOpeningFeature()
      {
         // get current Left/Right feature's value of this door family.
         List<FamilySymbol> ffs = new List<FamilySymbol>(); 
         foreach (ElementId elementId in m_family.GetFamilySymbolIds())
         {
            ffs.Add((FamilySymbol)(m_app.ActiveUIDocument.Document.GetElement(elementId)));
         }
         foreach (FamilySymbol doorSymbol in ffs)
         {
            // update the the related family shared parameter's value if user already added it.
            if (doorSymbol.ParametersMap.Contains("BasalOpening"))
            {
               Parameter basalOpeningParam = doorSymbol.ParametersMap.get_Item("BasalOpening");
               bool setResult = basalOpeningParam.Set(m_basalOpeningValue);
            }
         }
      }

      /// <summary>
      /// Delete the temporarily created door instance and its host.
      /// </summary>
      public void DeleteTempDoorInstance()
      {
         Document doc = m_app.ActiveUIDocument.Document;
         Autodesk.Revit.DB.Element tempWall = m_oneInstance.Host;
         doc.Delete(m_oneInstance.Id); // delete temporarily created door instance with this family.
         doc.Delete(tempWall.Id); // delete the door's host.
      }

      /// <summary>
      /// Create one temporary door instance with this family.
      /// </summary>
      /// <returns>the created door.</returns>
      private FamilyInstance CreateOneInstanceWithThisFamily()
      {
         Autodesk.Revit.DB.Document doc = m_app.ActiveUIDocument.Document;
         Autodesk.Revit.Creation.Document creDoc = doc.Create;
         Autodesk.Revit.Creation.Application creApp = m_app.Application.Create;

         // get one level. A project has at least one level.
         Level level = new FilteredElementCollector(doc).OfClass(typeof(Level)).FirstElement() as Level;

         // create one wall as door's host
         Line wallCurve = Line.CreateBound(new Autodesk.Revit.DB.XYZ(0, 0, 0), new Autodesk.Revit.DB.XYZ(100, 0, 0));
         Wall host = Wall.Create(doc, wallCurve, level.Id, false);
         doc.Regenerate();

         // door symbol.
         List<FamilySymbol> ffs = new List<FamilySymbol>(); 
         foreach (ElementId elementId in m_family.GetFamilySymbolIds())
         {
            ffs.Add((FamilySymbol)(m_app.ActiveUIDocument.Document.GetElement(elementId)));
         }
         FamilySymbol doorSymbol = ffs[0];

         // create the door
         FamilyInstance createdFamilyInstance = creDoc.NewFamilyInstance(new Autodesk.Revit.DB.XYZ(0, 0, 0), doorSymbol, host, level,
                                                StructuralType.NonStructural);
         doc.Regenerate();

         return createdFamilyInstance;
      }

      #endregion
   }
}

DoorFamilyGeometry.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 System.Text;
using System.Linq;

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


namespace Revit.SDK.Samples.DoorSwing.CS
{
   /// <summary>
   /// The DoorGeometry object is used to transform Revit geometry data
   /// to appropriate format for GDI.
   /// </summary>
   public class DoorGeometry
   {
      #region "Members"

      // User preferences for parsing of geometry.
      Options m_options;
      // boundingBox of the geometry. 
      BoundingBoxXYZ m_bbox;
      // curves can represent the wireFrame of the door's geometry.
      List<List<XYZ>> m_curve3Ds = new List<List<XYZ>>();

      #endregion

      #region "Properties"

      /// <summary>
      /// BoundingBox of the 2D geometry.
      /// </summary>
      public System.Drawing.RectangleF BBOX2D
      {
         get
         {
            return new System.Drawing.RectangleF((float)m_bbox.Min.X, (float)m_bbox.Min.Y,
                  (float)(m_bbox.Max.X - m_bbox.Min.X), (float)(m_bbox.Max.Y - m_bbox.Min.Y));
         }
      }

      #endregion

      #region "Methods"

      /// <summary>
      /// construct function.
      /// </summary>
      /// <param name="door">of which geometry data is wanted.</param>
      public DoorGeometry(Autodesk.Revit.DB.Element door)
      {
         m_options = new Options();
         m_options.View = GetPlanform2DView(door);
         m_options.ComputeReferences = false;
         Autodesk.Revit.DB.GeometryElement geoEle = door.get_Geometry(m_options);
         AddGeometryElement(geoEle);

         m_bbox = door.get_BoundingBox(m_options.View);
      }

      /// <summary>
      /// Draw the line contains in m_curve3Ds in 2d Preview.Drawn as top view.
      /// </summary>
      /// <param name="graphics">Graphics to draw</param>
      /// <param name="drawPen">The pen to draw curves.</param>
      public void DrawGraphics(System.Drawing.Graphics graphics, System.Drawing.Pen drawPen)
      {
         for (int i = 0; i < m_curve3Ds.Count; i++)
         {
            List<XYZ> points = m_curve3Ds[i];

            for (int j = 0; j < (points.Count - 1); j++)
            {
               // ignore xyz.Z value, drawn as top view.
               System.Drawing.PointF startPoint = new System.Drawing.PointF((float)points[j].X, (float)points[j].Y);
               System.Drawing.PointF endPoint = new System.Drawing.PointF((float)points[j + 1].X, (float)points[j + 1].Y);
               graphics.DrawLine(drawPen, startPoint, endPoint);
            }
         }
      }

      /// <summary>
      /// Retrieve the ViewPlan corresponding to the door's level. 
      /// </summary>
      /// <param name="door">
      /// one door whose level is corresponding to the retrieved ViewPlan.
      /// </param>
      /// <returns>One ViewPlan</returns>
      static private ViewPlan GetPlanform2DView(Autodesk.Revit.DB.Element door)
      {
         IEnumerable<ViewPlan> viewPlans = from elem in
                                              new FilteredElementCollector(door.Document).OfClass(typeof(ViewPlan)).ToElements()
                                           let viewPlan = elem as ViewPlan
                                           where viewPlan != null && !viewPlan.IsTemplate && viewPlan.GenLevel.Id.IntegerValue == door.LevelId.IntegerValue
                                           select viewPlan;
         if (viewPlans.Count() > 0)
         {
            return viewPlans.First();
         }
         else
            return null;
      }

      /// <summary>
      /// iterate GeometryObject in GeometryObjectArray and generate data accordingly.
      /// </summary>
      /// <param name="geoEle">a geometry object of element</param>
      private void AddGeometryElement(Autodesk.Revit.DB.GeometryElement geoEle)
      {
         // get all geometric primitives contained in the Geometry Element
         //GeometryObjectArray geoObjArray = geoEle.Objects;
         IEnumerator<GeometryObject> Objects = geoEle.GetEnumerator();

         // iterate each Geometry Object and generate data accordingly.
         //foreach (GeometryObject geoObj in geoObjArray)
         while (Objects.MoveNext())
         {
            GeometryObject geoObj = Objects.Current;

            if (geoObj is Curve)
            {
               AddCurve(geoObj);
            }
            else if (geoObj is Edge)
            {
               AddEdge(geoObj);
            }
            else if (geoObj is Autodesk.Revit.DB.GeometryElement)
            {
               AddElement(geoObj);
            }
            else if (geoObj is Face)
            {
               AddFace(geoObj);
            }
            else if (geoObj is Autodesk.Revit.DB.GeometryInstance)
            {
               AddInstance(geoObj);
            }
            else if (geoObj is Mesh)
            {
               AddMesh(geoObj);
            }
            else if (geoObj is Profile)
            {
               AddProfile(geoObj);
            }
            else if (geoObj is Solid)
            {
               AddSolid(geoObj);
            }
         }
      }

      /// <summary>
      /// generate data of a Curve.
      /// </summary>
      /// <param name="obj">a geometry object of element.</param>
      private void AddCurve(GeometryObject obj)
      {
         Curve curve = obj as Curve;

         if (!curve.IsBound)
         {
            return;
         }

         // get a polyline approximation to the curve.
         List<XYZ> points = curve.Tessellate() as List<XYZ>;

         m_curve3Ds.Add(points);
      }

      /// <summary>
      /// generate data of an Edge.
      /// </summary>
      /// <param name="obj">a geometry object of element.</param>
      private void AddEdge(GeometryObject obj)
      {
         Edge edge = obj as Edge;

         // get a polyline approximation to the edge.
         List<XYZ> points = edge.Tessellate() as List<XYZ>;

         m_curve3Ds.Add(points);
      }

      /// <summary>
      /// generate data of a Geometry Element.
      /// </summary>
      /// <param name="obj">a geometry object of element.</param>
      private void AddElement(GeometryObject obj)
      {
         Autodesk.Revit.DB.GeometryElement geoEle = obj as Autodesk.Revit.DB.GeometryElement;
         AddGeometryElement(geoEle);
      }

      /// <summary>
      /// generate data of a Face.
      /// </summary>
      /// <param name="obj">a geometry object of element.</param>
      private void AddFace(GeometryObject obj)
      {
         Face face = obj as Face;

         // get a triangular mesh approximation to the face.
         Mesh mesh = face.Triangulate();
         if (null != mesh)
         {
            AddMesh(mesh);
         }
      }

      /// <summary>
      /// generate data of a Geometry Instance.
      /// </summary>
      /// <param name="obj">a geometry object of element.</param>
      private void AddInstance(GeometryObject obj)
      {
         Autodesk.Revit.DB.GeometryInstance instance = obj as Autodesk.Revit.DB.GeometryInstance;
         Autodesk.Revit.DB.GeometryElement geoElement = instance.SymbolGeometry;

         AddGeometryElement(geoElement);
      }

      /// <summary>
      /// generate data of a Mesh.
      /// </summary>
      /// <param name="obj">a geometry object of element.</param>
      private void AddMesh(GeometryObject obj)
      {
         Mesh mesh = obj as Mesh;
         List<XYZ> points = new List<XYZ>();

         // get all triangles of the mesh.
         for (int i = 0; i < mesh.NumTriangles; i++)
         {
            MeshTriangle trigangle = mesh.get_Triangle(i);

            for (int j = 0; j < 3; j++)
            {
               // A vertex of the triangle.
               Autodesk.Revit.DB.XYZ point = trigangle.get_Vertex(j);

               double x = point.X;
               double y = point.Y;
               double z = point.Z;

               points.Add(point);
            }

            Autodesk.Revit.DB.XYZ iniPoint = points[0];
            points.Add(iniPoint);

            m_curve3Ds.Add(points);
         }
      }

      /// <summary>
      /// generate data of a Profile.
      /// </summary>
      /// <param name="obj">a geometry object of element.</param>
      private void AddProfile(GeometryObject obj)
      {
         Profile profile = obj as Profile;

         // get the curves that make up the boundary of the profile.
         CurveArray curves = profile.Curves;

         foreach (Curve curve in curves)
         {
            AddCurve(curve);
         }
      }

      /// <summary>
      /// generate data of a Solid.
      /// </summary>
      /// <param name="obj">a geometry object of element.</param>
      private void AddSolid(GeometryObject obj)
      {
         Solid solid = obj as Solid;

         // get the faces that belong to the solid.
         FaceArray faces = solid.Faces;

         foreach (Face face in faces)
         {
            AddFace(face);
         }
      }

      #endregion
   }
}