Host Reference

Still enjoying my climbing and sunshine holiday with my sons in Avignon.
Yesterday we went climbing and exploring the cliffs or ‘calanque’ of Cassis, east of Marseille
(more images):

Calanque de Cassis

Besides climbing, swimming in the Gard river and Mediterranean Sea, and blogging now and then, my sons are also artistically active:

Dog by Cornelius

Returning to the Revit API, however:
We already touched on the relationship between a host and its hosted elements in some previous posts.
The first such topic was the

relationship inverter
,
making use of the explicit property providing a reference to the host of hosted elements such as doors, windows and other family instances.
Since this property only specifies the relationship in one direction, we implemented the relationship inverter to obtain the inverse references.

No such explicit property is provided in either direction in the

association between a tag and the tagged element
,
and that discussion mentions four ideas for possible workarounds instead.

Here is another question on a similar topic, the relationship between a wall and its wall footing:

Question:
How can I obtain a reference to a wall footing from the wall attached to it?
And vice versa, is it possible to obtain a reference to the wall supported by a wall footing?

Wall footing

Answer:
As in the case of the tag and the tagged element, the Revit API does not provide any direct access to the link in either direction,
neither to get the reference of a wall footing from the wall attached to it or vice versa.
The workaround via the Document.Delete method mentioned as one of the four workarounds to determine the association between

a tag and the tagged element

can be used in this case as well:
You call the method to delete the wall.
It automatically includes the wall footing in the deletion, and returns the element ids of all deleted objects in an ElementIdSet, from which you can pick out the wall footing.
If you encapsulate this operation in a transaction which is aborted after the call, the deletion will not be committed, and you will have obtained the desired information with no changes made to the model.
Here is a sample code snippet to implement this:

I added a new command class CmdWallFooting to The Building Coder sample implementing this functionality.
Here is the source code of its Execute method:


Application app = commandData.Application;
Document doc = app.ActiveDocument;
 
ContFooting footing = null;
 
Wall wall = Util.SelectSingleElementOfType(
  doc, typeof( Wall ), "a wall" ) as Wall;
 
if ( null == wall )
{
  message = "Please select a single wall element.";
}
else
{
  doc.BeginTransaction();
  ElementIdSet delIds = null;
  try
  {
    delIds = doc.Delete( wall );
  }
  catch ( System.Exception )
  {
    message = "Deletion failed.";
    doc.AbortTransaction();
    return CmdResult.Failed;
  }
  doc.AbortTransaction();
 
  foreach ( ElementId id in delIds )
  {
    ElementId refId = id;
    Element elem = doc.get_Element( ref refId );
    if ( null == elem )
      continue;
    footing = elem as ContFooting;
    if ( null != footing )
      break;
  }
}
string s = Util.ElementDescription( wall );
 
Util.InfoMsg( ( null == footing )
  ? string.Format( "No footing found for {0}.", s )
  : string.Format( "{0} has {1}.", s,
    Util.ElementDescription( footing ) ) );
 
return CmdResult.Failed;

This is the result of running the new command on the wall depicted above:

Wall footing message

Another efficient workaround has become possible in Revit 2010 by making use of the new API method FindReferencesByDirection.
It finds both elements and geometric references that intersect a ray extending in a certain direction from an origin point.
The Revit 2010 SDK Samples AvoidObstruction and RaytraceBounce demonstrate the use of this new method.
By using a couple of points on the wall footing, we can easily determine which wall is located directly above it, and vice versa as well.
This provides a much stronger possibility to the workarounds using general geometric proximity suggested in the post on the

tag association
.

Here is
version 1.1.0.34
of the complete Visual Studio solution with the new command.

Update: I updated this article for Revit 2011 on August 3 2010 based on the comment below by Jo Lee to fix the

transaction migration errors
introduced
by the simplistic initial flat port of the code from Revit 2010 to the Revit 2011 API.


Comments

