Create Room on Level in Phase

Question:
I want to create a room at a specific location on a given level and in a specific phase as well.
I see a constructor to create a room in a phase, and a constructor to create a room in a level at given UV coordinates, but there is no constructor to do both.
If I create a room on a level, I don’t see how to establish the phase.
If I create it in a phase, I don’t see how to position it on a level at the required position.
Is there a way to achieve both?

Answer:
First, here is some background information on the relevant room properties and existing samples that create rooms:

Room Level, Location and Phase Properties

There are is an SDK sample RoomSchedule and a Revit API introduction training lab Lab2_0_CreateLittleHouse which show how to place a room, but neither of them demonstrate setting all three of its level, location and phase properties.

The following properties allow you to get its level and get and set its location:

  • Level: returns the level to which the room is assigned.
  • Location: returns a location point object. The point within the location object can be get and set. This is the location of the room within the level. The Z location should be the elevation of the level and is not changeable.

You can also read its level by using the LEVEL_NAME or ROOM_LEVEL_ID parameters. Unfortunately, these parameters are both read-only:


LEVEL_NAME     String/Text  read-only  "Level 1"
ROOM_LEVEL_ID  ElementId    read-only  Levels 13071 'Level 1'

It has properties to read its creation and demolishment phases, and they are also marked as read-only:

  • PhaseCreated: the phase when the element is created.
  • PhaseDemolished: the phase when the element is to be demolished.

So I do not see any way to directly modify the level or phase properties of an existing room.

Ideas for creating a new Room with specific Level and Phase

The following overloads can be used to create a new room or place an existing one:


Room NewRoom( Phase );
Room NewRoom( Level, UV point );
Room NewRoom( Room, PlanCircuit );

A previous post on

plan topology

and the

CmdPlanTopology command

shows how to use the latter overload to create a new room.

You can also use it to place an existing unplaced room. You should be able to use the first overload to create a new room in a specified phase and then feed the newly created room to the third overload in order to place it.

Here is suggestion for another even simpler approach:

The NewRoom( Level, UV ) method uses the current phase. You could get the current phase of your current view, store that, change the current phase to whatever you like, call NewRoom, and then set the phase back to its original value again. I haven’t tried it, but it seems like that should work.

Difficulties creating a new Room with specific Level and Phase

Here are the results of trying both approaches:

1.
I tried to change the Phase of the actual view before creating the new Room but that does not work.
I changed the Phase like this:


View v = document.ActiveView;
ElementId id = myPhase.Id;
Parameter p = v.get_Parameter(
BuiltInParameter.VIEW_PHASE );
p.Set( ref id );
Room r = doc.NewRoom( level, uv );

After executing the command, I can see the phase of the view has changed, but the room is not created in the phase I set.
I tried to put the code changing the phase in a transaction, too, and that doesn’t work either.

2.
Then I created the room using the method NewRoom( Phase ).
And indeed, I can position the resulting room with the second method, NewRoom( Room, PlanCircuit ).
But this brings up a new problem: how can I determine which circuit to use to create my room at the given UV coordinates?
I could not find an easy way to do this.
Finally I ended up iterating through all the circuits in my level and phase.
If the circuit has no room, I create the room, and test if the UV point (with the level’s Z coordinate) lies within its bounding box.
If so, we are done.
If not, delete the room, and continue trying with the next circuit.
Rather inefficient:


// create the room in the phase:
Room roomNueva = doc.Create.NewRoom( phase );
// search for the plan circuit which
// locates the room at the given UV coordinates:
XYZ xyz = new XYZ( uv.U, uv.V, level.Elevation );
PlanTopology pt = doc.get_PlanTopology( level, phase );
foreach( PlanCircuit pc in pt.Circuits )
{
if( !pc.IsRoomLocated )
{
Room room = doc.Create.NewRoom( roomNueva, pc );
// test if the bounding box contains our point:
if( Geometry.BoundingBoxXYZContains(
roomNueva.get_BoundingBox( null ),
xyz ) )
{
break;
}
else // if not, delete the room:
{
doc.Delete( room );
room = null;
}
}
}

