Random Material generator

The post “Randomize Color and Material in Revit” seemed like a good reason for me to write a post about randomly setting materials.

First, some random number humor:

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

    // get all glass materials in document
    IEnumerable<Element> materials = new FilteredElementCollector(doc)
        .OfClass(typeof(Material))
        .Cast<Material>()
        .Where(q => q.MaterialClass == "Glass");

    using (Transaction t = new Transaction(doc,"Random Materials"))
    {
        t.Start();
        foreach (Element e in new FilteredElementCollector(doc).OfClass(typeof(FamilyInstance)).OfCategory(BuiltInCategory.OST_CurtainWallPanels))
        {
            Parameter materialParam = e.get_Parameter("Material");
            if (materialParam == null)
                continue;

            int randomNumber = new Random(Guid.NewGuid().GetHashCode()).Next(0,materials.Count());

            materialParam.Set(materials.ElementAt(randomNumber).Id);
        }
        t.Commit();
    }
}
Advertisements

Making a beam associated with an edge (part 2)

In the previous post, I showed how to create a beam using the geometry of an edge, and how to store parameter data in the beam that can be used to identify the edge used to create it.

Here is how to update the beams when the edge geometry has changed.

public void UpdateAllBeamsOnEdges()
{
    Document doc = this.ActiveUIDocument.Document;
    UIDocument uidoc = this.ActiveUIDocument;
    SelElementSet selSet = SelElementSet.Create();

    int updatedCtr = 0;
    int skippedCtr = 0;

    using (Transaction t = new Transaction(doc, "Update beams on edges"))
    {
        t.Start();
        // find all beams that have a value for the BeamReference parameter
        // the lambda expression (inside the Where statement) defines a local variable named stableRefParam
        // to help check that both the parameter is not null and that the value of the parameter is not null
        foreach (FamilyInstance fi in new FilteredElementCollector(doc)
                 .OfClass(typeof(FamilyInstance))
                 .OfCategory(BuiltInCategory.OST_StructuralFraming)
                 .Cast<FamilyInstance>()
                 .Where(q => {
                            Parameter stableRefParam = q.get_Parameter("BeamReference"); 
                            return stableRefParam != null &&
                                stableRefParam.AsString() != null;}))
        {
            // get the string from the parameter
            string stableRef = fi.get_Parameter("BeamReference").AsString();

            // get the reference and edge from the stable reference string
            Reference r = Reference.ParseFromStableRepresentation(doc, stableRef);                
            Edge edge = doc.GetElement(r).GetGeometryObjectFromReference(r) as Edge;

            if (edge == null)
            {
                selSet.Add(fi);
                skippedCtr++;
                continue;
            }
            // get the location curve of the beam
            LocationCurve lc = fi.Location as LocationCurve;

            // set the location curve of the beam to the geometry curve of the edge
            lc.Curve = edge.AsCurve();

            updatedCtr++;
        }
        t.Commit();
    }
    uidoc.Selection.Elements = selSet;
    TaskDialog.Show("Info","Updated " + updatedCtr + " beams\n" + "Skipped " + skippedCtr + " highlighted beams (references may no longer exist)");
}

Making a beam associated with an edge (part 1)

Erik asks:

with the UI you can select edges to place a beam but it is not associated to that edge. Can you make it associate?

Yes, we can use the API to solve this problem. In this post I will show how to create the beam and store information about the edge used to create it. In the next post I will show how to update the beam to match the shape of the modified edge.

public void CreateBeamOnEdge()
{
    Document doc = this.ActiveUIDocument.Document;
    UIDocument uidoc = this.ActiveUIDocument;

    // find the family symbol for the W-Wide Flange : W12X26 beam
    FamilySymbol beamSymbol = new FilteredElementCollector(doc).OfClass(typeof(FamilySymbol)).Cast<FamilySymbol>()
        .First(q => 
               q.Family.FamilyCategory.Name == "Structural Framing" &&
               q.Family.Name == "W-Wide Flange" && 
               q.Name == "W12X26");

    // find the lowest elevation level in the project (sort levels by elevation, then take the first one)
    Level level = new FilteredElementCollector(doc).OfClass(typeof(Level)).Cast<Level>().OrderBy(q => q.Elevation).First();

    // prompt the user to select an edge
    Reference r = uidoc.Selection.PickObject(ObjectType.Edge,"Pick edge");

    // find the edge from the edge's reference
    Edge edge = doc.GetElement(r).GetGeometryObjectFromReference(r) as Edge;

    using (Transaction t = new Transaction(doc, "Create Beam"))
    {
        t.Start();

        // create a beam on the curve of the edge
        FamilyInstance fi = doc.Create.NewFamilyInstance(edge.AsCurve(), beamSymbol, level, StructuralType.Beam);

        // store a string representation of the edge's reference in a parameter of the beam
        // the value of the parameter will be something like:
        // 99406e0f-efac-4920-9d5f-fe6cea12fc2a-0002cf51:4:LINEAR
        Parameter beamRefParam = fi.get_Parameter("BeamReference");        
        if (beamRefParam == null)
            TaskDialog.Show("Error","Need to create a BeamReference parameter");
        else
            beamRefParam.Set(r.ConvertToStableRepresentation(doc));

        t.Commit();
    }
}

Automating the Building Maker workflow

Tobias suggested that it would be great to see the API used to create Walls by Face, Floors by Face, Roofs by Face, and Mass Floors.

Fortunately, the Revit API has FaceWall.Create and MassInstanceUtils.AddMassLevelDataToMassInstance methods.
Unfortunately, the Revit API has no methods to create Floors by Face and Roofs by Face.

Below is a code sample showing how to create Face Walls on the non-horizontal surfaces and Mass Floors for all levels.

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

    WallType wType = new FilteredElementCollector(doc).OfClass(typeof(WallType)).Cast<WallType>().FirstOrDefault(q => q.Name == "Generic - 6\" Masonry");

    Options opt = new Options();
    opt.ComputeReferences = true;

    using (Transaction t = new Transaction(doc, "Create Face Walls & Mass Floors"))
    {
        t.Start();
        foreach(Solid solid in fi.get_Geometry(opt).Where(q => q is Solid).Cast<Solid>() )
          {
            foreach(Face f in solid.Faces)
              {
                  if (!FaceWall.IsValidFaceReferenceForFaceWall(doc, f.Reference))
                      continue;
                FaceWall.Create( doc, wType.Id, WallLocationLine.CoreExterior, f.Reference );

              }
          }

        foreach (Level level in new FilteredElementCollector(doc).OfClass(typeof(Level)).Cast<Level>())
        {
            MassInstanceUtils.AddMassLevelDataToMassInstance(doc, fi.Id, level.Id);
        }

      t.Commit();
    }
}

Free Revit File Version Tool – Download it today!

Remember this post about Steve’s wish?

When you open a Revit file that was last saved in a previous version, would you love it if Revit asked “Do you want to upgrade?” And would you want a “No” button?

If so, the free File Version Reporter from Boost Your BIM is for you!

  1. Check the ‘last saved version’ for a single file
  2. Check the ‘last saved version’ for all files in a folder
  3. Get a notification dialog when starting to upgrade a file from a previous version with a “No” button

Download the free tool at http://gdurl.com/lbnw/download

The tool is free and also a test of the Pay What You Want approach that Laura Handler mentioned recently. You decide how much time this tool saves you, how much aggravation it helps you avoid, and how much it is worth to you. I hope you will love it and you will make a generous contribution. If you don’t like it, don’t pay anything. If this works for everyone, I’ll happily publish some more Revit API tools this way.