最终成果
成果还需要补充,目前只完成了楼梯部分还需要
- 外侧墙体做联动标注
- 考虑到正向中分专业建模的情况还需要对链接模型进行处理
- 用户自定义选取竖向标注位置
- 做尺寸标注字体避开梯段
- 标高与尺寸标注样式的选择问题
对齐竖向标注位置
楼梯架构
楼梯的开发首先需要分清这几个名称方便后期调用
楼梯 Stairs
梯段 StairsRun
踢面 StairsRiser
踏板 Tread
楼梯标注问题
标注需要获取Reference及楼梯平台或是梯段的横向面以及竖向面,而楼梯分为上面几个部分,每个都有单独的Solid可以拾取,我的问题也发生在这个位置,通过单独拾取Geometry返回的Type()是ElementType
,并不是Stairs相关的类,所以通过单独选取获得的Reference是错误的,猜测单独获取的Solid.Reference是编辑楼梯中的分类,所以出现不报错有ID但无法显示的现象,如果有人需要做楼梯自动标注的话,我这里将我的思路写出来供大家参考。
楼梯标注步骤
- 获取楼梯Geometry
- 获取GeometryInstance
- 通过Instance的类别获取Host Element 并取出instance下的Solid从而获取目标面
- 利用Host Element的Paramater 与 Face结合生成标注
code
//单击楼梯面可获取楼梯踢面的类型为Stairs,尝试从Stairs的Geometry中取出
var stairsGeo = stairs.get_Geometry(option);
foreach (GeometryObject o in stairsGeo)
{
if(o is GeometryInstance instance)
{
//至多两个Solid,如果有一个则代表只有结构或只有建筑,表示此为单一专业文件
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
{
//体积大的为结构部分体积小的为面层部分,此处可随意取用
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;
//踏步的向量必为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);
}
else if (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();
//梯段路径一般为一个线段,向量为踢面的方向
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
//此处筛选出所有的横向面与纵向面,但是横向面无需使用,暂时留用
//如果梯段的踏步数量无法准确提取可以通过标高判定单个梯段内的踏步数量与高度
PlanarFace referFace1 = null, referFace2 = null, referFace3 = null, referFace4 = null;
SelectTargetFaces(faces, runPathDir, out referFace1, out referFace2);
SelectTargetFaces(faces, runPathDir, out referFace3, out referFace4, 0);
CreateDimension(doc, view, run, referFace1, referFace2);
//CreateVerticalDimension(doc,view,run,referFace3,referFace4);
//var relativeTopElevation = run.get_Parameter(BuiltInParameter.STAIRS_RUN_TOP_ELEVATION);
//var relativeTopValue = relativeTopElevation.AsValueString()/* / 304.8*/;
//var relativeEndElevation = run.get_Parameter(BuiltInParameter.STAIRS_RUN_BOTTOM_ELEVATION);
//var relativeEndValue = relativeEndElevation.AsValueString()/* / 304.8*/;
referFace3 = map.FirstOrDefault(x => Math.Abs(x.Key - run.TopElevation) < 0.01).Value;
referFace4 = map.FirstOrDefault(x => Math.Abs(x.Key - run.BaseElevation) < 0.01).Value;
if (referFace3 == null || referFace4 == null)
{
continue;
}
CreateVerticalDimension(doc, view, run, referFace3, referFace4);
}
}
}
标高标注
自动标注少不了标高标注,API的四个XYZ参数分别代表原点,引线折点,引线折点中点,参照原点,一般参照原点与原点为同一点即可,只要点在标注的Reference上即可,也没什么特别注意的,直接把代码贴上吧。
foreach (KeyValuePair<double, PlanarFace> face in map)
{
//创建标高
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));//引线折点
var endPoint = point.Add(new XYZ(0, 2, 1));//引线终点
var spotElevation = doc.Create.NewSpotElevation(view, elevationFaceRefer, point,
bendPoint, endPoint, point, true);
}