Revit APP Blog

Information on Revit APP.

Browsing Posts in Coding

Before Revit 2010 API, there is no transaction exported to API developers, that’s to say, API developer doesn’t need to care about how transaction works for Revit document and how we should use it in API development. But for new Revit API, we have to create our own Transaction and we can decide when to start, commit or rollback our transaction. I’d like to discuss a little more about the transaction in Revit API development because many of us met problems for this.

Transaction in Revit API is just like what we now a transaction is. Transaction is the minimal atom of user visible change in document – Undo/Redo. All changes in a transaction will be combined to one Undo/Redo item in Revit, user can easily undo/redo the block of changes, but there is no way to undo/redo part of changes in a transaction – they have to be done together or be cancelled together.

In new Revit API, any change to document needs be included in transaction, if you forgot to do so, a warning will pop up when you execute your own addins. So remember to make sure all changes are in transaction(s) (It’s not necessary to put all changes in one big transaction, but any change should be in a transaction).

To add a transaction is quite simple:

Transaction myTrans = new Transaction(doc);
myTrans.Start(“My Change”);

The string parameter in the “Start” function is the name of this transaction and will be shown in the Undo/Redo list, so choose a proper transaction name is useful for end user to understand what happened.

To commit or rollback a transaction is also simple:

myTrans.commit(); or myTrans.rollback();

We have two methods to control whether we will show or hide elements in a specific view:

View.setVisibility / View.getVisibility and View.Hide / View.Unhide. The first pair is to control whether all elements belong to a specific category will show, the second pair is to control whether a specific group of elements will show in a view.

Here is some sample code:

UIDocument uiDoc = commandData.Application.ActiveUIDocument;
Application app = commandData.Application.Application;
Document doc = uiDoc.Document;

View curView = doc.ActiveView;
Transaction trans = new Transaction(doc);
trans.Start(“Hide or Unhide”);
Category cat = doc.Settings.Categories.get_Item(BuiltInCategory.OST_Doors);
if (cat != null)
{
bool bVisibility = curView.getVisibility(cat);
curView.setVisibility(cat, !bVisibility);
}

ElementSet elemSet = new ElementSet();
ICollection<Element> elems = new FilteredElementCollector(doc, curView.Id).OfCategory(BuiltInCategory.OST_Windows).WhereElementIsNotElementType().ToElements();
bool bHide = true;
foreach (Element e in elems)
{
elemSet.Insert(e);
bHide = e.IsHidden(curView);
}
if (bHide == false)
{
curView.Hide(elemSet);
}
trans.Commit();
return Result.Succeeded;

Attention:

Once you hide some elements, you cannot be able to FilteredElementCollector(doc, curView.Id) to get these elements, so you’d better to store these elements’ ids somewhere if you want to unhide them later.

Some times we need retrieve all level elevatioins, here is the code:

string strMsg = “”;
Transaction trans = new Transaction(doc, “Show Level”);
trans.Start();
FilteredElementCollector collector = new FilteredElementCollector(doc);
ICollection<Element> elems = collector.WhereElementIsNotElementType().OfClass(typeof(Level)).ToElements();
foreach (Level lv in elems)
{
strMsg += lv.Name + ” : elevation” + lv.Elevation.ToString(“F2″) + “\n”;
}
TaskDialog.Show(“Level elements”, strMsg);
trans.RollBack();

Just notice that, the Elevation got from the Level element is stored in feet unit, if you want to show other unit (like inches or meters), you need to transform it before use it.

We introduced one way to retrieve revit thumbnail in post: http://blog.revitapp.com/2010/07/revit-thumbnails/. However, we found that that tool has some unknown issue which will make Revit crash.

Here we introduce another class to get the file preview (including Revit thumbnail):

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

using System.Drawing;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;

namespace RevitApp
{
   internal class ThumbnailCreator : IDisposable
   {
      // Fields
      private IMalloc alloc;
      private Size desiredSize;
      private bool disposed;
      private Bitmap thumbnail;

