Fresh off my success at creating a sketched stair run from lines imported from CAD ( Create Stairs From CAD Link/List of Lines with Python Script?),
I tried to adapt it to a switchback stair. The documentation only shows a sketched stair and straight run, with the landing magically finding it’s location.
Why not do it that way? My goal is to translate exactly what the CAD geometry shows and not let Revit decide. This geometry is taken from a real building, and I want to make sure it isn’t “fudged” just to make Revit happy.
I am getting close (after many Revit crashes, what’s up with that?), but am not able to connect the second stair-run to the landing, as you can see here:
I tried a “midLevel” variable approximating the elevation where newRun2 and the landing could meet, but no dice (see hashed out line 53 in code). Also, the requirements for the Landing baseElevation are a little confusing to me:
baseElevation
Type: System Double
Base elevation of the new stairs run. The elevation has following restriction:
- The base elevation is relative to the base elevation of the stairs. (Relative? Meaning the same height? How is that calculated?)
- The base elevation will be rounded automatically to a multiple of the riser height. (Are they just saying it will connect automatically to top of the stair-run?)
- The base elevation should be equal to or greater than half of the riser height. (Are they saying it should be > than 1/2 a single riser, or…?)
At any rate, here is my code:
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Architecture import StairsRun
from Autodesk.Revit.DB.Architecture import StairsLanding
from Autodesk.Revit.DB import CurveLoop
doc = DocumentManager.Instance.CurrentDBDocument
class StairsFailurePreprocessor( IFailuresPreprocessor ):
def PreprocessFailures(self, failuresAccessor):
return FailureProcessingResult.Continue
baseLevel = UnwrapElement(IN[0])
nextLevel = UnwrapElement(IN[1])
b1Curves = IN[2]
r1Curves = IN[3]
p1Curves = IN[4]
b2Curves = IN[5]
r2Curves = IN[6]
p2Curves = IN[7]
elCurves = IN[8]
TransactionManager.Instance.ForceCloseTransaction()
newStairsScope = StairsEditScope(doc, 'New Stairs')
newStairsId = newStairsScope.Start(baseLevel.Id, nextLevel.Id)
trans = Transaction(doc, 'Add Runs and Landings to Stairs')
trans.Start()
bdryCurves1 = list(b1Curves)
riserCurves1 = list(r1Curves)
pathCurves1 = list(p1Curves)
bdryCurves2 = list(b2Curves)
riserCurves2 = list(r2Curves)
pathCurves2 = list(p2Curves)
landingLoop = CurveLoop.Create(elCurves)
r1Count = len(r1Curves)
r2Count = len(r2Curves)
#midLevel = nextLevel.Elevation - baseLevel.Elevation / 2 * r1Count / r2Count
newRun1 = Autodesk.Revit.DB.Architecture.StairsRun.CreateSketchedRun(doc, newStairsId, baseLevel.Elevation, bdryCurves1, riserCurves1, pathCurves1)
newRun2 = Autodesk.Revit.DB.Architecture.StairsRun.CreateSketchedRun(doc, newStairsId, baseLevel.Elevation, bdryCurves2, riserCurves2, pathCurves2)
newLanding = Autodesk.Revit.DB.Architecture.StairsLanding.CreateSketchedLanding(doc, newStairsId, landingLoop, newRun1.TopElevation)
trans.Commit()
newStairsScope.Commit(StairsFailurePreprocessor())
OUT = newStairsId
…and the graph. The smaller python nodes convert Dynamo Lines using .ToRevitType (my thanks to @wouter.hilhorst).
I am not committed to this solution, but it seems like it should work somehow.
Best,
-L