Bottom Face of a Wall

We already went into quite a bit of detail analysing the geometry of walls and other elements, but the topic keeps cropping up again anyway.
An overview of the preceding posts on this topic is given in the discussion of

cylindrical columns
.
Here is a case handled by Joe Ye which I thought might complement the previous posts on this topic, since it is so simple and minimal.

Question:
How can I find the bottom face of a wall?

Answer:
We can query the wall for its solid geometry using the Element.Geometry property, which is accessed by the get_Geometry method in C#.
From the returned solid, all faces can be accessed.
The bottom face of the wall has a normal vector equal to (0,0,-1), and in most cases this is the unique for the bottom face.
So we just iterate over all faces, and stop when we find one whose normal vector is vertical and has a negative Z coordinate.

I implemented a new external command named CmdWallBottomFace to demonstrate this.
Here is the code of its Execute method.
As always, it returns Failed even if it did in fact succeed, so that no changes are registered in the BIM, since the command does nothing to modify the model:


Application app = commandData.Application;
Document doc = app.ActiveDocument;
 
string s = "a wall, to retrieve its bottom face";
 
Wall wall = Util.SelectSingleElementOfType(
  doc, typeof( Wall ), s ) as Wall;
 
if( null == wall )
{
  message = "Please select a wall.";
}
else
{
  Options opt = app.Create.NewGeometryOptions();
  GeoElement e = wall.get_Geometry( opt );
 
  foreach( GeometryObject obj in e.Objects )
  {
    Solid solid = obj as Solid;
    if( null != solid )
    {
      foreach( Face face in solid.Faces )
      {
        PlanarFace pf = face as PlanarFace;
        if( null != pf )
        {
          if( Util.IsVertical( pf.Normal, _tolerance )
            && pf.Normal.Z < 0 )
          {
            Util.InfoMsg( string.Format(
              "The bottom face area is {0},"
              + " and its origin is at {1}.",
              Util.RealString( pf.Area ),
              Util.PointString( pf.Origin ) ) );
            break;
          }
        }
      }
    }
  }
}
return CmdResult.Failed;

When the command is executed and a wall selected, the area and origin point of its bottom face is reported in a message box and in the Visual Studio debug output window:

Wall bottom face area and origin


The bottom face area is 265.82,
and its origin is at (30.76,20.57,-9.84).

Here is
version 1.1.0.44
of the complete Visual Studio solution including the new command.

Thank you very much Joe for this answer!


Comments

8 responses to “Bottom Face of a Wall”

  1. Hi Jeremy,
    I am using Revit since 7 version , but i never make some programming work in it.
    Can you help me?
    1.What language i must to use ?
    2.What i need to start programming?
    3.Some useful links for biginer!
    I am interesting in FreeForm programming.
    To make Revit do something like this (it was made in Maya (MEL):http://www.flickr.com/photos/daniloarsic/
    http://www.flickr.com/photos/danielwidrig
    Big Thanks

  2. Dear Roman,
    I am glad to hear of your interest. Regarding your specific questions:
    1. You can use any .NET language. C# or VB is easiest and recommended.
    2. VSTA or Visual Studio Tools for Applications is built in to the Revit product. The recommended external development environment is Microsoft Visual Studio. You can also use the Express edition, which is free.
    3. The Building Coder blog includes a category named ‘Getting Started’ which includes many topics that are useful for novice Revit API users. A succinct overview of helpful additional resources for getting started is provided in
    http://thebuildingcoder.typepad.com/blog/2009/04/getting-started-with-the-revit-2009-api.html
    It is written for the Revit 2009 API, but most of it applies equally well to Revit 2010.
    Good luck and cheers, Jeremy.

  3. Hi, Jeremy,
    I think this way to get bottom is not exact, if the wall has door, It will get two bottom faces which is the wall bottom face splitted by door.
    thanks,
    Jinshou.

  4. Dear Jinshou,
    You are absolutely right, and all kinds of exceptional and not so exceptional cases will need special handling for production use.
    Above all, you need lots of testing, and automated testing, and an ever-expanding collection of test cases to insure against regression.
    Cheers, Jeremy.

  5. Hi, Jeremy,
    I found that the Revit 2012 API has some problems.Like that if the wall has one door, the bottom face should be split into two bottom faces by door, but by API get wall’s solid and get solid’s faces, only can get one bottom face, it should be two bottom faces. And if more than one door also can only get one bottom face.
    thanks,
    Jinshou.

  6. Dear Jinshou,
    I believe the Revit development team might disagree with you there.
    Why should there be two faces? One single face may contain multiple loops, both disconnected outer loops and inner hole loops.
    The bottom face of a wall is probably always just one single face, as long as the wall has a flat bottom at all, regardless of any doors it may contain.
    That one face may have holes in it, if the door really breaks through the bottom of the wall.
    Also, the door may be a little bit up in the wall, off the floor, with no break at all in the bottom face.
    Check out that one face and see whether it contains multiple loops.
    Cheers, Jeremy.

  7. Hi, Jeremy,
    I’m sorry, I made a mistake.
    As you said, after add a doors into the wall, it still one face, but the face contains multiple loops.
    Thanks,
    Jinshou.

  8. Dickins John Avatar
    Dickins John

    Hi Jeremy,
    I am trying to get the bottom face of a Beam (structural Framing). In some beams I am getting bottom face when I use Normal.Z<0, whereas in some beams it is giving top face when I use Normal.Z<0. In such cases if I use Normal.Z>0, it is giving me the required bottom face. Can you explain why this happens? kindly help me.
    Here is my code:
    //methdo to get the bottom face of element passed to it
    public static List GetBottomFace(Element ele, Document doc)
    {
    try
    {
    List faces = new List();
    if (ele is Floor)
    {
    IList bottomFaces = HostObjectUtils.GetBottomFaces((Floor)ele);
    foreach (Reference refer in bottomFaces)
    {
    faces.Add((doc.GetElement(refer)).GetGeometryObjectFromReference(refer) as Face);
    }
    return faces;
    }
    Options opt = new Options();
    opt.DetailLevel = ViewDetailLevel.Fine;
    GeometryElement geoEle = ele.get_Geometry(opt);
    IEnumerator enu = geoEle.GetEnumerator();
    enu.Reset();
    while (enu.MoveNext())
    {
    Solid solid = enu.Current as Solid;
    if (null != solid)
    {
    foreach (Face face in solid.Faces)
    {
    PlanarFace pf = face as PlanarFace;
    if (null != pf)
    {
    if (pf.Normal.Z < 0)
    {
    faces.Add(face);
    return faces;
    }
    }
    }
    }
    }
    return null;
    }
    catch
    {
    throw new Exception();
    }
    }

Leave a Reply to RomanCancel reply

Discover more from Autodesk Developer Blog

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

Continue reading