Schedule slope of all roof or floor faces

A Revit user asks:

Is there any way to extract a Slope or angle of planar face through revit Api. I have modified flat roof by modifying sub elements, and would like to collect all surface angle or slopes, since we need to validate if all roof surfaces are in 2,5% inclinations. Is there anything which can be used through API for automatic evaluations of these conditions?

Yes, there is!

If you’d like this information to update when the floor is deleted or its geometry changes, that can be done with Dynamic Model Update.

public void GetSlopes()
{
    UIDocument uidoc = this.ActiveUIDocument;
    Document doc = uidoc.Document;
    Reference hostReference = uidoc.Selection.PickObject(ObjectType.Element, "Select floor or roof");
    HostObject host = doc.GetElement(hostReference) as HostObject;
    IList references = HostObjectUtils.GetTopFaces(host);
    
    TextNoteOptions textNoteOptions =  new TextNoteOptions();
    textNoteOptions.TypeId = new FilteredElementCollector(doc).OfClass(typeof(TextNoteType)).FirstOrDefault().Id;
        
    using (Transaction t = new Transaction(doc, "Slopes"))
    {
        t.Start();
        foreach (Reference r in references)
        {
            PlanarFace face = host.GetGeometryObjectFromReference(r) as PlanarFace;
            XYZ normal = face.FaceNormal;
            double angleRadians = normal.AngleTo(XYZ.BasisZ);
            double angleDegrees = angleRadians * 180 / Math.PI;
            XYZ origin = face.Origin;
            string slopeString = Math.Round((angleDegrees), 3).ToString();
            makePoint(doc, origin, slopeString, 1);
            TextNote.Create(doc, doc.ActiveView.Id, origin, slopeString, textNoteOptions);
        }
        t.Commit();
    }
    
}

public FamilyInstance makePoint(Document doc, XYZ pt, string comment, double radius)
{
    if (pt == null)
        return null;

    FamilyInstance ret = null;

    using (Transaction t = new Transaction(doc, "t"))
    {
        bool started = false;
        try
        {
            t.Start();
            started = true;
        }
        catch
        { }

        FamilySymbol fs = new FilteredElementCollector(doc)
            .OfClass(typeof(FamilySymbol))
            .Cast()
            .FirstOrDefault(q => q.Family.Name == "DiagPoint" && q.Name == "DiagPoint");
        
        if (fs != null)
        {
            if (!fs.IsActive)
                fs.Activate();
            ret = (FamilyInstance)doc.Create.NewFamilyInstance(pt, fs, Autodesk.Revit.DB.Structure.StructuralType.NonStructural);
            ret.LookupParameter("Comments").Set(comment);
            ret.LookupParameter("Radius").Set(radius);
        }
        if (started)
            t.Commit();
    }
    return ret;
}