Element Materials

I recently heard several queries on how to access the surface material of a wall or other building element. There are several different ways to access materials defined on building elements. One method is discussed in the section 16.3 Element Material in the
Revit 2009 API Developer Guide.
Another method goes through the geometry and retrieves the material associated with each face. We will discuss the latter approach in this and the next post.

Retrieving the material associated with element geometry is actually very simple, similar to and simpler than the geometrical traversal that we looked at in the post on

Wall Dimensions
.
The geometry displayed in Revit generally has a solid associated with it, each solid has a set of faces, and each face has a material, which can be queried using its MaterialElement property.
Therefore, we can simply query the building element for its geometry, traverse that, pick out all solids, ask each one for its faces, and list their materials. Here is the code to do so:


using System;
using System.Collections.Generic;
using System.Diagnostics;
using Autodesk.Revit;
using Autodesk.Revit.Elements;
using Autodesk.Revit.Geometry;
using CmdResult = Autodesk.Revit.IExternalCommand.Result;
using RvtElement = Autodesk.Revit.Element;
using GeoElement = Autodesk.Revit.Geometry.Element;
 
namespace BuildingCoder
{
  class CmdGetMaterials : IExternalCommand
  {
    public List<string> GetMaterials( GeoElement geo )
    {
      List<string> materials = new List<string>();
      foreach( GeometryObject o in geo.Objects )
      {
        if( o is Solid )
        {
          Solid solid = o as Solid;
          foreach( Face face in solid.Faces )
          {
            string s = face.MaterialElement.Name;
            materials.Add( s );
          }
        }
      }
      return materials;
    }
 
    public CmdResult Execute(
      ExternalCommandData commandData,
      ref string message,
      ElementSet elements )
    {
      Application app = commandData.Application;
      Document doc = app.ActiveDocument;
      Selection sel = doc.Selection;
      Options opt = app.Create.NewGeometryOptions();
      string msg = string.Empty;
      int i, n;
 
      foreach( RvtElement e in sel.Elements )
      {
        GeoElement geo = e.get_Geometry( opt );
        List<string> materials = GetMaterials( geo );
 
        msg += "n" + Util.ElementDescription( e );
 
        n = materials.Count;
        if( 0 == n )
        {
          msg += " has no materials.";
        }
        else
        {
          i = 0;
          msg += string.Format(
            " has {0} material{1}:",
            n, Util.PluralSuffix( n ) );
 
          foreach( string s in materials )
          {
            msg += string.Format(
              "n  {0} {1}", i++, s );
          }
        }
      }
      if( 0 == msg.Length )
      {
        msg = "Please select some elements.";
      }
      Util.InfoMsg( msg );
      return CmdResult.Succeeded;
    }
  }
}

Here is the little house sample, consisting of four walls, a floor, a roof, a door and two windows, which we can run this code on:

Little House

Here is the result of selecting all elements of the little house and running the command:


Walls  has 17 materials:
0 Default Wall
1 Default Wall
2 Default Wall
3 Default Wall
. . .
16 Default Wall
Walls  has 6 materials:
0 Default Wall
1 Default Wall
. . .
5 Default Wall
Walls  has 6 materials:
0 Default Wall
1 Default Wall
. . .
5 Default Wall
Walls  has 6 materials:
0 Default Wall
. . .
5 Default Wall
Doors M_Single-Flush  has no materials.
Windows M_Fixed  has no materials.
Windows M_Fixed  has no materials.
Floors  has 6 materials:
0 Default Roof
1 Default Roof
. . .
5 Default Roof
Roofs  has 12 materials:
0 Default Roof
1 Default Roof
. . .
11 Default Roof

Notice that the sample in its current state does not report any materials for the door or windows. This is because these elements are family instances, and their geometry is nested in a geometry instance, which the current code does not traverse into. In a future instalment, we will rectify that to list the materials nested in family instances as well.

I am adding the complete Visual Studio solution here. This version 1.0.0.5 includes all commands we discussed so far: CmdListWalls, CmdRelationshipInverter, CmdWallDimensions, CmdFilterPerformance and the new CmdGetMaterials.


Comments

8 responses to “Element Materials”

  1. Great topic Jeremy…
    I’ve often wondered about some of the interaction between the different Materials in an element…
    In a multi-layered wall, you need to get the CompoundLayerStructure to get at the interior/exterior wall material – do these translate out to the Interior/Exterior Wall faces?
    Also, I presume when you “paint” a material onto a wall face it picks it up with the approach listed above?
    Thanks – Matt

  2. Hi Matt,
    Thanks for your appreciation! Yes, for a multi-layered wall you would look at the CompoundLayerStructure, and I would assume that each layer would produce its own faces with its own material assignments, some of them corresponding to the interior and exterior wall faces … I have not tried it out, though.
    And yes, in response to your second assumption above, ‘when you “paint” a material onto a wall face it picks it up with the approach listed above’ … that is true as far as I know.
    Both of these might be topics for future posts.
    Best regards,
    Jeremy

  3. Hi Jeremy,
    I got a question…
    Can you get the area of materials associated to the face also?
    Cheers!

  4. Hi Pierre,
    Thank you very much for resubmitting your email question as a comment to the post! I prefer questions and answers becoming part of a public dialogue, as much as possible.
    If you look where the materials come from in the method GetMaterials, you will note that each material is associated with a face. The Face class has a property Area, so you can determine the area of each material per face. If you want the total area of the material, you can accumulate all those areas for each one. This could be designed similarly to the volume summation presented in
    http://thebuildingcoder.typepad.com/blog/2009/02/compound-wall-layer-volumes.html
    And bear in mind that all areas are in square feet.
    Cheers, Jeremy.

  5. Hi Jeremy,
    …another question.
    Can you get the volume of materials associated to the face also?
    Well ,the face don’t have a volume but the materials associated to this face is also associated to an Element,so it has a volume.
    Can I have the volume of element / material which is projected on the face ?
    Cheers
    Max

  6. Dear Max,
    Thank you for your query, although it appears a bit confusing to me.
    As you say, the face has no volume, just an area. If you are applying material evenly to the face and know its thickness, then you can calculate the volume from that.
    If the material is represented by some element, then you can query that element for its geometry and calculate the volume from that.
    The last part of the question is still more confusing, because if you project anything at all onto a face, it will once again become two-dimensional and thus not have any volume.
    Cheers, Jeremy.

  7. that’s is very cool thanks for the tip.

  8. Dear Nina,
    Thank you very much for the appreciation, it’s a pleasure!
    Cheers, Jeremy.

Leave a Reply

Discover more from Autodesk Developer Blog

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

Continue reading