In the previous post, we noted that the area parameter for a wall had a numerical value of 283.65 on one hand, but a string representation of ‘26.352 m²’ on the other. The reason for these two different values is that Revit internally works with a fixed set of database units for different measurement types. These internal database units cannot be changed. All raw database values obtained from attributes will always be returned and expected in database units. Some of the internal database length units are imperial. The database unit for length is feet, and areas are stored in square feet. The units used are not the standardised SI units according to the International System of Units SI.

Similarly, if we examine the thickness of a 200 mm wall, e.g. one using the system family ‘Basic Wall’ and the type ‘Generic – 200.0 mm’, its thickness is available in the type parameter ‘width’. It appears to have the value 200 mm in the user interface, if set up to display metric length units. Looking at the actual value of the underlying parameter, however, returns a completely different number, something like 0.6561. 0.6561 feet is 0.6561 * 12 = 7.8732 inches, which corresponds to 7.8732 * 25.4 = 199.97928 millimetres.

The user interface settings affecting the display of units in Revit can be queried through the API. The ProjectUnit SDK sample demonstrates how to do this. The units displayed in the user interface can be queried through the read-only Document.DisplayUnitSystem property. The Parameter.DisplayUnitType property determines how any individual parameter is displayed in the user interface. The DisplayUnitType enumeration lists all the supported display unit types.

It can sometimes be tricky to figure out exactly what units Revit is using internally, for instance when analysing things like point, line and area loads in Revit Structure. For these loads, the units used are in terms of N and m, unlike other parameters and co-ordinates which use feet for all lengths.

The good news, and the main message of this post, is that you do not really have to care what units Revit is using internally. All you need to do is some little research to determine a valid conversion factor. You can enter the unit value for whatever you are interested in in the user interface, and then check what the API reports. It will always be in the same internal units. This can then be used as a conversion factor for that specific unit. It works consistently. Possibly you may refine this depending on the metric or imperial Revit setting, but the factors are the same and consistent.

So the simplest thing to do to determine the conversion factor to use is to set the parameter to 1 in the user interface and then observe the value returned by the API, which gives the conversion factor between the two.

I am appending a small utility class UnitConversion.cs which may be of use in this context, even if just to give you a first impression of how these issues may be handled. I am not saying that this is the optimal solution. It includes some useful constants and stems from the Midas Link Revit Structure sample application which is available including source code on the ADN web site. By the way, the updated MidasLink version for Revit 2009 has just been posted to ADN, in case you are interested. Please excuse the fact that the source code lines exceed the blog display width. To obtain and review the full source code, please simply copy and paste it to notepad or some other editor.

// (C) Copyright 2003-2007 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.Collections;
using System.Windows.Forms;
using System.Diagnostics;
using Autodesk.Revit;
using Autodesk.Revit.Elements;
using Autodesk.Revit.Enums;
using Autodesk.Revit.Parameters;

namespace Revit.MGT
{
    /// <summary>
    /// Unit conversion - convert values from standard units to given units.
    /// </summary>
    public class UnitConversionFactors
    {
        #region Class Member Variables
        /// <summary>
        /// Standard units
        /// </summary>
        private string m_FromUnits;
        /// <summary>
        /// Given units
        /// </summary>
        private string m_ToUnits;
        /// <summary>
        /// true: conversion available for given units
        /// </summary>
        private bool m_RatioSetUpSucceeded;
        /// <summary>
        /// To store length ratio
        /// </summary>
        private double m_LengthRatio;
        /// <summary>
        /// To store point load ratio
        /// </summary>
        private double m_PointLoadRatio;
        /// <summary>
        /// To store point load moment ratio
        /// </summary>
        private double m_PointLoadMomentRatio;
        /// <summary>
        /// To store line load ratio
        /// </summary>
        private double m_LineLoadRatio;
        /// <summary>
        /// To store line moment ratio
        /// </summary>
        private double m_LineMomentRatio;
        /// <summary>
        /// To store area load ratio
        /// </summary>
        private double m_AreaLoadRatio;
        /// <summary>
        /// To store stress ratio
        /// </summary>
        private double m_StressRatio;
        /// <summary>
        /// To store unit weight ratio
        /// </summary>
        private double m_UnitWeightRatio;
        /// <summary>
        /// To store point spring ratio
        /// </summary>
        private double m_PointSpringRatio;
        /// <summary>
        /// To store rotational point spring ratio
        /// </summary>
        private double m_RotationalPointSpringRatio;
        #endregion

