Extract the names of the rooms separated by a wall

Extract the names of the rooms separated by a wall

Anonymous
Not applicable
1,338 Views
5 Replies
Message 1 of 6

Extract the names of the rooms separated by a wall

Anonymous
Not applicable

Hello, 

 

I use Revit to model my projects, then I export the BOMs to an excel that creates my quotes for clients. However, I am running into a problem: 

 

When I need to demolish (or create) a wall, I would like to see its location, if any, appear in the BOM. 

For example, if I break a wall between the kitchen and the living room, I would like to see "kitchen" or "living room", or even both, next to the surfaces. But I can't find a way to implement this. 

 

Do you have any ideas to help me? 

 

Thank you!

Translated with www.DeepL.com/Translator (free version)

0 Likes
Accepted solutions (2)
1,339 Views
5 Replies
Replies (5)
Message 2 of 6

RPTHOMAS108
Mentor
Mentor

Via the API you can use use Room.GetBoundarySegments

 

This will return a nested list of BoundarySegment from which you can get BoundarySegment.ElementId or BoundarySegment.LinkElementId

 

Then it is just a case or matching the ElementId up with the wall id and pairing with the room(s). 

0 Likes
Message 3 of 6

RPTHOMAS108
Mentor
Mentor
Accepted solution

Some walls will be part of more than two rooms.

 

 Private Function Obj_210629a(ByVal commandData As Autodesk.Revit.UI.ExternalCommandData,
ByRef message As String, ByVal elements As Autodesk.Revit.DB.ElementSet) As Result

        Dim UIDoc As UIDocument = commandData.Application.ActiveUIDocument
        If UIDoc Is Nothing Then Return Result.Cancelled Else
        Dim IntDoc As Document = UIDoc.Document

        Dim FEC As New FilteredElementCollector(IntDoc)
        Dim ECF As New ElementCategoryFilter(BuiltInCategory.OST_Rooms)
        Dim Els As List(Of ElementId) = FEC.WherePasses(ECF).WhereElementIsNotElementType.ToElementIds

        Dim WallRefs As New Dictionary(Of ElementId, List(Of String))
        For i = 0 To Els.Count - 1
            Dim Rm As Room = IntDoc.GetElement(Els(i))

            Dim BSegs As IList(Of IList(Of BoundarySegment)) = Rm.GetBoundarySegments(New SpatialElementBoundaryOptions)
            For x = 0 To BSegs.Count - 1
                Dim BSegs0 As IList(Of BoundarySegment) = BSegs(x)
                For y = 0 To BSegs0.Count - 1
                    Dim Bseg As BoundarySegment = BSegs0(y)
                    If Bseg.ElementId <> ElementId.InvalidElementId Then
                        Dim CurRef As List(Of String)
                        If WallRefs.ContainsKey(Bseg.ElementId) Then
                            CurRef = WallRefs(Bseg.ElementId)
                        Else
                            CurRef = New List(Of String)
                            WallRefs.Add(Bseg.ElementId, CurRef)
                        End If

                        Dim Rm_el As Element = Rm 'Name property of Room is WriteOnly but Name property of Element isn't.
                        Dim RoomName As String = Rm_el.Name
                        If CurRef.Contains(RoomName) = False Then
                            CurRef.Add(RoomName)
                        End If

                    End If

                Next
            Next
        Next

        Dim FECw As New FilteredElementCollector(IntDoc)
        Dim ECFw As New ElementClassFilter(GetType(Wall))
        Dim Elsw As List(Of ElementId) = FECw.WherePasses(ECFw).ToElementIds

        Using Tx As New Transaction(IntDoc, "Name walls based on rooms")
            If Tx.Start = TransactionStatus.Started Then

                For i = 0 To Elsw.Count - 1
                    'Some boundary segments will not relate to walls.
                    If WallRefs.ContainsKey(Elsw(i)) Then

                        Dim El As Element = IntDoc.GetElement(Elsw(i))

                        'Using instance comments parameter for convenience
                        Dim P As Parameter = El.Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS)
                        If P Is Nothing Then Continue For Else

                        Dim Refs As List(Of String) = WallRefs(Elsw(i))
                        Refs.Sort()
                        Dim V As New Text.StringBuilder
                        For j = 0 To Refs.Count - 1
                            If j = Refs.Count - 1 Then
                                V.Append(Refs(j))
                            Else
                                V.Append(Refs(j) & " / ")
                            End If
                        Next
                        P.Set(V.ToString)

                    End If
                Next
                Tx.Commit()
            End If
        End Using
        Return Result.Succeeded
    End Function
Message 4 of 6

jeremy_tammik
Alumni
Alumni
Accepted solution

Very nice sample code snippet indeed! Thank you very much for that.

 

To expand slightly on Richard's rather terse explanation: Richard's code does two things:

  

  • For all rooms, for each bounding wall, determine all the neighbouring rooms and create a dictionary mapping the wall element id to a list of the rooms it bounds
  • For each wall element id in the dictionary created above, add a list of the names of all the rooms it bounds to its comment field 

 

Cool.

 

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 5 of 6

jeremy_tammik
Alumni
Alumni

Ported Richard's very nice VB.NET implementation to C# and The Building Coder samples:

 

https://github.com/jeremytammik/the_building_coder_samples/compare/2022.0.150.14...2022.0.150.15

 

    // Originally implemented by Richard @RPTHOMAS108 Thomas in VB.NET in
    // https://forums.autodesk.com/t5/revit-api-forum/extract-the-names-of-the-rooms-separated-by-a-wall/m-p/10428696

    /// <summary>
    /// For all rooms, determine all adjacent walls,
    /// create dictionary mapping walls to adjacent rooms,
    /// and tag the walls with the adjacent room names.
    /// </summary>
    void TagWallsWithAdjacentRooms( Document doc )
    {
      FilteredElementCollector rooms
        = new FilteredElementCollector( doc )
          .WhereElementIsNotElementType()
          .OfCategory( BuiltInCategory.OST_Rooms );

      Dictionary<ElementId, List<string>> map_wall_to_rooms
        = new Dictionary<ElementId, List<string>>();

      SpatialElementBoundaryOptions opts
        = new SpatialElementBoundaryOptions();

      foreach( Room room in rooms )
      {
        IList<IList<BoundarySegment>> loops 
          = room.GetBoundarySegments( opts );

        foreach (IList<BoundarySegment> loop in loops )
        {
          foreach( BoundarySegment seg in loop )
          {
            ElementId idWall = seg.ElementId;

            if( ElementId.InvalidElementId != idWall )
            {
              if(!map_wall_to_rooms.ContainsKey(idWall))
              {
                map_wall_to_rooms.Add( 
                  idWall, new List<string>() );
              }

              string room_name = room.Name;

              if(!map_wall_to_rooms[idWall].Contains( room_name ) )
              {
                map_wall_to_rooms[ idWall ].Add( room_name );
              }
            }
          }
        }
      }

      using( Transaction tx = new Transaction( doc ) )
      {
        tx.Start( "Add list of adjacent rooms to wall comments" );

        Dictionary<ElementId, List<string>>.KeyCollection ids
          = map_wall_to_rooms.Keys;

        foreach( ElementId id in ids )
        {
          Element wall = doc.GetElement( id );

          Parameter p = wall.get_Parameter(
            BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS );

          if( null != p )
          {
            string s = string.Join( " / ", 
              map_wall_to_rooms[ id ] );

            p.Set( s );
          }
        }
        tx.Commit();
      }
    }

 

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 6 of 6

jeremy_tammik
Alumni
Alumni
0 Likes