      // Methods
      public ThumbnailCreator()
      {
         this.desiredSize = new Size(128, 128);
      }

      public ThumbnailCreator(int width, int height)
      {
         desiredSize = new Size(128, 128);
         desiredSize.Width = width;
         desiredSize.Height = height;
      }

      public void Dispose()
      {
         if (!this.disposed)
         {
            if (this.alloc != null)
            {
               Marshal.ReleaseComObject(this.alloc);
            }
            this.alloc = null;
            if (this.thumbnail != null)
            {
               this.thumbnail.Dispose();
            }
            this.disposed = true;
         }
      }

      ~ThumbnailCreator()
      {
         this.Dispose();
      }

      private bool getThumbNail(string file, IntPtr pidl, IShellFolder item)
      {
         bool CS;
         IntPtr hBmp = IntPtr.Zero;
         IExtractImage extractImage = null;
         try
         {
            if (Path.GetFileName(PathFromPidl(pidl)).ToUpper().Equals(Path.GetFileName(file).ToUpper()))
            {
               int prgf;
               IUnknown iunk = null;
               Guid iidExtractImage = new Guid(“BB2E617C-0920-11d1-9A0B-00C04FC2D6C1″);
               item.GetUIObjectOf(IntPtr.Zero, 1, ref pidl, ref iidExtractImage, out prgf, ref iunk);
               extractImage = (IExtractImage)iunk;
               if (extractImage != null)
               {
                  SIZE sz = new SIZE
                  {
                     cx = this.desiredSize.Width,
                     cy = this.desiredSize.Height
                  };
                  StringBuilder location = new StringBuilder(260, 260);
                  int priority = 0;
                  int requestedColourDepth = 0×20;
                  EIEIFLAG flags = EIEIFLAG.IEIFLAG_SCREEN | EIEIFLAG.IEIFLAG_ASPECT;
                  int uFlags = (int)flags;
                  extractImage.GetLocation(location, location.Capacity, ref priority, ref sz, requestedColourDepth, ref uFlags);
                  extractImage.Extract(out hBmp);

                  if (hBmp != IntPtr.Zero)
                  {
                     this.thumbnail = Image.FromHbitmap(hBmp);
                  }
                  Marshal.ReleaseComObject(extractImage);
                  extractImage = null;
               }
               return true;
            }
            CS = false;
         }
         catch (Exception)
         {
            if (hBmp != IntPtr.Zero)
            {
               UnManagedMethods.DeleteObject(hBmp);
            }
            if (extractImage != null)
            {
               Marshal.ReleaseComObject(extractImage);
            }
            throw;
         }
         return CS;
      }

