Family Instance Room Phase

We already looked at some examples of confusion due to the interaction of phases with the room property on family instances. Here is a new aspect of this encountered and solved by Patrick Rosendahl of SOLAR-COMPUTER GmbH, who kindly explains the issue and its resolution like this:

Problem: I am having a problem with the FamilyInstance Room property. I looked at the discussion of issues with the Room property and its phase dependency but have not been able to solve it yet.

This is the situation:

These are the problems encountered:

Questions:

As a workaround, I thought of calling the get_Room method on the family instance in a loop over all available phases in the project, and making use of the document PointInRoom method if that fails.

Solution: Here is a promising start for a solution that I am currently exploring:

Here is the actual method implementating this that I am currently working with, including some todo items left as an exercise for the reader ;)

public static Room DetermineRoom( Element el )
{
  FamilyInstance fi = el as FamilyInstance;
 
  if( fi == null )
  {
    return null;
  }
 
  // As simple as that?
 
  try
  {
    if( fi.Room != null )
    {
      //Debug.WriteLine("fi.Room != null");
      return fi.Room;
    }
  }
  catch
  {
  }
 
  // Try phasing
 
  Room r = null;
 
  foreach( Phase p in el.Document.Phases )
  {
    try
    {
      // TODO should check fi.GetPhaseStatus 
      // instead of provoking an exception
 
      r = fi.get_Room( p );
 
      if( r != null )
      {
        //Debug.WriteLine("fi.get_Room( " 
        //  + p.Name + ") != null");
 
        return r;
      }
    }
    catch
    {
    }
  }
 
  LocationPoint lp = el.Location as LocationPoint;
 
  if( lp != null )
  {
    // Try design options
 
    List<Element> roomlst = get_Elements(
      el.Document, typeof( Room ) );
 
    // Try rooms from primary design option
 
    foreach( Element roomel in roomlst )
    {
      Room priroom = roomel as Room;
 
      if( priroom == null )
        continue;
 
      if( priroom.DesignOption == null )
        continue;
 
      if( priroom.DesignOption.IsPrimary )
      {
        // TODO should check whether priroom 
        // and el phasing overlaps
 
        if( priroom.IsPointInRoom( lp.Point ) )
        {
          //Debug.WriteLine(
          //  "priroom.IsPointInRoom != null");
 
          return priroom;
        }
      }
    }
 
    // Emergency: try any room
 
    foreach( Element roomel in roomlst )
    {
      Room room = roomel as Room;
 
      if( room == null )
        continue;
 
      // TODO should check whether room 
      // and el phasing overlaps
 
      if( room.IsPointInRoom( lp.Point ) )
      {
        //Debug.WriteLine(
        //  "room.IsPointInRoom != null");
        return room;
      }
    }
  }
 
  // Nothing found
 
  return null;
}

I think this approach provides is a good starting point. A more complete solution might possibly take the phase and design option as arguments. In my context, the function above rarely returns a non-primary design option room.

Many thanks to Patrick for his research and sharing this solution!