Measuring Glass Area In a Door Above 2′

Following up on the previous post, here is how to put all the pieces together to find a door’s glass area above 2′

  1. Find the glass area of the door as-is
  2. Edit the door family
  3. Create a void to eliminate the bottom 2′ of glass
  4. Reload the door into the project
  5. Find the glass area of the modified door
  6. Rollback the changes to the door and the reloading of the door into the RVT

glassarea

public void MesaureGlassArea()
{
    Document doc = this.ActiveUIDocument.Document;
    UIDocument uidoc = new UIDocument(doc);
    FamilyInstance instance = doc.GetElement(uidoc.Selection.PickObject(ObjectType.Element)) as FamilyInstance;

    // Get the surface area of glass in the family
    string info = "Total glass area in door = " + getGlassAreaInFamily(instance) + "\n";

    // Open and edit the family document
    Document familyDoc = doc.EditFamily(instance.Symbol.Family);

    // The family geometry is going to be edited (to create the void to cut off the bottom 2' of glass) and then reloaded into the RVT.
    // After this is done, call getGlassAreaInFamily to get the modified glass area.
    // But in the end we don't want to keep all the transactions created by CreateExtrusionAndCutGlass.
    // A transaction group can be used to rollback all the transactions that were committed inside the transaction group.
    using (TransactionGroup transactionGroup = new TransactionGroup(doc,"Glass measurement"))
    {
        transactionGroup.Start();

        // Cut off the bottom 2 feet of glass
        CreateExtrusionAndCutGlass(familyDoc);

        // Load the modified family back into the RVT
        // FamilyLoadOptions tells Revit to overwrite the existing family instances in the RVT
        FamilyLoadOptions loadOptions = new FamilyLoadOptions();
        familyDoc.LoadFamily(doc,loadOptions);

        // Get the surface area of glass in the modified family
        info += "Glass in door above 2 feet = " + getGlassAreaInFamily(instance);    

        // Rollback the transaction group so that the reloading of the family and modifications to the family are discarded.
        transactionGroup.RollBack();
    }

    TaskDialog.Show("Material info", info);

    // Close the family document. False means do not save the file
    familyDoc.Close(false);
}

private double getGlassAreaInFamily(Element element)
{
    foreach (Material material in element.Materials)
    {
        if (material.Name == "Glass")
            return element.GetMaterialArea(material);
    }    
    return 0;
}

// FamilyLoadOptions tells Revit what to do when loading the family into a document that already contains the family
public class FamilyLoadOptions : IFamilyLoadOptions
{
    // Always return true so that all existing families and their parameters are overwritten with the new family
    public bool OnFamilyFound(bool familyInUse, out bool overwriteParameterValues)
    {
        overwriteParameterValues = true;
        return true;
    }
    public bool OnSharedFamilyFound(Family sharedFamily, bool familyInUse, out FamilySource source, out bool overwriteParameterValues)
    {
        overwriteParameterValues = true;
        source = FamilySource.Family;
        return true;
    }
}