After some discussion with the Revit development team, the conclusion is that probably the ‘right’ way to go about this would be to create the room and then set the phase, which the API currently does not let you do.
The approach iterating through all the plan circuits and testing where the room ends up for each seems to be the only way to go for now.


Comments

21 responses to “Create Room on Level in Phase”

  1. Antonio Sanna Avatar
    Antonio Sanna

    Hello,
    You can know the working phase in which it was created a room.
    I tried to read the parameters, but …
    BuiltInParameter.ROOM_PHASE = “Nothing”
    BuiltInParameter.ROOM_PHASE_ID = “Nothing”
    BuiltInParameter.ROOM_PHASE_NAME = “”
    Is there a solution?
    Thank you very much
    Antonio

  2. Dear Antonio,
    Have you checked the PhaseCreated property? According to the section 12.3 ‘Phase’ in the SDK developer guide ‘Revit 2009 API Developer Guide.pdf’, the Phase Created property has the following characteristics:
    – It identifies the phase in which the component was added.
    – The default value is the same as the current view Phase value.
    – Change the Phase Created parameter by selecting a new value from the drop-down list.
    Does that work for you?
    Cheers, Jeremy.

  3. Antonio Sanna Avatar
    Antonio Sanna

    Dear Jeremy,
    Thanks for your reply.
    What I’m trying to get is a list of rooms in a particular phase.
    The list of steps in the document I have already obtained.
    When questioned the ownership of the room with the API, the field is empty.
    If, however, questionable ownership with Revit, I see that the stage was assigned.
    image:
    http://www.studiotecnicodesign.com/public/data/atsanna/RoomPhase.jpg
    I can not read the parameter (highlighted in the picture) with the API.
    Thank you very much.
    Antonio

  4. Dear Antonio,
    I just started a new Revit project and created a room using the default settings. The Phase property in the element properties dialogue in your screen snapshot shows ‘New Construction’. The PhaseCreated and PhaseDemolished properties are indeed both null, at least as far as RvtMgdDbg tells me. But the parameters that you mention are not null for me:
    ROOM_PHASE Phase 110001 ‘New Construction’
    ROOM_PHASE_ID Phase Id 110001 ‘New Construction’
    These are both ElementId properties. I do not see a ROOM_PHASE_NAME property, however. This is in Revit Architecture 2009, build 20080915_2100.
    I created another phase named ‘Phase 1’, set the view property Phase property to that, created another new room, and determined that its parameters also return the expected value:
    ROOM_PHASE Phase 130449 Phases ‘Phase 1’
    ROOM_PHASE_ID Phase Id 130449 Phases ‘Phase 1’
    Cheers, Jeremy.

  5. Antonio Sanna Avatar
    Antonio Sanna

    Dear Jeremy,
    Thank you for your kind response.
    I’m working with Revit Architecture 2009 Build 20081118_1045.
    This is an example for the part of my code that does not work …

    Dim list As New List (Of Revit.Element) ‘rooms in the project
    doc.Elements (GetType (Room), list)

    GetProperty (list (0), BuiltInParameter.ROOM_PHASE) = “Nothing”
    GetProperty (list (0), BuiltInParameter.ROOM_PHASE_ID) = “Nothing”

    GetProperty (list (0), BuiltInParameter.ROOM_PHASE_NAME) = “”

    Public Function getProperty (ByVal room As Room, ByVal paraEnum As BuiltInParameter) As String
    Dim propertyValue As String = Nothing
    ‘the value of parameter
    ‘Get the parameter via the parameterId
    Dim param As Parameter = ROOM.PARAMETER (paraEnum)
    If param Is Nothing Then
    Return “”
    End If
    ‘Get the parameter’s storage type
    Dim storageType As StorageType = param.StorageType
    Select Case storageType
    Case storageType. [Integer]
    Ivalo Dim As Integer = param.AsInteger ()
    propertyValue = iVal.ToString ()
    Exit Select
    Case storageType. [String]
    StringVal Dim As String = param.AsString ()
    propertyValue = stringVal
    Exit Select
    Case storageType. [Double]
    Dim dVal As Double = param.AsDouble ()
    dVal = Math.Round (dVal, 2)
    propertyValue = dVal.ToString ()
    Exit Select
    Case Else
    Exit Select
    End Select
    Return propertyValue
    End Function
    I tried to create multiple phases of work, but I can not ever get to the stage associated with the room.
    Thanks for your help.
    Antonio.

  6. Dear Antonio,
    As I pointed out above, the Phase parameter data type is an element id, because it is a reference from one Revit element to another, from the room to the phase. Your getProperty function handles integer, double and string storage types, but ignores element ids. That’s the problem.
    Cheers, Jeremy.

  7. Antonio Sanna Avatar
    Antonio Sanna

    Dear Jeremy,
    Now I understand …
    Thank you for your availability.
    Antonio

  8. hello, I am a new revit user. I am having trouble creating a stair and don’t know how to connect it to the second floor.
    and how to add railing to it.

  9. Dear Andrew,
    I am afraid that you cannot currently add a railing to the model through the API. The reasons for this are explored in a discussion with Berria on the topic:
    http://thebuildingcoder.typepad.com/blog/2009/02/list-railing-types.html#comments
    Regarding the creation of a new stair element and connecting it to the second floor, I would assume that that is possible. Looking at the SDK documentation in ‘Revit 2009 API Developer Guide.pdf’, you will find the following info in the section ‘10.5.1 Stair and Ramp’:
    Stair, Ramp, and the associated symbols do not have specific classes in the API. Stair and its associated symbol are represented as Element and Symbol in the OST_Stairs category.
    Implementing code to insert a stair will require some simple exploration, similar to the work done for columns, beams, and railings in the commands CmdNewColumnTypeInstance, CmdNewBeamTypeInstance, CmdListRailingTypes and CmdNewRailing, which unfortunately does not create a new railing instance. They were published on February 9, 11, 12 and 27, respectively.
    The link from the stair to the second floor is probably defined by some parameter on the stair element. Looking at the posts in the category Parameters provides lots of info on how to explore and set parameters on elements.
    In short, you can first create a model containing the kinds of stair that you are interested in and explore that to discover the category and parameters required, then convert the manual steps to API code.
    I hope this helps. Sorry I cannot sit down and do it for you right away, but there are other pressing issues I have to address as well.
    Cheers, Jeremy.

  10. Dear Andrew,
    I am afraid that you cannot currently create a stair through the Revit API either. Creating a stair requires a sketch and inserting a family instance, but the NewFamilyInstance method has no overload supporting the specification of a sketch. Sorry about this.
    Cheers, Jeremy.

  11. Dear Jeremy,
    I’m developing a program call 4D system, but now can not move, the reason is don’t know Revit API can add new “Phase” or not?
    From what i study and find in help, there is no function to create that. Is that true?
    Thanks in advance.

  12. Dear Quyet,
    I believe you are right and there is currently no API functionality to create a new phase. Sorry about that.
    Cheers, Jeremy.

  13. Dear Jeremy,
    Thanks for posting this great post for creating rooms on specific levels.
    I think this will also help to create spaces and zones on levels.
    Thanks
    Sandeep

  14. harrymattison Avatar
    harrymattison

    Hi Jeremy – In the 4 years since you posted this, do you know if there is any better solution than to your question “how can I determine which circuit to use to create my room at the given UV coordinates?”

  15. I am also curious if this is still the best way to place unplaced rooms. Also, is there an updated way to test if the room bounding box contains the point? The code ‘Geometry.BoundingBoxXYZContains’ is causing errors. Thank you!

  16. Dear Harry, dear Bryan,
    Nope, sorry, I am still not aware of a better way.
    Regarding the Geometry.BoundingBoxXYZContains method, that is a custom method implemented in a private geometry utility library. It can easily be rebuilt based on a suitable comparison operator for the XYZ point class, e.g. like this:
    const double _eps = 1.0e-9;
    public static bool IsZero(
    double a,
    double tolerance )
    {
    return tolerance > Math.Abs( a );
    }
    public static bool IsZero( double a )
    {
    return IsZero( a, _eps );
    }
    public static bool IsEqual( double a, double b )
    {
    return IsZero( b – a );
    }
    public static int Compare( double a, double b )
    {
    return IsEqual( a, b ) ? 0 : ( a < b ? -1 : 1 );
    }
    public static int Compare( XYZ p, XYZ q )
    {
    int d = Compare( p.X, q.X );
    if( 0 == d )
    {
    d = Compare( p.Y, q.Y );
    if( 0 == d )
    {
    d = Compare( p.Z, q.Z );
    }
    }
    return d;
    }
    public static bool IsEqual( XYZ p, XYZ q )
    {
    return 0 == Compare( p, q );
    }
    Now you can implement BoundingBoxXyzContains like this:
    // Return true if the given bounding box bb
    // contains the given point p in its interior.
    public bool BoundingBoxXyzContains(
    BoundingBoxXYZ bb,
    XYZ p )
    {
    return 0 < Compare( bb.Min, p )
    && 0 < Compare( p, bb.Max );
    }
    Please also refer to the following forum discussion threads:
    http://forums.autodesk.com/t5/Autodesk-Revit-API/Check-to-see-if-a-point-is-inside-bounding-box/m-p/4354446#M4343
    http://forums.autodesk.com/t5/Autodesk-Revit-API/Place-unplaced-room/m-p/4353454#M4335
    Cheers, Jeremy.

  17. Hi Jeremy,
    Thank you for such a wonderful blog, I’ve learned so much from it. I’m trying to do something similar to what you posted above but I can’t seem to be able to change the phase of views with my code and wondered if you had any suggestions. Using message boxes, I can get my variable viewPhase to return “Existing” but p.AsValueString() always returns “New Construction”. The view is created earlier in my code so I’m wondering if I need to commit the transaction before setting it’s phase. (I’m using Revit 2015) Any ideas?
    String viewPhase = room.get_Parameter(BuiltInParameter.ROOM_PHASE).AsValueString();
    Parameter p = view.get_Parameter(BuiltInParameter.VIEW_PHASE);
    p.SetValueString(viewPhase);
    Thanks!
    Jared

  18. Dear Jared,
    Thank you for your query and appreciation.
    I am very glad you like it :-)
    You need to look at the built-in parameter storage type and use the appropriate data type to set a new value.
    In this case, the storage type may or may not be an element id. It is almost certainly not a string.
    Use RevitLookup to see what the original data type is.
    Something like this:
    ElementId viewPhaseId = room.get_Parameter(BuiltInParameter.ROOM_PHASE).AsElementId();
    Parameter p = view.get_Parameter(BuiltInParameter.VIEW_PHASE);
    p.SetValueString(viewPhaseId);
    However, I am not sure at all, and this is completely untested.
    Are you sure this property is editable?
    Can you set it up the way you want in the user interface?
    Here is another little discussion on accessing a room phase:
    http://thebuildingcoder.typepad.com/blog/2012/08/adsk-file-import-and-phase-of-room.html#2
    Cheers, Jeremy.

  19. That was it! To set the VIEW_PHASE, it wanted an ElementId instead of a string.
    Thank you very much!
    Jared

  20. Edwin Guerra Avatar
    Edwin Guerra

    Jeremy,
    Are you aware of a limitation we have experienced (2014 and prior, 2015 we haven’t tested) where if a Revit user creates a custom phase (anything above the OOTB New Construction and Existing), the room information becomes inaccessible through the API (is reported as NULL)? This can be verified using the Snoop tool if you just create a blank project model a room and put a door, then run snoon on the door. If you merge the phase so you are back to the original ones, then the door reads the room relationship correctly…

  21. Dear Edwin,
    Nope, I am not aware of that.
    If you can provide a reproducible case demonstrating what you describe, I think I should report that to the development team and ask whether this is intended behaviour:
    http://thebuildingcoder.typepad.com/blog/about-the-author.html#1b
    Thank you!
    Cheers, Jeremy.

Leave a Reply

Discover more from Autodesk Developer Blog

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

Continue reading