// // (C) Copyright 2003-2019 by Autodesk, Inc. // // Permission to use, copy, modify, and distribute this software in // object code form for any purpose and without fee is hereby granted, // provided that the above copyright notice appears in all copies and // that both that copyright notice and the limited warranty and // restricted rights notice below appear in all supporting // documentation. // // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE // UNINTERRUPTED OR ERROR FREE. // // Use, duplication, or disclosure by the U.S. Government is subject to // restrictions set forth in FAR 52.227-19 (Commercial Computer // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. // using System; using System.Collections.Generic; using Autodesk.Revit.DB; using Autodesk.Revit.DB.Architecture; namespace Revit.SDK.Samples.WinderStairs.CS { /// /// It represents a winder stairs, might include multiple straight runs and winder corners. /// abstract class Winder { /// /// Control Points to determine the winder shape(e.g. L or U shape). /// public virtual IList ControlPoints { get; set; } /// /// Winder stairs Run width. /// public double RunWidth { get; set; } /// /// Winder stairs tread depth, it just makes sense for straight steps. /// public double TreadDepth { get; set; } /// /// Outer boundary curves calculated by algorithm. /// protected IList OuterBoundary { get; private set; } /// /// Inner boundary curves calculated by algorithm. /// protected IList InnerBoundary { get; private set; } /// /// Center walk-path calculated by algorithm. /// protected IList CenterWalkpath { get; private set; } /// /// Riser lines calculated by algorithm. /// protected IList RiserLines { get; set; } /// /// This method creates the sketched winder run and it also deletes the input winderRunId. /// /// Revit Document to create the sketched run /// Flag to control whether to draw the sketch in document /// Previous created winder, it will be deleted public void Build(Document rvtDoc, bool drawSketch, ref ElementId winderRunId) { // Preparing the sketch containers. OuterBoundary = new List(); InnerBoundary = new List(); CenterWalkpath = new List(); RiserLines = new List(); // Fill the sketch containers GenerateSketch(); // Draw the sketch with model curves if required so. if (drawSketch) DebugSketch(rvtDoc); // Create the sketched run CreateWinderRun(rvtDoc, ref winderRunId); } /// /// This method generates the winder sketch and fills the sketch to the properties: /// OuterBoundary, InnerBoundary, CenterWalkpath and RiserLines. /// protected abstract void GenerateSketch(); /// /// This method creates the sketched run in Revit document. /// /// Revit Document /// Created winder run private void CreateWinderRun(Document rvtDoc, ref ElementId winderRunId) { using (StairsEditScope stairsMode = new StairsEditScope(rvtDoc, GetType().Name)) { var winderOldRun = rvtDoc.GetElement(winderRunId) as StairsRun; var stairsId = ElementId.InvalidElementId; // Non-existed stairs, create a new one. if (winderOldRun == null) { // Find two levels to create a stairs between them FilteredElementCollector filterLevels = new FilteredElementCollector(rvtDoc); var levels = filterLevels.OfClass(typeof(Level)).ToElements(); List levelList = new List(); levelList.AddRange(levels); levelList.Sort((a, b) => { return ((Level)a).Elevation.CompareTo(((Level)b).Elevation); }); // Start the stairs edit mode stairsId = stairsMode.Start(levelList[0].Id, levelList[1].Id); } else // using the existed stairs { // Start the stairs edit mode stairsId = stairsMode.Start(winderOldRun.GetStairs().Id); } using (Transaction winderTransaction = new Transaction(rvtDoc)) { // Start the winder creation transaction winderTransaction.Start(GetType().Name); // The boundaries is consist of internal and external boundaries. List boundarys = new List(); boundarys.AddRange(InnerBoundary); boundarys.AddRange(OuterBoundary); // Calculate the run elevation. Stairs stairs = rvtDoc.GetElement(stairsId) as Stairs; double elevation = ControlPoints[0].Z; double actualElevation = Math.Max(elevation, stairs.BaseElevation); // Create the run StairsRun run = StairsRun.CreateSketchedRun(rvtDoc, stairsId, actualElevation, boundarys, RiserLines, CenterWalkpath); if (ElementId.InvalidElementId != winderRunId) { // Delete the old run rvtDoc.Delete(winderRunId); } // output the new run winderRunId = run.Id; // Finish the winder run creation. winderTransaction.Commit(); } // Finish the stairs Edit mode. stairsMode.Commit(new StairsEditScopeFailuresPreprocessor()); } } /// /// This method draws sketch as model curves in Revit document for debug purpose. /// /// Revit document private void DebugSketch(Document rvtDoc) { try { using (Transaction debugTransaction = new Transaction(rvtDoc)) { debugTransaction.Start("DEBUG API WINDER SKETCH"); SketchPlane skp = SketchPlane.Create( rvtDoc, Plane.CreateByNormalAndOrigin(XYZ.BasisZ, ControlPoints[0])); CurveArray curves = new CurveArray(); foreach (var curve in OuterBoundary) { curves.Append(curve); } foreach (var curve in InnerBoundary) { curves.Append(curve); } foreach (var curve in CenterWalkpath) { curves.Append(curve); } foreach (var curve in RiserLines) { curves.Append(curve); } rvtDoc.Create.NewModelCurveArray(curves, skp); debugTransaction.Commit(); } } catch (System.Exception) { // SWALLOW ALL DEBUG EXCEPTION } } } class StairsEditScopeFailuresPreprocessor : IFailuresPreprocessor { public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor) { failuresAccessor.DeleteAllWarnings(); return FailureProcessingResult.Continue; } } }