Inserting a Beam

This is the final Verona installment, discussing the last remaining topic raised in the

Revit API training in Verona

the week before last, on creating new beam types and inserting beam instances through the API.

Similar to the exploration concerning

columns
,
we explored the following topics:

  • Retrieving all matching family elements in current document in order to check whether the family we are interested in is loaded.
  • Exploring the results of using a FamilyFilter.
  • Loading a new family, if not already present.
  • Creating a new family symbol, i.e. duplicating a beam type and setting its name and dimensions.
  • Inserting a new beam instance into the model.

The interesting new aspects addressed with beams compared to columns are:

  • The family type parameters and the naming convention used are completely different.
  • Inserting a beam instance requires using a different version of NewFamilyInstance.

We implemented a new external command CmdNewBeamTypeInstance to demonstrate the steps listed above.
It is very similar to the command CmdNewColumnTypeInstance for the columns.
First, we set up some constants to define the family we are interested in, its library path, the structural type and a unit conversion:


const string family_name
  = "M_Concrete-Rectangular Beam";
 
const string extension
  = ".rfa";
 
const string directory
  = "C:/Documents and Settings/All Users"
  + "/Application Data/Autodesk/RAC 2009"
  + "/Metric Library/Structural/Framing"
  + "/Concrete/";
 
const string path
  = directory + family_name + extension;
 
StructuralType stBeam
  = StructuralType.Beam;

Creating a new Beam Type

Most of the implementation of the Execute method is the same as for

CmdNewColumnTypeInstance
.
We check whether the family we are interested in is already loaded, making use of a family filter to get all family elements in the current document. We again note that the family filter returns both the symbols contained within the family and the family itself. The family element itself is stored in the variable ‘f’, and its symbols are simply listed. In real life, we would probably eliminate the symbols by creating a Boolean ‘and’ filter and filtering for the Family class as well as the family name.
If the family was not already loaded, then ‘f’ remains null, and we load it with the LoadFamily method. It would also be sufficient to load one single symbol from the family, since we just need one single symbol ‘s’ in order to call its Duplicate method. Any one will do, so we simply select the first one.
When duplicating it, we simultaneously define the new symbol name. We list all its parameters, set the new type’s dimensions, and demonstrate that we can change its name at a later stage as well if desired:


s.get_Parameter( "b" ).Set(
  Util.MmToFoot( 500 ) );
 
s.get_Parameter( "h" ).Set(
  Util.MmToFoot( 1000 ) );
s.Name = "Nuovo simbolo due";

The names of the dimension parameters we are interested in for the beam are named ‘b’ and ‘h’.
The column class that we examined used a completely different naming convention, with full names and upper-case initial letters, e.g. ‘Width’ and ‘Depth’.
This just goes to show that families are user defined and every family can use different conventions.

The new beam and column types appear like this in the Revit project browser:

New column and beam types

To follow the standard Revit type naming conventions, we would normally include the new type dimensions in its name, like the existing types do.

Creating FamilyInstance Objects

We did some experiments in order to place an instance of our new symbol in the model.
First we verified that it is possible to insert a beam, which normally uses a location line, by specifying only a location point:


XYZ p = XYZ.Zero;
doc.Create.NewFamilyInstance( p, s, nonStructural );

We can also place it with just a point and a direction:


XYZ p = XYZ.Zero;
XYZ q = app.Create.NewXYZ( 30, 20, 20 ); // feet
FamilyInstance fi = doc.Create.NewFamilyInstance(
  p, s, q, null, nonStructural );

In both of these cases, the instance has no location line defined for it, causing it to behave rather strangely and basically be unusable, e.g. it cannot be selected.

It is also possible to place it on a level, but lacking a location line, this version is also not really useful:


List<Element> levels = new List<Element>();
doc.get_Elements( typeof( Level ), levels );
Debug.Assert( 0 < levels.Count,
  "expected at least one level in model" );
 
Level level = levels[0] as Level;
 
fi = doc.Create.NewFamilyInstance(
  line, s, level, nonStructural );

These various attempts led us to realise that we really do need to define a location line for the beam.
We also verified that we must specify a structural type. Specifying a non-structural type means that no beam is created, and results in a null family instance. So this is the final working version for inserting a valid instance of a beam with sloped location line:


XYZ p = XYZ.Zero;
XYZ q = app.Create.NewXYZ( 30, 20, 20 ); // feet
Line line = app.Create.NewLineBound( p, q );
FamilyInstance fi = doc.Create.NewFamilyInstance(
  line, s, null, stBeam );

Here is an image showing the result of running the two new commands CmdNewBeamTypeInstance and CmdNewColumnTypeInstance, which insert one instance each of the of the new beam and column types:

New column and beam instances

By the way, if you have any questions regarding the use of NewFamilyInstance and especially the choice of the correct overload to use for specific situations,
the first place to look is in the

Revit 2009 API Developer Guide

section 11.3.4 on Creating FamilyInstance Objects.
That document contains the most complete and up-to-date description of the topic.
That section was also provided temporarily as a stand-alone SDK document named
Guide to placing Family Instances with the API.doc
This document provides a roadmap on how to create different categories of family instances using the API.
Typically these instances are created using one of the eight overloads of the Autodesk.Revit.Creation.Document method NewFamilyInstance.
The choice of which overload to use depends not only on the category of the instance, but also other characteristics of the placement, such as whether it should be hosted, placed relative to a reference level, or placed directly on a particular face.
The details are included in a table.
Instances of some family types are better created through methods other than NewFamilyInstance and are listed in a second table.

Here is
version 1.0.0.24
of the complete Visual Studio solution with the new CmdNewBeamTypeInstance command implementation.


Comments

