Family Instance Room Phase
Originally Published inWe 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!