0725/2078

Family Instance Room Phase

Originally Published in

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:

  • Customer makes use of design options and phasing.
  • Most rooms are in the main model, some rooms are in design options.
  • There are three phases: phase_A, phase_B, phase_C.
  • Phase_C is not used, have not checked the impact if deleted.
  • Most architecture is created in phase_A and located in the main model.
  • Some architecture is created in phase_B and located in design options.
  • All family instances and all rooms are created in phase_B.
  • Room volume computation is turned on.
  • Revit’s schedules work correctly, i.e. show the correct room-wise list of family instances.

These are the problems encountered:

  • Sometimes, the family instance Room property returns null, even though the family instance is clearly within a room.
  • Even worse: sometimes, the family instance method get_Room( familyinstance.CreationPhase ) returns null.

Questions:

  • Might there be a problem with the design options?
  • Is there any better workaround than the two approaches mentioned above?
  • What function is the Revit schedule using to successfully determine the room property of family instances?

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:

  • Obviously, first try using the family instance Room property directly.
  • If that fails, try
    foreach(Phase p) { familyinstance.get_Room(p) }
  • Hard part: determine primary options;
    foreach(Room r where r.DesignOption.IsPrimary) {
      r.IsPointInRoom( fi.Location ) }
  • Emergency:
    foreach( Room r ) { r.IsPointInRoom( fi.Location ) }

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!