Curtain wall dimensions with API and Dynamo

In this post I want to show a method that allows to automatically dimension curtain walls in Revit, with the result as on an image above.
First let’s assume that our input data are: a curtain wall, a line specifying location of the future dimension line and a view. In order to create a new dimension line in Revit we use such code:

doc.Create.NewDimension(view,line,refArray);

Where “doc” is our Revit document, “view” a view where we want to draw the dimension, “line” dimension placement line and “refArray” a list references to all measured objects/lines.

To get result as above we need to find two kinds of references:
-the ones that point to side edges of the wall
-the ones that point to vertical grid lines

The first ones will be collected directly from the wall geometry. In order to do that we need to find a Geometry Object of our wall, like so:

Options options = this.Application.Create.NewGeometryOptions();
options.ComputeReferences = true;
options.IncludeNonVisibleObjects = true;

Where”w” is the wall and “options” is a helper object containing parameters of the geometry extraction. It is important here to set it so it takes into account non visible objects and object references.

Next we iterate the geoElement to find solid objects. Then we check direction of all the solid’s faces (normal vector). If it is parallel to the direction of the dimension line we can add this face’s reference to the list. (refArray). It would look like that:

foreach(GeometryObject obj in geoElement){
  Solid s = obj as Solid;
  if(s!=null) {
    foreach(Face f in s.Faces){
      PlanarFace pf = f as PlanarFace;
      if(pf!=null) {
        XYZ faceNormal = pf.FaceNormal;
        if(isParallel(faceNormal,line.GetEndPoint(1)-line.GetEndPoint(0))) {
          refArray.Append(f.Reference);
        }
      }
    }
  }
}

Now we are gonna collect references to the vertical grid lines of the wall. We can do it using such code:

ICollection gridIds = w.CurtainGrid.GetVGridLineIds();

The above function returns ids of the grid lines, not the objects themselves. Therefore we have to find them in the document (using the ids) and then query them for any line geometries. References to those lines are added again to the list. Like so:

foreach(ElementId gridId in gridIds) {
  CurtainGridLine gridLine = doc.GetElement(gridId) as CurtainGridLine;
  if(gridLine!=null) {
    GeometryElement gridGeo = gridLine.get_Geometry(options);
    foreach(GeometryObject obj in gridGeo) {
      Line l = obj as Line;
      if(l!=null) refArray.Append(l.Reference);
    }
  }
}

Code for the entire function could look like this:

private void horizontalDimension(Document doc, View view, Wall w, Line line) {
                        
  ReferenceArray refArray = new ReferenceArray();
            
  Options options = this.Application.Create.NewGeometryOptions();
  options.ComputeReferences = true;
  options.IncludeNonVisibleObjects = true;
            
  GeometryElement geoElement = w.get_Geometry(options);
            
  //get side references            
  foreach(GeometryObject obj in geoElement){
    Solid s = obj as Solid;
    if(s!=null) {
      foreach(Face f in s.Faces){
        PlanarFace pf = f as PlanarFace;
        if(pf!=null) {
          XYZ faceNormal = pf.FaceNormal;
          if(isParallel((faceNormal,line.GetEndPoint(1)-line.GetEndPoint(0))) {
            refArray.Append(f.Reference);
          }
        }
      }
    }
  }
            
  //get grid references            
  ICollection<ElementId> gridIds = w.CurtainGrid.GetVGridLineIds();
            
  foreach(ElementId gridId in gridIds) {
    CurtainGridLine gridLine = doc.GetElement(gridId) as CurtainGridLine;
    if(gridLine!=null) {
      GeometryElement gridGeo = gridLine.get_Geometry(options);
      foreach(GeometryObject obj in gridGeo) {
        Line l = obj as Line;
        if(l!=null) refArray.Append(l.Reference);
      }
    }
  }
            
  using(Transaction t = new Transaction(doc,"horizontal dimension")) {                      
    t.Start();
    doc.Create.NewDimension(view,line,refArray);
    t.Commit();
  }
}

And this would be a Dynamo version, in Python:

import clr

#The inputs to this node will be stored as a list in the IN variables.
wall = UnwrapElement(IN[0])
lineElement = UnwrapElement(IN[1])
view = UnwrapElement(IN[2])

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Transactions import TransactionManager
from RevitServices.Persistence import DocumentManager

def isParallel(v1,v2):
  return v1.CrossProduct(v2).IsAlmostEqualTo(XYZ(0,0,0))

line = lineElement.GeometryCurve
lineDir = line.GetEndPoint(1) - line.GetEndPoint(0)

refArray = ReferenceArray()

doc = DocumentManager.Instance.CurrentDBDocument

options = Options()
options.ComputeReferences = True
options.IncludeNonVisibleObjects = True

geoElement = wall.get_Geometry(options)

#get side references
for obj in geoElement:
  if isinstance(obj,Solid):
    for f in obj.Faces:
      faceNormal = f.FaceNormal
      if isParallel(faceNormal,lineDir):
        refArray.Append(f.Reference)
    
    
#get grid references
for id in wall.CurtainGrid.GetVGridLineIds():
  gridLine = doc.GetElement(id)
  gridGeo = gridLine.get_Geometry(options)
  for obj in gridGeo:
    if isinstance(obj,Line):
      refArray.Append(obj.Reference)


TransactionManager.Instance.EnsureInTransaction(doc)
doc.Create.NewDimension(view, line, refArray)
TransactionManager.Instance.TransactionTaskDone()

#Assign your output to the OUT variable.
OUT = 0
Posts created 30

9 thoughts on “Curtain wall dimensions with API and Dynamo

  1. Hi,

    Thanks for sharing this script! It’s very handy for complex curtain walls. Though is it possible to use it for sloped glazing? I’ve tried to use it with a simple roof, but no result. I’ve also tried to rewrite the python script, but my lack of knowledge got me to reply to this forum. Hopefully you can help me!

  2. Thank you for your code,
    for some reason, It doesn’t work for me, it gives me an error on the python script command on Dynamo.
    It says, IronpythonEvaluator.EvaluateIronPythonScript
    operation Failed
    Traceback( most recent call last(:
    file””, line 6, in
    indexErrorL index out of range: 2

    1. Hi MBI,
      it seems to me it is a python node input error. Have you added necessary number of inputs to the code node?

  3. Great! thank you so much for sharing this.

    I was trying to make this action on several walls at the same time.
    I’ve tried to iterate with another for loop inserting each time only one wall and its corresponding line, but for some reason, it only puts dimensions on the first wall.
    any suggestions?

    I would send a picture if possible…

Leave a Reply to Venkatesh Cancel reply

Your email address will not be published.

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top