        #region Class Public Properties
        /// <summary>
        /// Get FromUnits
        /// </summary>
        public string FromUnits
        {
            get
            {
                return m_FromUnits;
            }
        }
        /// <summary>
        /// Get ToUnits
        /// </summary>
        public string ToUnits
        {
            get
            {
                return m_ToUnits;
            }
        }
        /// <summary>
        /// Get RatioSetUpSucceeded
        /// </summary>
        public bool RatioSetUpSucceeded
        {
            get
            {
                return m_RatioSetUpSucceeded;
            }
        }
        /// <summary>
        /// Get length ratio
        /// </summary>
        public double LengthRatio
        {
            get
            {
                return m_LengthRatio;
            }
        }
        /// <summary>
        /// Get point load ratio
        /// </summary>
        public double PointLoadRatio
        {
            get
            {
                return m_PointLoadRatio;
            }
        }
        /// <summary>
        /// Get point load moment ratio
        /// </summary>
        public double PointLoadMomentRatio
        {
            get
            {
                return m_PointLoadMomentRatio;
            }
        }
        /// <summary>
        /// Get line load force ratio
        /// </summary>
        public double LineLoadForceRatio
        {
            get
            {
                return m_LineLoadRatio;
            }
        }
        /// <summary>
        /// Get line load moment ratio
        /// </summary>
        public double LineLoadMomentRatio
        {
            get
            {
                return m_LineMomentRatio;
            }
        }
        /// <summary>
        /// Get area load ratio
        /// </summary>
        public double AreaLoadRatio
        {
            get
            {
                return m_AreaLoadRatio;
            }
        }
        /// <summary>
        /// Get stress ratio
        /// </summary>
        public double StressRatio
        {
            get
            {
                return m_StressRatio;
            }
        }
        /// <summary>
        /// Get unit weight ratio
        /// </summary>
        public double UnitWeightRatio
        {
            get
            {
                return m_UnitWeightRatio;
            }
        }
        /// <summary>
        /// Get point sprint ratio
        /// </summary>
        public double PointSpringRatio
        {
            get
            {
                return m_PointSpringRatio;
            }
        }
        /// <summary>
        /// Get rotational point spring ratio
        /// </summary>
        public double RotationalPointSpringRatio
        {
            get
            {
                return m_RotationalPointSpringRatio;
            }
        }
        #endregion

        #region Class Constructor
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="lengthUnit">length unit</param>
        /// <param name="forceUnit">forth unit</param>
        public UnitConversionFactors(
            string lengthUnit,
            string forceUnit )
        {
            // Initialize standard factors
            InitializeConversionFactors();
            // Get length conversion factor
            double lenFactor = GetLengthConversionFactor(lengthUnit);
            if (!m_RatioSetUpSucceeded)
            {
                return;
            }
            // Get Force conversion factor
            double forceFactor = GetForceConversionFactor(forceUnit);
            if (!m_RatioSetUpSucceeded)
            {
                return;
            }
            // Set up all the conversion factors
            m_ToUnits = lengthUnit + '-' + forceUnit;
            SetUnitConversionFactors(lenFactor, forceFactor);
        }
        #endregion