9 responses to “Host Reference”

  1. I was looking at AvoideObstruction for inteference checking hints, when it dawned on me that Revit does an inteference check when I create a new family instance, and then throws it’s own errors (like if I placed 2 columns in the same position). Is there a way to tap into this built in interference checking tool?
    jvj

  2. While I was reviewing AvoidObstruction, I realized that Revit performs an Interference Dection for me, then throws its own errors. Example: create 2 of the same columns in the same position. Is there a way to tap into this interference checking system, or the error system, to capture this list before the user, and delete the duplcates via code?
    jvj

  3. Dear Jamie,
    Sorry, not that I am aware of. Sounds like an interesting future feature, though.
    Cheers, Jeremy.

  4. Ritish Avatar
    Ritish

    Hi Jeremy,
    Will u please suggest How do i get doors of wall? means which door belong to which wall?

  5. Dear Ritish,
    I already have. There are a number of posts that deal explicitly with this question, e.g.
    http://thebuildingcoder.typepad.com/blog/2010/03/object-relationships.html
    Cheers, Jeremy.

  6. Joo Lee Avatar
    Joo Lee

    Dear Jeremy,
    I tested your cmdWallFooting command in revit architecture 2011.
    But it is not work.
    transaction is not start.
    how can i work with transaction?
    sorry, my english is to bad.

  7. Dear Joo Lee,
    Please don’t worry about your English, it sounds just fine to me.
    Thank you very much for pointing this out!
    This command was flat migrated from Revit 2010 and never tested.
    I tested it now as well and discovered two problems with it:
    1. It did not have any active transaction open at all, since it was set to read-only transaction mode.
    2. The Revit 2010 transaction was replaced by a Revit 2011 sub-transaction, which requires a call to Start before it can be used.
    Fix 1: The read-only transaction mode causes the following error whan trying to delete the wall: “Attempt to modify the model outside of transaction.”
    It can be fixed by specifying the transaction attribute like this:
    [Transaction( TransactionMode.Automatic )]
    Fix 2: The sub-transaction can be started by calling its Start method. Then the code to temporarily delete the wall looks like this:
    SubTransaction t = new SubTransaction( doc );
    ICollection delIds = null;
    try
    {
    t.Start();
    delIds = doc.Delete( wall );
    t.RollBack();
    }
    catch ( Exception ex )
    {
    message = “Deletion failed: ” + ex.Message;
    t.RollBack();
    return Result.Failed;
    }
    I posted the updated version of The Building Coder sample code:
    http://thebuildingcoder.typepad.com/blog/2010/08/transaction-migration-errors.html
    Cheers, Jeremy.

  8. Joo Lee Avatar
    Joo Lee

    Dear Jeremy,
    Thanks for your reply.
    I create a form. it have a button.
    I want use transaction in form.
    but InvalidOperationException is occured.
    private void button1_Click(object sender, EventArgs e)
    {
    UIApplication app = m_commandData.Application;
    UIDocument uidoc = app.ActiveUIDocument;
    Document doc = uidoc.Document;
    ContFooting footing = null;
    Wall wall = Util.SelectSingleElementOfType(
    uidoc, typeof(Wall), “a wall”) as Wall;
    if (null != wall)
    {
    SubTransaction t = new SubTransaction(doc);
    ICollection delIds = null;
    try
    {
    t.Start();
    delIds = doc.Delete(wall);
    t.RollBack();
    }
    catch (System.Exception)
    {
    //message = “Deletion failed.”;
    t.RollBack();
    return;// Result.Failed;
    }
    foreach (ElementId id in delIds)
    {
    Element elem = doc.get_Element(id);
    if (null != elem)
    {
    footing = elem as ContFooting;
    if (null != footing)
    break;
    }
    }
    }
    string s = Util.ElementDescription(wall);
    Util.InfoMsg((null == footing)
    ? string.Format(“No footing found for {0}.”, s)
    string.Format(“{0} has {1}.”, s,
    Util.ElementDescription(footing)));
    }

  9. Dear Joo Lee,
    Maybe your form is modeless, in which case you have no access to the Revit API at all:
    http://thebuildingcoder.typepad.com/blog/2010/07/modeless-loose-connectors.html
    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