private void CreateExtrusionAndCutGlass(Document doc)
{
    Autodesk.Revit.ApplicationServices.Application app = doc.Application;

    // Height of the void extrusion
    double height = 2;

    // Four points to define corners of the rectangle to extrude
    XYZ pnt1 = new XYZ(-10, -10, 0);
    XYZ pnt2 = new XYZ(10, -10, 0);
    XYZ pnt3 = new XYZ(10, 10, 0);
    XYZ pnt4 = new XYZ(-10, 10, 0);

    // Create the four lines of the rectangle
    // These are internal "Line" elements, not model lines or detail lines
    Line line1 = app.Create.NewLine(pnt1, pnt2, true);
    Line line2 = app.Create.NewLine(pnt2, pnt3, true);
    Line line3 = app.Create.NewLine(pnt3, pnt4, true);
    Line line4 = app.Create.NewLine(pnt4, pnt1, true);

    // Put these lines into a CurveArray
    CurveArray curveArray = new CurveArray();
    curveArray.Append(line1);
    curveArray.Append(line2);
    curveArray.Append(line3);
    curveArray.Append(line4);

    // Put this array into a CureArrArray (an array of CurveArrays)
    // Extrusion creation uses a CureArrArray so you can extrusion multiple loops 
    CurveArrArray curveArrayArray = new CurveArrArray();
    curveArrayArray.Append(curveArray);

    // Create a plane at the origin with a normal in the up direction
    XYZ planeNormal = XYZ.BasisZ;
    XYZ planeOrigin = XYZ.Zero;
    Plane plane = app.Create.NewPlane(planeNormal, planeOrigin);

    Extrusion extrusion = null;

    using (Transaction t = new Transaction(doc, "Create Extrusion"))
       {
            t.Start();
            // Create a sketch plane to be used for the extrusion
            SketchPlane sketchPlane = doc.FamilyCreate.NewSketchPlane(plane);
            // Create the extrusion. The "false" specifies that it will be a void
            extrusion = doc.FamilyCreate.NewExtrusion(false, curveArrayArray, sketchPlane, height);
            t.Commit();
       }

    // Cut the other 3D elements with the new void using CombineElements and a CombinableElementArray
    CombinableElementArray ceArray = new CombinableElementArray();

    // Add the new void extrusion to the CombinableElementArray
    ceArray.Append(extrusion);

    // Add all GenericForm elements with the Glass subcategory to a CombinableElementArray
    foreach (GenericForm genericForm in new FilteredElementCollector(doc).OfClass(typeof(GenericForm)).Cast<GenericForm>())
    {
        Category category = genericForm.Subcategory;
        if (category != null && category.Name == "Glass")
        {
            ceArray.Append(genericForm);
        }
    }

    using (Transaction t = new Transaction(doc, "Combine Elements"))
       {
            t.Start();
            // Combine the elements so that the void will cut the solids
            GeomCombination geomCombination = doc.CombineElements(ceArray);
            t.Commit();
       }
}
Advertisements

5 thoughts on “Measuring Glass Area In a Door Above 2′

  1. Can the IFamilyLoadOptions be used to load a set of edited families in a folder into a model and overwrite? Having a heck of a time figuring it out. I tried the following but Revit crashes. When I put the foreach in a transaction, I get a transaction must be closed before calling LoadFamily error:

    UIDocument uidoc = this.ActiveUIDocument;
    Document doc = uidoc.Document;

    string pathDir = @”C:\Users\Michael\Desktop\MyFamilies”;

    string[] array1 = Directory.GetFiles(pathDir, “*.rfa”);

    FamilyLoadOptions loadOptions = new FamilyLoadOptions();

    foreach (string path in array1)
    {
    Document familyDoc = Application.OpenDocumentFile(path);
    familyDoc.LoadFamily(doc, loadOptions);
    familyDoc.Close(false);
    }

    Thanks.

    • Use one of the LoadFamily overrides that takes a string (which is the full path to the RFA) and loads it into the active document. For example:

      		public void loadFamilies()
      		{
      			Document doc = this.ActiveUIDocument.Document;
      			using (Transaction t = new Transaction(doc,"Load Families"))
      			{
      				t.Start();
      				foreach (string s in Directory.GetFiles(@"C:\Users\harry_000\Desktop\New folder (2)","*.rfa"))
      				{
      					doc.LoadFamily(s);
      				}
      				t.Commit();
      			}
      		}
      
    • If the families are already loaded you need to use the Document.LoadFamily Method (String, IFamilyLoadOptions, Family%)

      The API documentation notes:
      If you are reloading an edited family back into the source document from which it was extracted, this method will always fail. This is because this method automatically suppresses the prompts Revit typically uses to deal with conflicts between families, and assumes that any such conflict should prevent the loading. If you want to be able to reload the same family into the source document, you should use the LoadFamily overload accepting IFamilyLoadOptions.

  2. Thanks. I could have sworn i tried something like this but didn’t get it to work but now it is. This is my code:

    public void LoadFamilyFolder()
    {
    Document doc = this.ActiveUIDocument.Document;

    IFamilyLoadOptions myOptions = new FamilyOptions();
    Family family = null;

    using (Transaction t = new Transaction(doc,”Load Families”))
    {
    t.Start();
    foreach (string s in Directory.GetFiles(@”\\ny11\Transfer\myFolder\Project Components”,”*.rfa”))
    {
    doc.LoadFamily(s, myOptions, out family);
    }
    t.Commit();
    }
    }
    public class FamilyOptions : IFamilyLoadOptions
    {
    public bool OnFamilyFound(bool familyInUse, out bool overwriteParameterValues)
    {
    overwriteParameterValues = true;
    return true;
    }
    public bool OnSharedFamilyFound(Family sharedFamily, bool familyInUse, out FamilySource source, out bool overwriteParameterValues)
    {
    source = FamilySource.Family;
    overwriteParameterValues = true;
    return true;
    }
    }

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s