Hosting a Light Fitting on a Reference Plane

It is sometimes a challenge to determine which of the numerous

overloads of the NewFamilyInstance method
to
use to achieve a desired effect.
Here is a question on using it to host a light fitting by Simon Jones, with an initial answer by Saikat Bhattacharya, followed by lots more research by Simon to nail down the right solution that really works.

Question: How can I host a light fitting onto a reference plane?

I tried several different ways without any luck so far.

When I use the following, the light is hosted by the reference plane but doesn’t move with it:


mRevitDoc.Document.Create.NewFamilyInstance(
pt, mFamilySymbol, refDir, mReferencePlane,
StructuralType.NonStructural);

What should I use instead to make the fitting remain attached to the plane at all times?

Answer: The following modification to your code addresses your requirement.

It uses the overload of NewFamilyInstance taking a reference, point, vector and symbol to insert a new instance of a family onto a face referenced by the input Reference instance, using a location and reference direction.

This creates a family instance which moves when the ReferencePlane is moved.

For simplicity, I have hard coded the element id of the ReferencePlane of my test project.

Before running this code, please select the lighting instance on the base work plane.
This code then creates a lighting instance on the reference plane (along with the existing lighting fixture on the reference).

Now you can move the reference plane to the other side of the wall and confirm that the new lighting fixture instance moves along with it too.


  Selection sel = uidoc.Selection;
 
  ElementSet elemSet = sel.Elements;
 
  Transaction trans = new Transaction( doc );
  trans.Start( "Lights Camera Action!" );
 
  IEnumerator iter = elemSet.ForwardIterator();
 
  Element element;
 
  ReferencePlane mReferencePlane = null;
  FamilyInstance mFamilyInstance = null;
  FamilySymbol mFamilySymbol = null;
 
  while( iter.MoveNext() )
  {
    element = iter.Current as Element;
 
    FamilyInstance fi = element as FamilyInstance;
 
    mFamilyInstance = fi;
    mFamilySymbol = fi.Symbol;
  }
 
  mReferencePlane = doc.get_Element(
    new ElementId( 615738 ) ) as ReferencePlane;
 
  XYZ pt = XYZ.Zero;
  XYZ refDir = XYZ.BasisZ;
 
  uidoc.Document.Create.NewFamilyInstance(
    mReferencePlane.Reference, pt, refDir,
    mFamilySymbol );
 
  trans.Commit();

Response: Perfect, got it working now.

The issue was that I was trying to place the light on a horizontal reference plane and it seems that the argument was set incorrectly.
To begin with, strangely enough, it seemed that I needed to use a null vector for the reference direction for a horizontal reference plane:


XYZ refDir = new XYZ(0,0,0);

Before that, I was using:


XYZ refDir = new XYZ(0,0,1);

That caused my error.

Here is a current snapshot of my
C# code and
some
sample input data.
The code will read a TXT file and place lights on a named reference plane.

I explored the effect of the reference direction used in more detail.
Here are my findings:

The reference direction required obviously depends on the orientation of the reference plane.
So I guess the sensible thing to do is to use a direction relative to the plane’s normal.

However, my solution requires taking ceiling layouts from AutoCAD and reading them into Revit via a txt file exported from AutoCAD.
Within Revit we use horizontal reference planes drawn from right to left (as even with manual insertion that effects the orientation of the light); therefore, this is the solution I require and am happy that I have.

From what I can work out, the reference direction needs to point in the direction the reference plane is drawn; therefore 0,0,1 works for vertical planes, and 1,0,0 for horizontal ones.
For a quick hack, the following works for both vertical and horizontal ref planes:


XYZ refDir = new XYZ(
rp.Normal.Z, rp.Normal.X, rp.Normal.Y );

Here are the results of my tests prior to adding the above hack:

Vertical Reference Plane along the End Wall

1. Vertical RP +ve Y (drawn bottom to top), RefDir 0,0,1:

Lighting fixture on reference plane test 1

2. Vertical RP -ve Y (drawn top to bottom), RefDir 0,0,1:

Lighting fixture on reference plane test 2

Result: The lights have been placed on the other side of the reference plane.

3. Vertical RP -ve Y (drawn top to bottom), RefDir 0,0,0:

Lighting fixture on reference plane test 3

Result: Same side of ref plane, but now they’re rotated around 90 degrees.

Horizontal Reference Plane along the Underside of the Ceiling

4. Horizontal RP -ve X (drawn right to left), RefDir 0,0,0:

