Two Clicks to Create and Rotate Family Instances

public void createAndOrient()
{
    UIDocument uidoc = this.ActiveUIDocument;
    Document doc = uidoc.Document;
    Application app = doc.Application;

    // Get the family symbol named "North Arrow 2"
    FamilySymbol famSym = new FilteredElementCollector(doc).OfClass(typeof(FamilySymbol)).Where(q => q.Name == "North Arrow 2").First() as FamilySymbol;

    // use a transaction group so that all the individual transactions are merged into a single entry in the Undo menu
    // this is optional
    using (TransactionGroup tg = new TransactionGroup(doc,"Create and Orient Instances"))
    {
        tg.Start();
        // create an infinite loop so user can create multiple instances in a single command
        // ESC when prompted to select a point will thrown an exception which is how the loop is exited
        while (true)
        {
            try
            {                
                XYZ pickPoint = uidoc.Selection.PickPoint("Click to specify instance location. ESC to stop placing instances.");

                FamilyInstance familyInstance = null;    
                // Create the instance with the default orientation
                // This is done in its own transaction so that the user can see the new instance when they are prompted for the orientation
                using (Transaction t = new Transaction(doc,"Place Instance"))
                {
                    t.Start();
                    familyInstance = doc.Create.NewFamilyInstance(pickPoint, famSym, doc.ActiveView);
                    t.Commit();
                }

                XYZ orientPoint = uidoc.Selection.PickPoint("Click to specify orientation. ESC to stop placing instances.");

                // Create a line between the two points
                // A transaction is not needed because the line is a transient element created in the application, not in the document
                Line orientLine = app.Create.NewLineBound(pickPoint, orientPoint);

                // Compute the angle between the vertical direction (XZY.BasisY) and the orientLine
                double angle = XYZ.BasisY.AngleTo(orientLine.Direction);

                // For diagnostics in Task dialog below
                double angleDegrees = angle * 180 / Math.PI;

                // AngleTo always returns the smaller angle between the two lines (for example, it will always return 10 degrees, never 350)
                // so if the orient point is to the left of the pick point, then correct the angle by subtracting it from 2PI (Revit measures angles in degrees)
                if (orientPoint.X < pickPoint.X)
                    angle = 2 * Math.PI - angle;

                // To show the need for angle corrections
                double angleDegreesCorrected = angle * 180 / Math.PI;
                //TaskDialog.Show("info","Angle directly from AngleTo = " + angleDegrees + "\n Angle after X correction = " + angleDegreesCorrected);

                // Create an axis in the Z direction 
                Line axis = app.Create.NewLineBound(pickPoint, new XYZ(pickPoint.X, pickPoint.Y, pickPoint.Z + 10));

                using (Transaction t = new Transaction(doc,"Orient Instance"))
                {
                    t.Start();
                    ElementTransformUtils.RotateElement(doc, familyInstance.Id, axis, -angle);
                    t.Commit();
                }
            }
            catch
            {
                // Get here when the user hits ESC when prompted for selection
                // "break" exits from the while loop
                break;
            }
        }
    // Consolidate all the transactions for the individual creation / rotation transactions into a single Undo item	
    tg.Assimilate();
    }
}

5 thoughts on “Two Clicks to Create and Rotate Family Instances

  1. Harry,

    I just wanted to take a sec and drop you a note to let you know how valuable these posts are and to say thanks. If you ever happen to be in Portland, pop in at the office for a free lunch!

    Thanks!

    Trevor Taylor
    Associate Partner

    ZGF ARCHITECTS LLP
    D 503.863.2580 E trevor.taylor@zgf.com
    1223 SW Washington Street, Suite 200
    Portland, OR 97205

    • Thank you Trevor! I don’t think I will be in Portland anytime soon, but will you be making the trip up to Vancouver for RTC? It would be great to meet you there.

  2. How would one tweak this line to retrieve a family by a name and a specfic type? For example North Arrow 2…type 1?

    FamilySymbol famSym = new FilteredElementCollector(doc).OfClass(typeof(FamilySymbol)).Where(q => q.Name == “North Arrow 2”).First() as FamilySymbol;

  3. One small note …

    in the comment you say

    “then correct the angle by subtracting it from 2PI (Revit measures angles in degrees)”

    I think you mean Revit measures angles in radians

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s