25 responses to “Inserting a Beam”

  1. Hello Jeremy :)
    Thank you very much for your useful Blog.
    Here is my question: Is it possible to make a Family which is not of a Revit predefined Template. I mean in the above example could you have “USER_NAME” instead of “Columns” in the project browser. I thought I should create a user defied Template but I get the name of the Template which I used to create my template.:(
    Thanks

  2. Hi Rooz,
    I am not an expert on family creation, since there was no API for that in 2009, where it was an almost pure product and user interface feature. That is changing with 2010, of course. As far as I can tell, the user interface forces you to select a predefined template. Also, already in 2009 the API does actually provide the Application NewFamilyDocument method, which provides the same functionality. However, it also requires a template filename argument. I don’t know what happens if you provide a blank string here. Sorry for the meagre information on this one.
    Cheers, Jeremy.

  3. Hi Jeremy,
    thanks for your fast answer Jeremy.
    I have three other related questions:
    1. How are the template files created in Revit? Actually I mean “the first template file .rft” ever.
    If the user tries to create one through API or the user interface he has to choose a template, otherwise it doesn’t work!?
    2.Is it possible to create a rft-file without using another rft-file.
    3. What I am trying here is like trying to define a new “Family category”, Settings->Family Category and Parameters-> “USER_DEFINED”. Possible?
    Thanks
    Roozbeh

  4. Hi Roozbeh,
    I don’t know about questions 1 or 2, but to 3 I can definitely answer nope, sorry, no way.
    Cheers, Jeremy.

  5. Roozbeh Avatar
    Roozbeh

    Hi Jeremy,
    thanks for the answer. It seems that I have no other choice than defining myFamily under a revit predefined template.
    I have decided to use a Mass Template and I defined myFamily which is “Fire” under Mass. It could be “FireFamily”…. Somehow there can be no fire where there is no mass. Makes sense! ;) I should be able to make it make sense, if I am going to get a gut point.
    Regads
    Roozbeh

  6. Hi Roozbeh,
    Makes sense to me! One gut point credit.
    Before committing to anything, you can always discuss the issue with your peers in the Revit API discussion group at http://discussion.autodesk.com, who know a lot more about defining families than I do.
    Cheers, Jeremy.

  7. Hi Jeremy,
    I have figured out that when I create a Family(load through API) and do nothing else (for example not creating a family Instance of it) it can be seen in the Project browser but disappears as soon as I save the Revit file.
    The same happens with a new Family Symbol which I create like above.
    How could I solve this problem?
    Regards
    Roozbeh

  8. Dear Roozbeh,
    I guess you would have to somehow insert an instance into the model to ensure the definition is preserved. Maybe there is some way to create elements which do not affect the rest of the model and remain invisible to the user? Maybe a sort of invisible building phase or something? Or just hidden elements?
    In general, I would recommend to never fight the system. If Revit does not want you to save family symbol definitions in a model with no inserted instances, so be it. You can save the family definition in an external file instead. Or just keep track of what it was that you defined, and retain the possibility to redefine it again when you really do need an instance in the model.
    Cheers, Jeremy.

  9. Hi Jeremy ,
    thank you very much for the answer. I think it is a good idea too. I would serialize my App. and the next time I want to use the family (which was loaded and not used) it would be loaded if it is no longer in Revit.
    Regards
    Roozbeh

  10. Jeremy,
    First thanks for all the great explanations using the revit api. The question I have is, Is there a maximum limit as to calling:
    FamilyInstance fi = doc.Create.NewFamilyInstance(
    line, s, null, stBeam );
    Does the Revit database have a limitation as to how many instances it can create? Is it better to split large grouping of instances into separate entry sets?
    Thanks Again
    Jeff

  11. Dear Jeff,
    I am not aware of any limitation in the number of family instances that can be managed, and would be very surprised if such a limit exists, short of limitations imposed by the available system resources and memory space.
    When inserting large numbers of instances, please check whether the optimisations offered by the SuspendUpdating class are of any use to you, and be aware of the batch creation functionality provided by the creation document NewFamilyInstances method and FamilyInstanceCreationData class, demonstrated by the ElementsBatchCreation SDK sample.
    Cheers, Jeremy.

  12. Hi Jeremy,
    Thanks for the response. Yes I am currently using the the ElementsBatchCreation example as a template and my processing has not completed after a very long period of time. My task is to create 20k plus beams programmatically so this must be stretching it with the available memory that I have.(4gigs) Thanks for the SuspendUpdating suggestion, I will take a look at that (whenever revit returns)
    Jeff

  13. Dear Jeff,
    Oh, that sounds as if you are on the right track and already have the important basics set then. Make sure that you have installed the web 2 update. Performance issues such as this are being continuously improved. Good luck!
    Cheers, Jeremy.

  14. Hi Jeremy,
    I was able to insert a sybmol with NewFamilyInstance into the 3D view using these examples. Now I am trying to insert a single metal stud from the “C Studs-Section.rfa” family into one of the drafting views. However, nothing shows up. I am thinking API can’t do this with NewFamilyInstance or the overload I am using has mistakes. Any ideas? Thanks!
    // Declare constant for symbol name
    const string symName = “1 5/8\””;
    // get document
    Autodesk.Revit.Application app = commandData.Application;
    Document doc = app.ActiveDocument;
    //load the Family and symbol
    doc.ActiveView.Document.LoadFamilySymbol(“C:\Program Files\Autodesk Revit Structure 2010\Content\Imperial Library\Detail Components\Div 05-Metals\054100-Structural Metal Studs Framing\C Studs-Section.rfa”, symName);
    // Assign the FamilySymbol to object s
    Autodesk.Revit.Symbols.FamilySymbol s = FindFamilySymbol(doc, “C Studs-Section”, symName);
    MessageBox.Show(“Family: ” + s.Family.Name + ” Symbol: ” + s.Name + “Category: ” + s.Category.Name);
    // Insert the detail component symbol
    FamilyInstance metalstud = doc.Create.NewFamilyInstance(XYZ.Zero, s, StructuralType.NonStructural);
    //check for success
    if (null == metalstud)
    {
    MessageBox.Show(“Create NewFamilyInstance Failed!”);
    }
    else
    {
    MessageBox.Show(“Name: ” + metalstud.Name);
    }

  15. Dear Jason,
    I fear you are out of luck here. This is a known problem. You can add detail item components to plan views and all works well. If you add them to non-plan views, however, the facing orientation is still (0,0,1), and the element is invisible in the view, even though it has been added to the database. Sorry for the bad news.
    Cheers, Jeremy.

  16. Hi Jeremy,
    In Revit Structure 2011, the “C Studs-Section.rfa” family can be showed in the drafting views using the following instance creation:
    FamilyInstance metalstud = doc.Create.NewFamilyInstance(XYZ.Zero, s, StructuralType.NonStructural);
    However, it is unselectable or editable. Do you have idea? By the way, how to create similar type element using revit API in Csharp?
    Thanks,
    Karl

  17. Dear Karl,
    I do not now off-hand which overload of NewFamilyInstance to use, but similar issues have cropped up many times in the past. Some family instances require a curve, for instance. Look at the developer guide overview of the NewFamilyInstance overloads, do some experimenting, and let us know what you find out.
    Regarding the similar element type, do you mean ‘instance’ or ‘type’? For ‘type’, you can use the Duplicate method, I think:
    http://thebuildingcoder.typepad.com/blog/2008/11/creating-a-new-family-symbol.html
    For ‘instance’ one workaround is to create and duplicate a grouped object:
    http://thebuildingcoder.typepad.com/blog/2010/05/duplicate-legend-component.html
    Cheers, Jeremy.

  18. Hi Jeremy,
    Thanks for all the good work and explanation. I have a problem during insert a single beam on specific level.
    In Revit 2011 SDK samples, CurvedBeam, i have noticed that i can’t create a curved beam instance on certain level.
    Inside the CurvedBeam program, there is a combo-box which provide user the option of on which level the beam should be placed, everything works fine if user choose to input a beam on level 1, however, when user try to create a beam on level 2, its fail. Nothing appeared on level 2 plan, however, the beam is created on level 1 instead. I have also try to create a beam on different level, however, everything end up where all the beam is created and placed on level 1. Any idea or solution about this problem?
    In revit 2011 Curvedbeam samples:
    beam = m_revit.ActiveUIDocument.Document.Create.NewFamilyInstance(center, fsBeam, level, StructuralType.Beam);
    CurvedBeam.cs LN 293 Col 91
    My own program :
    ICollection levels = levelcollector.OfClass(typeof(Level)).ToElements();
    Level level2 = (Level)levels.ElementAt(1);
    beam = m_docCreator.NewFamilyInstance(line, beamsymbol, level2, Autodesk.Revit.DB.Structure.StructuralType.Beam);
    Any suggestion is appreciated.
    Regards
    BSYap

  19. Dear BSYap,
    Thank you for the query. I checked what you said and can reproduce it using the CurvedBeam SDK sample. I reported it to the development team and hope that they can explain.
    Cheers, Jeremy.

  20. Hi Jeremy,
    Thanks so much for your help. Does this error occurred related to the unspecified workplane? By the way, how do we set the workplane because i can’t get any method related to workplane in Revit 2011 API.
    By the way, i have also noticed that there is a problem when input a level-base element. Revit Structure depicts elements going from higher levels to lower levels. For instance, a column created in Level 2 would go from Level 2 down to Level 1, however, this totally against the way of input when insert a column instance using a Revit API, please refer below:
    //Get level instance of level 2
    ICollection levels = levelcollector.OfClass(typeof(Level)).ToElements();
    Level level2= (Level)levels.ElementAt(1);
    //Create column instance on level 2 using overloaded method NewFamilyInstance(XYZ,FamilySymbol,Level,StructuralType)
    Guess what..
    The column is created on level 2 with Base Level property set to Level 2, but Top level property set to level 3 (which is moving upwards), but according to the revit structural insertion, when a column is insert on level 2, the column should goes down to level 1 where the column must have it’s base level set to level 1 and top level set to level 2.
    Any idea bout this?
    Thanks.
    BSYap

  21. Dear BSYap,
    Nope, no more ideas on this, sounds pretty confusing. I went through a bit of confusion creating the initial posts on inserting beams and columns as well … I hope you find a working solution that fulfils your needs!
    Since I will be going on holiday now, I will not be able to answer any updates for while, so please be patient … Thank you!
    Cheers, Jeremy.

  22. Kristoffer Avatar
    Kristoffer

    Hi Jeremy,
    I’m struggling with inserting a furniture component in my model (Revit 2011) and I wonder if what I’m seeing is the same phenomenon that bsyap is describing.
    What I want to do is to insert a piece of furniture (a bed) onto the first floor (ie, the first with elevation > 0). The Revit 2011 API Developer Guide.pdf says on page 134 that “Some FamilyInstance objects do not have host elements, such as tables and other furniture..”. However, an example of “Insert(ing) a new instance of a family into the document..” in the Revit 2011 API help doc uses this call:
    FamilyInstance instance = document.Create.NewFamilyInstance(location, symbol, direction, floor, StructuralType.NonStructural);
    .. which seems to be exactly what I want (the furniture in the example is even a “bedbox”), so I tried that. I have ensured that both the location (including the Z-coordinate) and the floor are correct. But the bed is nevertheless located on the zeroeth floor. In the Property dialog I see that the bed has been assigned a host, which is a floor, but not a level. But confusingly, when I inspect the bed using the Snoop tool, the host property as shown there is null. If I set a break point after the bed has been created and check its host property in the Immediate Window, it is also null.
    When I place the bed manually, I see that it has both a host (although the Snoop tool still says it hasn’t) and also a level. The manually placed bed is on the correct floor, so my next thought was that I should use an overload that includes the Level argument. In the guide-to-placing-family-instances-with-the-api.doc document I found an overload appropriate for furniture with this comment: “If it is to be hosted on a wall, floor or ceiling and associated to a reference level” which sounded good, so I tried:
    FamilyInstance revitBed =
    DBDocument.Create.NewFamilyInstance(location, bedFamilySymbol,
    floorBedIsOn, levelBedIsOn, StructuralType.NonStructural);
    .. and now the bed is located on the correct floor; the property dialog says its host is a floor; and it also has a Level (which is the correct level), just as when I insert the bed manually.
    However, this overload doesn’t include the referenceDirection argument, and I have so far not succeeded in finding a way of rotating the bed after it has been created.
    Clearly there are many more things to try out (yet more overloads, using a Rotate method post-creation, etc) but I suspect that there might be something not quite right here, and that the first overload I attempted “should have worked”.. could you throw some light upon this? Have I misunderstood something? (like so many times before.. :-)
    Thanks,
    Kristoffer

  23. Dear Kristoffer,
    Please have a look at my newest post, and let me know whether that and the tools presented there help you:
    http://thebuildingcoder.typepad.com/blog/2010/11/place-detail-instance.html
    Also, I have the following theory, which I would like you to confirm:
    The Z coordinate that you specify on the insertion point when calling NewFamilyInstance is ignored, and this is by design. You should specify zero there, even if you want the family instance to have a non-zero height later. The non-zero height is achieved by setting a parameter, maybe the built-in parameter INSTANCE_FREE_HOST_OFFSET_PARAM, which is displayed and editable in the user interface as ‘Offset’.
    Remember, Revit manages a parametrically driven model, so the height is defined by a parameter as well. The insertion point is irrelevant; the relationship to the host is the important driving factor.
    My favourite NewFamilyInstance overload candidate to choose for your case would probably be one of
    FamilyInstance NewFamilyInstance( XYZ location, FamilySymbol, Level, StructuralType );
    FamilyInstance NewFamilyInstance( XYZ location, FamilySymbol, Element host, Level, StructuralType );
    But please test all of them and let us know what solves the issue.
    The issue with the reference direction may need some additional functionality added to the API, or you may be able to solve this after inserting the family instance.
    Please keep us up to date with your progress.
    This looks like a very common problem to me, I have heard others struggling with similar issues, and it definitely looks like a candidate for another blog post. So please document you solution well, keep it general, and be ready to edit a guest blog post, if you don’t mind sharing your results. Thank you!
    Cheers, Jeremy.

  24. Kristoffer Avatar
    Kristoffer

    Jeremy,
    I solved the problem by using this overload:
    XYZ, FamilySymbol, Element (host), Level, StructuralType
    .. ie, the one that specifies both a host and a level, and then rotating the furniture with the Document.Rotate method after it is created. This way, the property dialog of the bed displays the same information when I put in the bed using the API as when I do it manually (ie, both a host and a level) and the bed has the correct orientation.
    Regarding the Z-coordinate: I suspected that it possibly should be zero and I tried that as well with the first overload I thought should be correct (XYZ, FamilySymbol, XYZ (direction), Element (host), StructuralType) but I saw no difference in behaviour: the bed still ended up on the zeroeth floor, not the first.
    Finally, I tried to set the offset-parameter as you suggested (with location.Z = 0) just to see the effect, but with little luck: the bed seems to be positioned right at the top of the floor it’s on and in the UI I cannot find the “Offset” parameter, neither on the instance nor the type. I do find it with the Snoop-tool however, but the value is zero despite me setting it to 6.5.
    But in any case, thanks so much for your as always informative reply.
    Kristoffer

  25. Dear Kristoffer,
    Thank you for the positive update, and congratulations on solving it satisfactorily. I am very glad that it worked out for you. I suggest creating a new blog post to document this result.
    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