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:

  • 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!


Comments

6 responses to “Family Instance Room Phase”

  1. Hi Jeremy, hi Patrick,
    if a FamilyInstance is line-based, its Location may be a LocationCurve instead of a LocationPoint.
    In this case it may be useful to test if the middle point of its curve is in room.
    Bye,
    Rudolf

  2. Hi Jeremy,
    I wanted to ask a question, not related to your above post. However I believe you have handled this before. i am looking for some guidance.
    I have some walls in a drawing, and I have command that will insert beams across the walls. When the beams are inserted I would like to modify their analytical line but in order to do that I need to get elementsatjoin for the beam, which returns nothing. However when the command ends I can select the beam I just inserted and get the elementsatjoin then. I have already tried to regenerate the drawing in my code but this still does not help. Do you have any insight? How can you get elementsatjoin form a beam that you just inserted through code?

  3. Sergey Babitsky Avatar
    Sergey Babitsky

    in some situations there are no Location at all :(
    then we must check geomerty

  4. Dear Rudolf,
    … or the entire curve, even, or whether the curve intersects the room boundary, or whatever.
    Cheers, Jeremy.

  5. Dear Sergey,
    That is the way it is right now, unfortunately…
    Cheers, Jeremy.

  6. Dear Richard,
    Yes, you definitely need to regenerate in between. If that is not enough, it sometimes helps to split the operation into several separate transactions and commit them in between as well:
    http://thebuildingcoder.typepad.com/blog/2010/01/extra-transaction-required.html
    http://thebuildingcoder.typepad.com/blog/2011/01/setting-duct-width-and-height-requires-regeneration.html
    Cheers, Jeremy.

Leave a Reply to RichardCancel reply

Discover more from Autodesk Developer Blog

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

Continue reading