      public Bitmap GetThumbNail(string file)
      {
         if (!File.Exists(file) && !Directory.Exists(file))
         {
            throw new FileNotFoundException(string.Format(“The file ‘{0}’ does not exist”, file), file);
         }
         if (this.thumbnail != null)
         {
            this.thumbnail.Dispose();
            this.thumbnail = null;
         }
         IShellFolder folder = getDesktopFolder;
         if (folder != null)
         {
            IntPtr pidlMain;
            try
            {
               int cParsed;
               int pdwAttrib;
               string filePath = Path.GetDirectoryName(file);
               folder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, filePath, out cParsed, out pidlMain, out pdwAttrib);
            }
            catch (Exception)
            {
               Marshal.ReleaseComObject(folder);
               throw;
            }
            if (pidlMain != IntPtr.Zero)
            {
               Guid iidShellFolder = new Guid(“000214E6-0000-0000-C000-000000000046″);
               IShellFolder item = null;
               try
               {
                  folder.BindToObject(pidlMain, IntPtr.Zero, ref iidShellFolder, ref item);
               }
               catch (Exception)
               {
                  Marshal.ReleaseComObject(folder);
                  this.Allocator.Free(pidlMain);
                  throw;
               }
               if (item != null)
               {
                  IEnumIDList idEnum = null;
                  try
                  {
                     item.EnumObjects(IntPtr.Zero, ESHCONTF.SHCONTF_NONFOLDERS | ESHCONTF.SHCONTF_FOLDERS, ref idEnum);
                  }
                  catch (Exception)
                  {
                     Marshal.ReleaseComObject(folder);
                     this.Allocator.Free(pidlMain);
                     throw;
                  }
                  if (idEnum != null)
                  {
                     IntPtr pidl = IntPtr.Zero;
                     bool complete = false;
                     while (!complete)
                     {
                        int fetched;
                        if (idEnum.Next(1, ref pidl, out fetched) != 0)
                        {
                           pidl = IntPtr.Zero;
                           complete = true;
                        }
                        else if (this.getThumbNail(file, pidl, item))
                        {
                           complete = true;
                        }
                        if (pidl != IntPtr.Zero)
                        {
                           this.Allocator.Free(pidl);
                        }
                     }
                     Marshal.ReleaseComObject(idEnum);
                  }
                  Marshal.ReleaseComObject(item);
               }
               this.Allocator.Free(pidlMain);
            }
            Marshal.ReleaseComObject(folder);
         }
         return this.thumbnail;
      }

      private static string PathFromPidl(IntPtr pidl)
      {
         StringBuilder path = new StringBuilder(260, 260);
         if (UnManagedMethods.SHGetPathFromIDList(pidl, path) != 0)
         {
            return path.ToString();
         }
         return string.Empty;
      }

      // Properties
#region Properties
      private IMalloc Allocator
      {
         get
         {
            if (!this.disposed && (this.alloc == null))
            {
               UnManagedMethods.SHGetMalloc(out this.alloc);
            }
            return this.alloc;
         }
      }

      public Size DesiredSize
      {
         get
         {
            return this.desiredSize;
         }
         set
         {
            this.desiredSize = value;
         }
      }

      public Bitmap ThumbNail
      {
         get
         {
            return this.thumbnail;
         }
      }

      private static IShellFolder getDesktopFolder
      {
         get
         {
            IShellFolder ppshf;
            UnManagedMethods.SHGetDesktopFolder(out ppshf);
            return ppshf;
         }
      }
#endregion
#region COMDefinitions
      // Nested Types
      private enum EIEIFLAG
      {
         IEIFLAG_ASPECT = 4,
         IEIFLAG_ASYNC = 1,
         IEIFLAG_CACHE = 2,
         IEIFLAG_GLEAM = 0×10,
         IEIFLAG_NOBORDER = 0×100,
         IEIFLAG_NOSTAMP = 0×80,
         IEIFLAG_OFFLINE = 8,
         IEIFLAG_ORIGSIZE = 0×40,
         IEIFLAG_QUALITY = 0×200,
         IEIFLAG_SCREEN = 0×20
      }

      [Flags]
      private enum ESFGAO
      {
         SFGAO_CANCOPY = 1,
         SFGAO_CANDELETE = 0×20,
         SFGAO_CANLINK = 4,
         SFGAO_CANMOVE = 2,
         SFGAO_CANRENAME = 0×10,
         SFGAO_CAPABILITYMASK = 0×177,
         SFGAO_COMPRESSED = 0×4000000,
         SFGAO_CONTENTSMASK = -2147483648,
         SFGAO_DISPLAYATTRMASK = 0xf0000,
         SFGAO_DROPTARGET = 0×100,
         SFGAO_FILESYSANCESTOR = 0×10000000,
         SFGAO_FILESYSTEM = 0×40000000,
         SFGAO_FOLDER = 0×20000000,
         SFGAO_GHOSTED = 0×80000,
         SFGAO_HASPROPSHEET = 0×40,
         SFGAO_HASSUBFOLDER = -2147483648,
         SFGAO_LINK = 0×10000,
         SFGAO_READONLY = 0×40000,
         SFGAO_REMOVABLE = 0×2000000,
         SFGAO_SHARE = 0×20000,
         SFGAO_VALIDATE = 0×1000000
      }