Lighting fixture on reference plane test 4

Result: Attached to the underside of the reference plane (as required).

5. Horizontal RP +ve X (drawn left to right), RefDir 0,0,0:

Lighting fixture on reference plane test 5

Result: Attached to the topside of the reference plane (not as required).

6. Horizontal RP +ve X (drawn left to right), RefDir 0,0,1 & Horizontal RP -ve X (drawn right to left), RefDir 0,0,1:

Lighting fixture on reference plane test 6

Result: ‘Error code: 5’.

7. Horizontal RP -ve X (drawn right to left), RefDir 1,0,0:

Lighting fixture on reference plane test 7

Result: Look OK.

8. Horizontal RP -ve X (drawn right to left), RefDir 0,1,0:

Lighting fixture on reference plane test 8

Result: Lights rotated 90 degrees.

Many thanks to Simon and Saikat for this example and all the research!


Comments

10 responses to “Hosting a Light Fitting on a Reference Plane”

  1. Jitendra Dhande Avatar
    Jitendra Dhande

    Hi Jeremy ,
    i want to know about how to show selected pipe type in properties window in Revit using C#.
    Thank You
    Jitendra Dhande

  2. Ken Marsh Avatar
    Ken Marsh

    Ok, this is a fascinating article and answered part of my latest quandry. As far as the next part, thank you to Simon for all the research! Based on this, can anyone rationalize the meaning of direction vector as used in NewFamilyInstance(reference, xyz location, xyz direction, familySymbol)? I found that by using a direction of (-1,0,0) the placement side flipped. (same effect Simon found where drawing the refplane the opposite way caused the placement side to flip)
    It appears that direction is the orientation of the family in the placement plane but it doesn’t suggest why the direction of drawing the refplane makes a difference unless it is relative to the plane normal. e.g., any angle -90 to 90 is on same side as normal, any angle 91 to 270 is placed on side opposite to normal?

  3. Hi Ken,
    My standard evasive answer to these kind of issues: understand it from the user interface point of view first.
    In Revit, the UI philosophy often helps a lot to clarify the API behaviour.
    So, have you asked a manual content creation expert, an application engineer?
    Cheers, Jeremy.

  4. Dear Jitendra Dhande,
    Here is a discussion of this very topic:
    http://thebuildingcoder.typepad.com/blog/2012/09/updating-properties-and-announcing-revit-lt.html
    Note that it does not work reliably, though, as some of the comments explain.
    Cheers, Jeremy.

  5. Hi Jeremy,
    Thanks for the blog. But I tried all possible options & yet am still getting the following error when creating a lighting fixture on a horizontal reference plane.
    Autodesk.Revit.Exceptions.ArgumentsInconsistentException: Reference direction is parallel to face normal at insertion point.
    Thanks,
    Mona

  6. Did you ever figure this out? It works for me in Revit 2012, but does not work in 2013 with 2013 API.

  7. Dear Bart,
    Sorry for not replying earlier.
    This is probably an error in one of your arguments.
    The Revit API improves error checking release by release, so erroneous input argument that went unnoticed in previous versions may throw and exception later.
    Very probably the problem is exactly what the error message says: the reference direction is parallel to the face normal at the insertion point.
    You probably need to understand that and fix it.
    I hope this helps.
    Cheers, Jeremy.

  8. Thanks for your reply because I haven’t found a lot of sources to help me on this.
    bubbleEnd = new xyz(5, 0, 0);
    freeEnd = new xyz(-5, 0, 0);
    cutVec = new xyz(0, 0, 1);
    The reference plane created from these points and vector has a normal of (0, -1, 0) and a direction of (1, 0, 0). It’s length runs horizontal when on a floor plan view and it’s height is the cutVec or the global Z. In 2012 version, when I set the reference direction to 1 or -1 unit vector for the X or Z value it will work. But in 2013 and 2014 I tried all the possible reference directions and still get the exception the ref dir is parallel. Shouldn’t one of them work?! It appears to be the same issue Mona replied with. None of the vectors work.

  9. Dear Bart,
    The best thing to do for you will be to submit a reproducible case for us to explore, and the easiest place to do that is in the Revit API discussion forum:
    http://thebuildingcoder.typepad.com/blog/about-the-author.html#1
    Cheers, Jeremy.

  10. Dear Jeremy
    Can i Host the Family instance on Linked Element Ceiling ?

Leave a Reply

Discover more from Autodesk Developer Blog

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

Continue reading