Stair development first needs to distinguish these names for convenient calling later
Stairs StairsRun StairsRiser Tread
Stair Dimension Problem
Dimensioning needs to obtain Reference and horizontal faces and vertical faces of stair landings or stair runs. Stairs are divided into the above parts, each has a separate Solid that can be picked. My problem also happened here. The Type() returned by picking Geometry alone is ElementType, not a class related to Stairs, so the Reference obtained by picking alone is wrong. Guessing that the Solid.Reference obtained alone is the classification in editing stairs, so there is a phenomenon that there is no error with ID but cannot be displayed. If anyone needs to do automatic stair dimensioning, I will write down my ideas here for everyone’s reference.
Stair Dimension Steps
Get Stair Geometry
Get GeometryInstance
Get Host Element through Instance category and take out Solid under instance to get target face
Use Paramater of Host Element combined with Face to generate dimensions
//Clicking on the stair face can identify the stair riser type as Stairs, try to extract from Stairs Geometry var stairsGeo = stairs.get_Geometry(option); foreach (GeometryObject o in stairsGeo) { if(o is GeometryInstance instance) { //At most two Solids. If there is one, it represents only structure or only architecture, indicating this is a single specialty file if (instance.Symbol.GetType() == typeof(StairsLanding)) { Solid fakeSolid = null; foreach (GeometryObject geometryObject in instance.GetInstanceGeometry()) { if (geometryObject is Solid solid) { if (fakeSolid == null) { fakeSolid = solid; } else { //Large volume is structural part, small volume is finish part, can be taken at will here if (fakeSolid.Volume > solid.Volume) { fakeSolid = solid; } } } }
PlanarFace planarFace = null; foreach (var face in fakeSolid.Faces) { if (face is PlanarFace pf) { var faceNormal = pf.FaceNormal; //Tread vector must be 0, 0, ±1 if (Math.Abs(faceNormal.X - 0) < 0.01 && Math.Abs(faceNormal.Y - 0) < 0.01 && Math.Abs(faceNormal.Z - 1) < 0.01) { planarFace = pf;
}
} }
map.Add((doc.GetElement(planarFace.Reference) as StairsLanding).BaseElevation, planarFace); } elseif (instance.Symbol.GetType() == typeof(StairsRun)) { Solid fakeSolid = null; foreach (GeometryObject geometryObject in instance.GetInstanceGeometry()) { if (geometryObject is Solid solid) { if (fakeSolid == null) { fakeSolid = solid; } else { if (fakeSolid.Volume > solid.Volume) { fakeSolid = solid; } } } }
var run = doc.GetElement(fakeSolid.Faces.get_Item(0).Reference) as StairsRun; var runTopElevation = run.TopElevation; var runPathLoop = run.GetStairsPath(); //Run path is generally a line segment, vector is the riser direction Line runPathDir = null; foreach (var curve in runPathLoop) { runPathDir = curve as Line; } var runGeo = run.get_Geometry(option);
var faces = fakeSolid.Faces; //Get All Faces //Screen out all horizontal and vertical faces here, but horizontal faces are not needed, keep for now //If tread quantity of stair run cannot be accurately extracted, tread quantity and height within a single run can be determined by level PlanarFace referFace1 = null, referFace2 = null, referFace3 = null, referFace4 = null; SelectTargetFaces(faces, runPathDir, out referFace1, out referFace2); SelectTargetFaces(faces, runPathDir, out referFace3, out referFace4, 0);
Automatic dimensioning cannot be without level dimensions. The four XYZ parameters of the API represent origin, leader bend point, leader bend point midpoint, and reference origin respectively. Generally, reference origin and origin can be the same point. As long as the point is on the dimensioned Reference, there is nothing special to pay attention to. Just paste the code directly.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
foreach (KeyValuePair<double, PlanarFace> face in map) { //Create level var elevationFace = face.Value; var elevationFaceRefer = elevationFace.Reference; var boundingBoxUV = elevationFace.GetBoundingBox(); var point = elevationFace.Evaluate(new UV((boundingBoxUV.Max.U + boundingBoxUV.Min.U) / 2, (boundingBoxUV.Max.V + boundingBoxUV.Min.V) / 2)); var bendPoint = point.Add(new XYZ(0, 1, 1));//Leader Bend Point var endPoint = point.Add(new XYZ(0, 2, 1));//Leader End Point
var spotElevation = doc.Create.NewSpotElevation(view, elevationFaceRefer, point, bendPoint, endPoint, point, true); }