        #region Class Implementation
        /// <summary>
        /// Initialize factor to convert internal units to standard ft, kips.
        /// </summary>
        private void InitializeConversionFactors()
        {
            // Internally Revit stores length in feet and other quantities in metric units.
            // Thus the derived unit for force is stored in a non-standard unit: kg-ft/s**2.
            // For example, m_PointLoadRatio below equals 1 (kip) / 14593.90 (kg-ft/s**2)
            m_FromUnits = "ft-kips";
            m_ToUnits = "";
            m_LengthRatio = 1;
            m_PointLoadRatio = 0.00006852176585679176;
            m_PointLoadMomentRatio = 0.00006852176585679176;
            m_LineLoadRatio = 0.00006852176585679176;
            m_LineMomentRatio = 0.00006852176585679176;
            m_AreaLoadRatio = 0.00006852176585679176;
            m_StressRatio = 0.00006852176585679176;
            m_UnitWeightRatio = 0.00006852176585679176;
            m_PointSpringRatio = 0.00006852176585679176;
            m_RotationalPointSpringRatio = 0.00006852176585679176 * 180 / Math.PI;    // Revit uses degrees, Midas uses radians
            m_RatioSetUpSucceeded = false;
        }
        /// <summary>
        /// Get length conversation factor
        /// </summary>
        /// <param name="lengthUnit">length unit type</param>
        /// <returns>length conversation factor</returns>
        private double GetLengthConversionFactor(
            string lengthUnit )
        {
            bool unitAvailable = true;
            double lenFac = 0;
            switch (lengthUnit)
            {
                case "ft":
                    lenFac = 1;
                    break;
                case "in":
                    lenFac = 12;
                    break;
                case "m":
                    lenFac = 0.3048;
                    break;
                case "cm":
                    lenFac = 30.48;
                    break;
                case "mm":
                    lenFac = 304.8;
                    break;
                default:
                    unitAvailable = false;
                    break;
            }
            m_RatioSetUpSucceeded = unitAvailable;
            return lenFac;
        }
        /// <summary>
        /// Get force conversation factor
        /// </summary>
        /// <param name="forceUnit">force unit</param>
        /// <returns>force conversation factor</returns>
        private double GetForceConversionFactor(
            string forceUnit )
        {
            bool unitAvailable = true;
            double forceFac = 0;
            switch (forceUnit)
            {
                case "kips":
                    forceFac = 1;
                    break;
                case "lbf":
                    forceFac = 1000;
                    break;
                case "kN":
                    forceFac = 4.4482216152605;
                    break;
                case "N":
                    forceFac = 4448.2216152605;
                    break;
                case "tonf": // metric tonne
                    forceFac = 4.4482216152605 * 0.101971999794;
                    break;
                case "kgf":
                    forceFac = 4448.2216152605 * 0.101971999794;
                    break;
                default:
                    unitAvailable = false;
                    break;
            }
            m_RatioSetUpSucceeded = unitAvailable;
            return forceFac;
        }
        /// <summary>
        /// Set length and force unit conversation factor
        /// </summary>
        /// <param name="lenFac">length unit factor</param>
        /// <param name="forceFac">force unit factor</param>
        private void SetUnitConversionFactors(
            double lenFac,
            double forceFac )
        {
            m_LengthRatio *= (lenFac);
            m_PointLoadRatio *= (forceFac);
            m_PointLoadMomentRatio *= (forceFac * lenFac);
            m_LineLoadRatio *= (forceFac / lenFac);
            m_LineMomentRatio *= (forceFac);
            m_AreaLoadRatio *= (forceFac / lenFac / lenFac);
            m_StressRatio *= (forceFac / lenFac / lenFac);
            m_UnitWeightRatio *= (forceFac / lenFac / lenFac / lenFac);
            m_PointSpringRatio *= (forceFac / lenFac);
            m_RotationalPointSpringRatio *= (forceFac * lenFac);
        }
        #endregion
    }
}

Comments

