Revit APP Blog

Information on Revit APP.

Browsing Posts published by Bruce

All materials in a document is stored in doc.Settings.Materials (doc is the pointer of the document). You can get all available materials through this property.

Material’s specified properties:

Color The color of the material.
CutPattern The cut pattern of the material.
CutPatternColor The cut pattern color of the material.
Glow Whether the material can glow.
RenderAppearance The rendering appearance property of the material.
Shininess The shininess of the material.
Smoothness The smoothness of the material.
SurfacePattern The surface pattern of the material.
SurfacePatternColor The surface pattern color of the material.
Transparency The transparency of the material.

You can modify a meterial through these properties. Of course, you can also add/insert/remove materials for doc.Settings.Materials.

Load family is a frequent action when we use Revit. However, try to find a desire family is frustrated because the folder structure is too complex. This tool is trying to let you find your family easily. It will filter the path name, then the file name, and it’s quite easy to use. Take a look at the demo vedio in following link to see how easy it is:-)

V0.3:
Add:
- Support 3 level of thumbnail sizes (Large, Medium, Small)
- Support hide file name when thumbnail is shown
- Support file name only (don’t show thumbnail to fasten the speed)
- Move two ribbon buttons into one split button to save space

Fix:
- Error when copy/paste foler path when setting searching root path

The link: http://en.revitapp.com/easy_family_loader.html

An old post http://blog.revitapp.com/2010/05/autodesk-revit-api-overview/ descibed what we can do with Revit API. Let’s recall the concept:

What Can I Do With the Autodesk Revit API?

The following are general areas where the API is suitable:

  • Creating add-ins to automate repetitive tasks in the Autodesk Revit user interface
  • Enforcing project design standards by checking for errors automatically
  • Extracting project data for analysis and to generate reports
  • Importing external data to create new elements or parameter values
  • Integrating other applications, including analysis applications, into Autodesk Revit products
  • Creating Autodesk Revit project documentation automatically

From the items, we can see that there actually are still restrictions for us to develop Revit addins applications. The main point is, most disabilities of Revit cannot be achieved by Revit API. That’s to say, if user can’t do the work manually in Revit, then most probably it also can’t be accomplished by Revit API. However, I think Revit API would be able to extend much in the future and real extend Revit capabilities.

So this doc only wants to help an API developer quickly judge the feasiblity of a requirement. Anyway, keep in mind that this is not always true, sometimes there is workaround for us.

We know that family can be inserted into a project, sometimes we want to specify a special point when we insert the family. We can pass the point (XYZ) as the first parameter of FamilyInstanceCreationData when call Document::NewFamilyInstances.

However, how can you know whether the insertion point is the right place you input? You can call FamilyInstance::Location to get the insertion point, but in Revit, you can use following method to know what exactly the insertion point is:

Add two perpendicular module lines in a plan view, drag a family into the view and move the mouse until two model lines are highlighted, click mouse to put down the family. The cross point of the two lines is the insertion point of this family. You can know the coordinate through “Manage” tab -> “Project Location” panel -> Coordinates -> Report Shared Coordinates.

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
   }
}

Currently Revit doesn’t support multiple selection in Material edition dialog, so when user wants to delete multiple materials, he/she has to select one, delete, then one again and again. It’s really tedious and waste lots of time. This little tool will help you a lot when you want to delete multiple materials.

The link is: http://en.revitapp.com/materialstool.html

Tips: try your best to use  Parameter(BuiltInParameter) when get parameter from element.

Revit as a parametric product, we will frequently use element parameters (retrieve, modify) to achieve our own goals.

There are several ways to get Parameter from an element:
Parameter(BuiltInParameter)
Parameter(Definition)
Parameter(Guid)
Parameter(String)

All almost similar except the last one which has the least performance because it will iterate all parameters in this element until find the parameter with the specified name. However, in most cases BuiltInParameter is more meaningful for us and easy to get, so it’s better for us to use BuiltInParameter to get parameter. In addition, use this can avoid localization problem, so you don’t need to write different code for different languages.

If you do need to use string to retrieve parameter, go ahead. But keep in mind that there is another property ParametersMap. If you want to search several parameters from one element (all use string as keyword), get this map first and use the map to get parameter would be faster.

Chinese Version: 点这里

When you develop your own application based on Revit API, there are many things that you need to know which won’t be included in the API help book or somewhere else. We call them tips. We plan to write down the tips we found or other friends found to help API developers.

Today we want to share one tip:

It’s better to write one Document::regenerate in one transaction just before its commit, and remember to re-get Elements, Views etc. after the regenerate if you put these code in one class/function.

Reason:

When document regeneration, many things may be changed including the memory allocated for the Elements/Views etc. So if you still use the Elements/View etc reference after the regenerate, things may go beyond your expectation. Just keep in mind that, the ElementId in document is stable, but the Element reference is not. Simplify the logic in one transaction will make your code easy to understand and less chance to encounter problems, sometimes one change will not be real until one regenerate. So if you found you change doesn’t work, maybe you need call regenerate.

Chinese Version: 点这里

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