      [Flags]
      private enum ESHCONTF
      {
         SHCONTF_FOLDERS = 0×20,
         SHCONTF_INCLUDEHIDDEN = 0×80,
         SHCONTF_NONFOLDERS = 0×40
      }

      [Flags]
      private enum ESHGDN
      {
         SHGDN_FORADDRESSBAR = 0×4000,
         SHGDN_FORPARSING = 0×8000,
         SHGDN_INFOLDER = 1,
         SHGDN_NORMAL = 0
      }

      [Flags]
      private enum ESTRRET
      {
         STRRET_WSTR,
         STRRET_OFFSET,
         STRRET_CSTR
      }

      [ComImport, Guid("000214F2-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
      private interface IEnumIDList
      {
         [PreserveSig]
         int Next(int celt, ref IntPtr rgelt, out int pceltFetched);
         void Skip(int celt);
         void Reset();
         void Clone(ref ThumbnailCreator.IEnumIDList ppenum);
      }

      [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("BB2E617C-0920-11d1-9A0B-00C04FC2D6C1")]
      private interface IExtractImage
      {
         void GetLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszPathBuffer, int cch, ref int pdwPriority, ref ThumbnailCreator.SIZE prgSize, int dwRecClrDepth, ref int pdwFlags);
         void Extract(out IntPtr phBmpThumbnail);
      }

      [ComImport, Guid("00000002-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
      private interface IMalloc
      {
         [PreserveSig]
         IntPtr Alloc(int cb);
         [PreserveSig]
         IntPtr Realloc(IntPtr pv, int cb);
         [PreserveSig]
         void Free(IntPtr pv);
         [PreserveSig]
         int GetSize(IntPtr pv);
         [PreserveSig]
         int DidAlloc(IntPtr pv);
         [PreserveSig]
         void HeapMinimize();
      }

      [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214E6-0000-0000-C000-000000000046")]
      private interface IShellFolder
      {
         void ParseDisplayName(IntPtr hwndOwner, IntPtr pbcReserved, [MarshalAs(UnmanagedType.LPWStr)] string lpszDisplayName, out int pchEaten, out IntPtr ppidl, out int pdwAttributes);
         void EnumObjects(IntPtr hwndOwner, [MarshalAs(UnmanagedType.U4)] ThumbnailCreator.ESHCONTF grfFlags, ref ThumbnailCreator.IEnumIDList ppenumIDList);
         void BindToObject(IntPtr pidl, IntPtr pbcReserved, ref Guid riid, ref ThumbnailCreator.IShellFolder ppvOut);
         void BindToStorage(IntPtr pidl, IntPtr pbcReserved, ref Guid riid, IntPtr ppvObj);
         [PreserveSig]
         int CompareIDs(IntPtr lParam, IntPtr pidl1, IntPtr pidl2);
         void CreateViewObject(IntPtr hwndOwner, ref Guid riid, IntPtr ppvOut);
         void GetAttributesOf(int cidl, IntPtr apidl, [MarshalAs(UnmanagedType.U4)] ref ThumbnailCreator.ESFGAO rgfInOut);
         void GetUIObjectOf(IntPtr hwndOwner, int cidl, ref IntPtr apidl, ref Guid riid, out int prgfInOut, ref ThumbnailCreator.IUnknown ppvOut);
         void GetDisplayNameOf(IntPtr pidl, [MarshalAs(UnmanagedType.U4)] ThumbnailCreator.ESHGDN uFlags, ref ThumbnailCreator.STRRET_CSTR lpName);
         void SetNameOf(IntPtr hwndOwner, IntPtr pidl, [MarshalAs(UnmanagedType.LPWStr)] string lpszName, [MarshalAs(UnmanagedType.U4)] ThumbnailCreator.ESHCONTF uFlags, ref IntPtr ppidlOut);
      }

      [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000000-0000-0000-C000-000000000046")]
      private interface IUnknown
      {
         [PreserveSig]
         IntPtr QueryInterface(ref Guid riid, out IntPtr pVoid);
         [PreserveSig]
         IntPtr AddRef();
         [PreserveSig]
         IntPtr Release();
      }

      [StructLayout(LayoutKind.Sequential)]
      private struct SIZE
      {
         public int cx;
         public int cy;
      }

      [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Auto)]
      private struct STRRET_ANY
      {
         // Fields
         [FieldOffset(4)]
         public IntPtr pOLEString;
         [FieldOffset(0)]
         public ThumbnailCreator.ESTRRET uType;
      }

      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
      private struct STRRET_CSTR
      {
         public ThumbnailCreator.ESTRRET uType;
         [MarshalAs(UnmanagedType.ByValArray, SizeConst = 520)]
         public byte[] cStr;
      }

      private class UnManagedMethods
      {
         // Methods
         [DllImport("gdi32", CharSet = CharSet.Auto)]
         internal static extern int DeleteObject(IntPtr hObject);
         [DllImport("shell32", CharSet = CharSet.Auto)]
         internal static extern int SHGetDesktopFolder(out ThumbnailCreator.IShellFolder ppshf);
         [DllImport("shell32", CharSet = CharSet.Auto)]
         internal static extern int SHGetMalloc(out ThumbnailCreator.IMalloc ppMalloc);
         [DllImport("shell32", CharSet = CharSet.Auto)]
         internal static extern int SHGetPathFromIDList(IntPtr pidl, StringBuilder pszPath);
      }
#endregion
   }
}

In the easy family loader project, we use WPF window to show family preview images. We use ListBox to show all the information.

Here is the code in xmal file:

<ListBox Name=”listFileView”  Grid.Row=”2″ Grid.Column=”3″ Grid.ColumnSpan=”3″ ItemsSource=”{Binding}” SelectionMode=”Multiple” ScrollViewer.HorizontalScrollBarVisibility=”Disabled”>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost=”True” />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border Margin=”3″ BorderThickness=”1″ BorderBrush=”SteelBlue” CornerRadius=”2″>
<StackPanel Margin=”3″>
<StackPanel.ToolTip>
<TextBlock Text=”{Binding Path=path}” TextWrapping=”wrap”/>
</StackPanel.ToolTip>
<Image Margin =”3″ HorizontalAlignment=”Center” Source=”{Binding Path=image}” Stretch=”None”></Image>
<TextBlock FontWeight=”Bold” HorizontalAlignment =”Center” Margin =”3″ Text=”{Binding Path=name}”></TextBlock>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

The code for data binding is “ItemsSource=”{Binding}”“, this is a simpler one, of course you can customize it in different ways, and you can also see Source=”{Binding Path=image}” in <DataTemplate>, which will show subitems in the list. Then we need a class to specify the data type for binding if you want to retrieve it sometime (like when user select one, you want to the detail user selected).

This is the class:

public class MyFile
{
public string strName;
public string strPath;
public ImageSource imgSrc;

public MyFile()
{
}

public string name
{
get { return strName; }
set { strName = value; }
}

public string path
{
get { return strPath; }
set { strPath = value; }
}

public ImageSource image
{
get { return imgSrc; }
set { imgSrc = value; }
}
}

Please notice that you have to write properties of the class as the same name in the binding clause (like: Binding Path=image, so we must have “image” property). And when you add items in the list, do like this:

listFileView.DataContext = from file in files
select new MyFile()
{
name = file.name,
path = file.path,
image = file.image,
};

When get data, you can use following code to retrieve information:

foreach (MyFile file in listFileView.SelectItems) { … }

Sometimes we want to use embedded image resource for ribbon button, so we can simplify our deliverables when release the add-ins (don’t need to copy external image files with the assembly). And actually we have the choice, following code will help you know how:

using System;
using System.IO;
using System.Windows.Media;
using System.Windows.Media.Imaging;

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

namespace myRevitApp
{
   [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Automatic)]
   [Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
   public class MyApp : IExternalApplication
   {
      // ExternalCommands assembly path
      static string addInPath = typeof(MyApp).Assembly.Location;
      // Button icons directory
      static string buttonIconsFolder = Path.GetDirectoryName(addInPath);
      public Result OnStartup(UIControlledApplication uiControlledApplication)
      {
         System.Reflection.Assembly myAssembly = System.Reflection.Assembly.GetExecutingAssembly();
         // begin to create custom Ribbon panel and command buttons.
         // create a Ribbon panel.
         RibbonPanel myPanel = uiControlledApplication.CreateRibbonPanel(“My Ribbon Panel”);

         // the first button in the DoorSwing panel, use to invoke the InitializeCommand.
         PushButton pushBtn = myPanel.AddItem(new PushButtonData(“Test”,
                                                          “Test”,
                                                          addInPath,
                                                          typeof(TestCommand).FullName))
                                                          as PushButton;
         pushBtn.ToolTip = “TestCommand”;
         pushBtn.LargeImage = GetEmbeddedImage(myAssembly, “Test.png”);
         pushBtn.Image = GetEmbeddedImage(myAssembly, “Test_small.png”);

         return Result.Succeeded;
      }

      private ImageSource GetEmbeddedImage(System.Reflection.Assembly app, string imageName)
      {
         System.IO.Stream file = app.GetManifestResourceStream(“myRevitApp.” + imageName);
         PngBitmapDecoder bd = new PngBitmapDecoder(file, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);

         return bd.Frames[0];
      }

      public Result OnShutdown(UIControlledApplication application)
      {
         return Result.Succeeded;
      }
   }
}

Notes:

Please make sure add “PresentationCore” and “WindowsBase” .NET references to the project, and add namespace “System.Windows.Media;” and “System.Windows.Media.Imaging;”.

In addition, make sure add the image resources to your project and set their property “Build Action” as “Embedded Resource”.

There is a post to describe the general change for element iterator in http://blog.revitapp.com/2010/06/new-element-iteration-interfaces/.

Here we have a simple example for code change from 2010 to 2011.

First we have 2010 API code:

TypeFilter familyInstanceTypeFilter = app.Create.Filter.NewTypeFilter(typeof(Autodesk.Revit.Elements.FamilyInstance));
CategoryFilter doorCategoryFilter = app.Create.Filter.NewCategoryFilter(BuiltInCategory.OST_Doors);
Filter andFilter = app.Create.Filter.NewLogicalOrFilter(familyInstanceTypeFilter,doorCategoryFilter);
ElementIterator eleIt= doc.get_Elements(andFilter);
while( eleIt.MoveNext())
{
// do something for element
}

Here is the new code in 2011:

FilteredElementCollector collector = new FilteredElementCollector(doc);
ElementClassFilter famInstFilter = new ElementClassFilter(typeof(FamilyInstance));
ElementCategoryFilter doorFilter = new ElementCategoryFilter(BuiltInCategory.OST_Doors);
LogicalOrFilter orFilter = new LogicalOrFilter(famInstFilter, doorFilter);
ICollection<Element> elems = collector.WherePasses(orFilter).ToElements();
foreach (Element e in elems)
{
// do something…
}

We can also simplify the code to:

ICollection<Element> elems = new FilteredElementCollector(doc).OfClass(typeof(FamilyInstance))
.OfCategory(BuiltInCategory.OST_Doors).ToElements();
foreach (Element e in elems)
{
// do something…
}

You can find that the new interface is much better to use and more possibilities.

Following code shows how to create a dimension for a selected curve based element:

namespace myRevitApp
{
   [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
   [Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
   public class TestCommand : IExternalCommand
   {
      public Result Execute(ExternalCommandData commandData, ref string message, Autodesk.Revit.DB.ElementSet elements)
      {
         UIDocument uiDoc = commandData.Application.ActiveUIDocument;
         Application app = commandData.Application.Application;
         Document doc = uiDoc.Document;
         View view = doc.ActiveView;
         ViewType vt = view.ViewType;

         if (vt == ViewType.FloorPlan || vt == ViewType.Elevation)
         {
            Reference eRef = uiDoc.Selection.PickObject(ObjectType.Element, “Please pick a curve based element like wall.”);
            if (eRef != null && eRef.Element != null)
            {
               XYZ dirVec = new XYZ();
               XYZ viewNormal = view.ViewDirection;

               LocationCurve locCurve = eRef.Element.Location as LocationCurve;
               if (locCurve == null || locCurve.Curve == null)
               {
                  TaskDialog.Show(“Prompt”, “Selected element isn’t curve based!”);
                  return Result.Cancelled;
               }

               // location curve needs to be perpendicular to view normal
               XYZ dirCur = locCurve.Curve.get_EndPoint(0).Subtract(locCurve.Curve.get_EndPoint(1)).Normalize();
               double d = dirCur.DotProduct(viewNormal);
               if (d > -0.000000001 && d < 0.000000001)
               {
                  dirVec = dirCur.CrossProduct(viewNormal);
                  XYZ p1 = locCurve.Curve.get_EndPoint(0);
                  XYZ p2 = locCurve.Curve.get_EndPoint(1);
                  XYZ dirLine = XYZ.Zero.Add(p1);
                  XYZ newVec = XYZ.Zero.Add(dirVec);
                  newVec = newVec.Normalize().Multiply(3);
                  dirLine = dirLine.Subtract(p2);

                  p1 = p1.Add(newVec);
                  p2 = p2.Add(newVec);
                  // move the dimension line a little away the element’s curve
                  Line newLine = app.Create.NewLine(p1, p2, true);

                  ReferenceArray arrRefs = new ReferenceArray();
                  Options options = app.Create.NewGeometryOptions();
                  options.ComputeReferences = true;
                  options.DetailLevel = DetailLevels.Fine;
                  GeometryElement element = eRef.Element.get_Geometry(options);
                  GeometryObjectArray geoObjectArray = element.Objects;
                  //enum the geometry element
                  for (int j = 0; j < geoObjectArray.Size; j++)
                  {
                     GeometryObject geoObject = geoObjectArray.get_Item(j);
                     Solid solid = geoObject as Solid;
                     if (solid == null)
                        continue;

                     FaceArrayIterator fIt = solid.Faces.ForwardIterator();
                     while (fIt.MoveNext())
                     {
                        PlanarFace p = fIt.Current as PlanarFace;
                        if (p == null)
                           continue;

                        p2 = p.Normal.CrossProduct(dirLine);
                        if (p2.IsZeroLength())
                        {
                           arrRefs.Append(p.Reference);
                        }
                        if (2 == arrRefs.Size)
                        {
                           break;
                        }
                     }
                     if (2 == arrRefs.Size)
                     {
                        break;
                     }
                  }
                  if (arrRefs.Size != 2)
                  {
                     TaskDialog.Show(“Prompt”, “Couldn’t find enough reference for creating dimension”);
                     return Result.Cancelled;
                  }

                  Transaction trans = new Transaction(doc, “create dimension”);
                  trans.Start();
                  doc.Create.NewDimension(doc.ActiveView, newLine, arrRefs);
                  trans.Commit();
               }
               else
               {
                  TaskDialog.Show(“Prompt”, “Selected element isn’t curve based!”);
                  return Result.Cancelled;
               }
            }
         }
         else
         {
            TaskDialog.Show(“Prompt”, “Only support Plan View or Elevation View”);
         }

         return Result.Succeeded;
      }
   }
}

Powered by WordPress Web Design by SRS Solutions © 2012 Revit APP Blog Design by SRS Solutions