9 responses to “Units”

  1. Henrik Bengtsson Avatar
    Henrik Bengtsson

    Hello!
    I have just discovered these conversion problems when i started to work with inserting columns in different locations, using the Geometry.XYZ class and by changing the parameter values FAMILY_BASE_LEVEL_PARAM and FAMILY_TOP_LEVEL_PARAM.
    All these use Foot as internal unit which makes it necessary use a conversion function like mmToFoot and opposite… It took a while to figure that out but now it roles just fine… The helper class stated above will help a lot…

  2. Hi Henrik,
    Thank you for the comment and I’m glad it works for you now! Yes, no problem, and easy to do, once you’ve figured it out.
    Best regards,
    Jeremy

  3. Hello Jeremy,
    I need create walls(in meters dimensions)with API Revit,how can I convert feet unit to meters?
    Is there any funtion to determinate the type of units(Meters),in the proyect?
    Best regards

  4. Dear Berria,
    To convert feet to meters, simply multiply by a constant factor. An example is provided in the Revit API introduction labs, for example in the external command defined in Lab2_0_CreateLittleHouse:
    const double MeterToFeet = 3.2808399;
    //
    // determine the four corners of the rectangular house:
    //
    double width = 7 * MeterToFeet;
    double depth = 4 * MeterToFeet;
    The code is available for download in
    http://thebuildingcoder.typepad.com/blog/files/rac_labs_20081117.zip
    How to determine the units displayed in the user interface is demonstrated by the ProjectUnit SDK sample mentioned above.
    Cheers, Jeremy.

  5. Hi Jeremy,
    Thank you for the comment, I’m glad it works good.
    Best regards,
    Berria

  6. Hi Jeremy,
    Thanks for the help. I am a newbie in Revit API, can you show me some information about Revit element(slab, roof, floor) and family instance(column). Every time when user try to insert a slab, beam, column, they need to create a profile(contain the XYZ coordinate) of the element. eg: newfamilyinstance(XYZ,…)
    But what does the Z value mean? In 3D model, the z value usually is the displacement along the z axis, but in Revit, what does this z value means?
    Any sample regarding to the insertion of a new slab? I have go through the “Revit 2011 API Developer Guide.pdf”, but not much help because it didn’t mentioned how to define a slopearrow and angle argument in newslab() method.
    Besides that, when using a newfloor() method, i have defined my floor level on level 2, yes, the floor is created on level 2 with the level property set to level 2, but the height offset is set to -10″(which means that the slab now is offset to level 1).
    Does this again deal with the z value?
    I think i need to concentrate more on the XYZ value of each revit element in order to insert the element in the correct location before i proceed to the next. Any idea for this.
    Thanks.
    Regards,
    BSYap
    Thanks for your guidance through these days.

  7. Dear Bsyap,
    I believe that in some cases the Z value of the given XYZ point is ignored, and the elevation information is defined by the level and offset parameters instead. It depends on many things, such as the type of element and the specific overload of the NewFamilyInstance method that you choose.
    Cheers, Jeremy.

  8. Estimado amigo:
    La Unica forma de agradecerte, lo que nos enseñas, es transmitiendo lo que nos das. El Viernes 22 de Noviembre del 2013 voy a dar un curso de Revit API en c# en ARUP Madrid. Lo he organizado en 60 horas y voy a desarrollar el manual de REVIT API en 2012 puesto que esta en pdf y me es mas sencillo manejarlo.
    Perdona que no te escriba en tu idioma, ya voy a empezar con las clases de Ingles y poco a poco aprendere.
    Un saludo desde Madrid y muchisimas gracias por tu trabajo.

  9. Hola Javier,
    Muchas gracias para tu noticia y apreciacion.
    Me gusta mucho lo que dices!
    Por otra parte, seria una lastima dar el curso basado su Revit 2012.
    El developer guide para Revit 2013 y 2014 tambien se pueden encontrar en forma PDF:
    http://thebuildingcoder.typepad.com/blog/2013/10/revit-2013-api-developer-guide-pdf.html
    http://thebuildingcoder.typepad.com/blog/2013/11/revit-2014-developer-guide-pdf.html
    Saludos desde la Suiza y mucha suerte para tu curso!
    Jeremy.

Leave a Reply to JavierCancel reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading