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)
Solved! Go to Solution.
Solved by jeremy_tammik. Go to Solution.
Solved by RPTHOMAS108. Go to Solution.
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).
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
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:
Cool.
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();
}
}
Shared on the blog as well:
Can't find what you're looking for? Ask the community or share your knowledge.