using System; using System.Collections.Generic; using System.Linq; using System.Text; using Autodesk.Revit.DB; using Autodesk.Revit.UI; namespace Revit.Samples.DirectionCalculation { /// /// Implementation class for utilities to find south facing exterior walls in a project. /// /// [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Automatic)] [Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)] [Autodesk.Revit.Attributes.Journaling(Autodesk.Revit.Attributes.JournalingMode.NoCommandData)] public class FindSouthFacingWalls : FindSouthFacingBase { /// /// The implementation of the FindSouthFacingWalls command. /// /// true to use the active project location's north/south direction. /// false to use the default coordinate system's north/south (Y-axis). protected void Execute(bool useProjectLocationNorth) { UIDocument uiDoc = new UIDocument(Document); Autodesk.Revit.UI.Selection.SelElementSet selElements = uiDoc.Selection.Elements; IEnumerable walls = CollectExteriorWalls(); foreach (Wall wall in walls) { XYZ exteriorDirection = GetExteriorWallDirection(wall); if (useProjectLocationNorth) exteriorDirection = TransformByProjectLocation(exteriorDirection); bool isSouthFacing = IsSouthFacing(exteriorDirection); if (isSouthFacing) selElements.Insert(wall); } // Select all walls which had the proper direction. uiDoc.Selection.Elements = selElements; } /// /// Finds all exterior walls in the active document. /// /// An enumerable containing exterior walls. protected IEnumerable CollectExteriorWalls() { FilteredElementCollector collector = new FilteredElementCollector(Document); IList elementsToProcess = collector.OfClass(typeof(Wall)).ToElements(); // Use a LINQ query to filter out only Exterior walls IEnumerable exteriorWalls = from wall in elementsToProcess.Cast() where IsExterior(Document.get_Element(wall.GetTypeId()) as ElementType) select wall; return exteriorWalls; } /// /// Test method to see if the wall type is exterior. /// /// The wall type. /// true if the wall is exterior, else false. protected bool IsExterior(ElementType wallType) { Parameter wallFunction = wallType.get_Parameter(BuiltInParameter.FUNCTION_PARAM); WallFunction value = (WallFunction)wallFunction.AsInteger(); return (value == WallFunction.Exterior); } /// /// Obtains the outward direction of the exterior wall. /// /// The wall. /// A normalized XYZ direction vector. protected XYZ GetExteriorWallDirection(Wall wall) { LocationCurve locationCurve = wall.Location as LocationCurve; XYZ exteriorDirection = XYZ.BasisZ; if (locationCurve != null) { Curve curve = locationCurve.Curve; //Write("Wall line endpoints: ", curve); XYZ direction = XYZ.BasisX; if (curve is Line) { // Obtains the tangent vector of the wall. direction = curve.ComputeDerivatives(0, true).BasisX.Normalize(); } else { // An assumption, for non-linear walls, that the "tangent vector" is the direction // from the start of the wall to the end. direction = (curve.get_EndPoint(1) - curve.get_EndPoint(0)).Normalize(); } // Calculate the normal vector via cross product. exteriorDirection = XYZ.BasisZ.CrossProduct(direction); // Flipped walls need to reverse the calculated direction if (wall.Flipped) exteriorDirection = -exteriorDirection; } return exteriorDirection; } } }