【Revit API】梁构件支座检查算法
一、前言
应该是第二次写关于Revit API的博文了。虽然在BIM企业中工作,从事桌面BIM软件开发,但是我是不怎么喜欢写Revit API相关的代码。平时更多的是在写界面展示,架构维护,授权验证这块。为什么不喜欢Revit API呢?其实Autodesk封装的这套API是不错的(我在之后的工作中用起来挺舒服的),可能还是人比较懒吧,老查英文的API手册有点烦,而且这手册界面让我想起了上学时帮导师写ObjectARX的痛苦经历。。。

吐槽完之后,开始上干货。为什么需要去判断梁构件是否有支座?原因有以下几个点:
1. 提醒BIM建模设计师其设计的梁构件是否正确,说白点就是:你丫画对了没?!
a. 如果有支座,支座与梁的位置是否符合图纸;
b. 如果没支座,为什么?是画错了(画成虚接触)还是本身就没有支座;
2. 如果梁有支座,OK!我根据平法规则自动分析节点并自动生成钢筋,完美;(这是后话,此篇不做节点分析与钢筋生成)
开发这个功能还是想帮助建模人员去检查自己画的模型。中国之大,BIM建模人员参差不齐,一个人就一种画法。
本篇会以图文代码结合的方式叙述,保证初来认识Revit的朋友也能看得懂,也希望高手能提提改进建议。
二、正文
Revit 版本:2016,
主函数:IsBeamHasSeat(Element element),
作用:判断梁构件是否有支座,适用于直梁与弧形梁。
思路:因为梁有支座的话肯定要有2个构件作为其支座,不然就翘脚了。counter就是计数器,如果到2了,就不用执行了,返回true即可。
说明:
1. 相交构件的函数GetJointElements是自己封装的,各位可根据实际自己编写,不暴露了。作用就是获取该梁周围一定范围内的所有构件;
2. IsStructrualColumn(),IsStructrualBeam()也是自己封装的,比较简单,不暴露了。作用就是要求作为梁支座的柱与梁是结构型构件,墙不用。
3. IsCoulmnBeSeatForBeam(),IsWallBeSeatForBeam(),IsBeamBeSeatForBeam() 这三个函数是核心,下面会慢慢展开讲。
public static bool IsBeamHasSeat(Element element)
{
int counter = ;
//获取相交构件
var jointElements = BaseGeomUtils.GetJointElements(element);
if (jointElements != null && jointElements.Any())
{
//检查柱的
foreach (var column in jointElements)
{ if (column.IsStructuralColumn() && IsCoulmnBeSeatForBeam(element, column))
{
counter++;
}
if (counter == )
{
return true;
}
} //检查墙的
foreach (var wall in jointElements)
{
if (IsWallBeSeatForBeam(element, wall))
{
counter++;
}
if (counter == )
{
return true;
}
} //检查梁的
foreach (var beam in jointElements)
{
if (beam.IsStructuralBeam() && IsBeamBeSeatForBeam(element, beam))
{
counter++;
}
if (counter == )
{
return true;
}
}
}
return false;
}
A. 判断柱构件是否为当前梁的支座
这时候要上图了,方便理解。
第1个大条件:

如果不符合这个条件,说明梁与柱可能是侧面相交的关系:

private static bool IsCoulmnBeSeatForBeam(Element currentBeam, Element jointColumn)
{
try
{
var minArea = 0.1;
var columnBottomFace = FaceUtils.GetBottomFace(jointColumn, minArea);
var beamBottomFace = FaceUtils.GetBottomFace(currentBeam, minArea);
//柱的下底面低于梁的下底面
bool isLower = columnBottomFace.Origin.Z < beamBottomFace.Origin.Z; //取Location和LocationCurve
var columnLocation = jointColumn.Location as LocationPoint;
var beamLocationCurve = currentBeam.Location as LocationCurve;
if (columnLocation != null && beamLocationCurve != null)
{
//1.Column的Location在Beam的Location下面
//2.Column的LocationPoint能映射到Beam的下底面
//3.Beam中有点可以投影到Column的下底面
if (beamBottomFace.Project(columnLocation.Point) != null ||
beamLocationCurve.Curve.Tessellate().Any(x => columnBottomFace.Project(x) != null
&& isLower))
{
return true;
} //侧面关系
else
{
var bc = beamLocationCurve.Curve;
//获取构件侧面(除去Z方向上下两个面)
var columnFaces = FaceUtils.GetSideFaces(jointColumn);
var beamFaces = FaceUtils.GetSideFaces(currentBeam);
var line = bc as Line;
if (line != null)
{
var beamLine = line.Direction;
//梁两端的面
var terminalFaces =
beamFaces.Where(x => (x as PlanarFace).SafelyFaceNormal().IsAlmostEqualTo(beamLine) ||
(x as PlanarFace).SafelyFaceNormal().IsAlmostEqualTo(-beamLine));
//判断梁的两端面与支座梁的侧面有没有相交
if (columnFaces.Any(fc => terminalFaces.Any(tf => tf.Intersect(fc) == FaceIntersectionFaceResult.Intersecting)))
{
return true;
} //没有相交则继续
//找到梁与柱相交面
var matchedItem =
columnFaces.Where(
x => (x as PlanarFace).SafelyFaceNormal().IsAlmostEqualTo(-beamLine) ||
(x as PlanarFace).SafelyFaceNormal().IsAlmostEqualTo(beamLine)); var sp = line.GetEndPoint();
var ep = line.GetEndPoint(); //梁的端点能否投影到柱的相交面上
if (matchedItem.Any())
{
var canProject = matchedItem.Any(face => face.Project(sp) != null || face.Project(ep) != null);
if (canProject && isLower)
{
return true;
}
}
}
else if (bc is Arc)
{
var sp = bc.GetEndPoint();
var ep = bc.GetEndPoint(); var points = bc.Tessellate().Where(x => !x.IsAlmostEqualTo(sp) && !x.IsAlmostEqualTo(ep));
var closeSp = points.FirstOrDefault();
var closeEp = points.LastOrDefault();
var tangentSp = closeSp - sp;
var tangentEp = closeEp - ep; //找到梁与柱相交面
var matchedItem =
columnFaces.Where(x => (x as PlanarFace).SafelyFaceNormal().AngleTo(-tangentSp) < UnitConverter.AngleToRad() ||
(x as PlanarFace).SafelyFaceNormal().AngleTo(tangentSp) < UnitConverter.AngleToRad() ||
(x as PlanarFace).SafelyFaceNormal().AngleTo(-tangentEp) < UnitConverter.AngleToRad() ||
(x as PlanarFace).SafelyFaceNormal().AngleTo(tangentEp) < UnitConverter.AngleToRad()); //梁的端点能否投影到柱的相交面上
if (matchedItem.Any() && isLower)
{
var isInsect = columnFaces.Any(fc => beamFaces.Any(x => x.Intersect(fc) == FaceIntersectionFaceResult.Intersecting));
var canProject = matchedItem.Any(face => face.Project(sp) != null || face.Project(ep) != null);
if ((isInsect || canProject) && isLower)
{
return true;
}
}
}
}
}
}
catch (Exception)
{
return false;
} return false;
}
B. 判断墙构件是否为当前梁的支座
墙的判断与柱类似,但是墙没有LocationPoint,但有LocationCurve,所以是这样的:

private static bool IsWallBeSeatForBeam(Element currentBeam, Element jointWall)
{
try
{
if (jointWall is Wall)
{
var currentWall = jointWall as Wall;
var minArea = 0.1;
var wallBottomFace = FaceUtils.GetBottomFace(currentWall, minArea);
var beamBottomFace = FaceUtils.GetBottomFace(currentBeam, minArea);
//墙的下底面低于梁的下底面
bool isLower = wallBottomFace.Origin.Z < beamBottomFace.Origin.Z; //取LocationCurve
var wallLocationCurve = currentWall.Location as LocationCurve;
var beamLocationCurve = currentBeam.Location as LocationCurve; if (wallLocationCurve != null && beamLocationCurve != null)
{
//1.Wall的Location在Beam的Location下面
//2.Wall中有点可以投影到Beam的下底面
//3.Beam中有点可以投影到Wall的下底面
if (wallLocationCurve.Curve.Tessellate().Any(pt => beamBottomFace.Project(pt) != null ||
beamLocationCurve.Curve.Tessellate().Any(x => wallBottomFace.Project(x) != null && isLower)))
{
return true;
} //侧面关系
else
{
var bc = beamLocationCurve.Curve;
var wallFaces = FaceUtils.GetSideFaces(currentWall);
var beamFaces = FaceUtils.GetSideFaces(currentBeam);
var line = bc as Line;
if (line != null)
{
var beamLine = line.Direction; //梁两端的面
var terminalFaces =
beamFaces.Where(x => (x as PlanarFace).SafelyFaceNormal().IsAlmostEqualTo(beamLine) ||
(x as PlanarFace).SafelyFaceNormal().IsAlmostEqualTo(-beamLine));
//判断梁的两端面与支座梁的侧面有没有相交
if (wallFaces.Any(fc => terminalFaces.Any(tf => tf.Intersect(fc) == FaceIntersectionFaceResult.Intersecting)))
{
return true;
} //没有相交则继续
//找到梁与墙相交面
var matchedItem =
wallFaces.Where(x => (x as PlanarFace).SafelyFaceNormal().IsAlmostEqualTo(-beamLine) ||
(x as PlanarFace).SafelyFaceNormal().IsAlmostEqualTo(beamLine)); var sp = line.GetEndPoint();
var ep = line.GetEndPoint(); //梁的端点能否投影到墙的相交面上
if (matchedItem.Any())
{
var canProject = matchedItem.Any(face => face.Project(sp) != null || face.Project(ep) != null);
if (canProject && isLower)
{
return true;
}
}
}
else if (bc is Arc)
{
var sp = bc.GetEndPoint();
var ep = bc.GetEndPoint(); var points = bc.Tessellate().Where(x => !x.IsAlmostEqualTo(sp) && !x.IsAlmostEqualTo(ep));
var closeSp = points.FirstOrDefault();
var closeEp = points.LastOrDefault();
var tangentSp = closeSp - sp;
var tangentEp = closeEp - ep;
//找到梁与墙相交面
var matchedItem =
wallFaces.Where(x => (x as PlanarFace).SafelyFaceNormal().AngleTo(-tangentSp) < UnitConverter.AngleToRad() ||
(x as PlanarFace).SafelyFaceNormal().AngleTo(tangentSp) < UnitConverter.AngleToRad() ||
(x as PlanarFace).SafelyFaceNormal().AngleTo(-tangentEp) < UnitConverter.AngleToRad() ||
(x as PlanarFace).SafelyFaceNormal().AngleTo(tangentEp) < UnitConverter.AngleToRad()); //梁的端点能否投影到墙的相交面上
if (matchedItem.Any())
{
var isInsect = wallFaces.Any(fc => beamFaces.Any(x => x.Intersect(fc) == FaceIntersectionFaceResult.Intersecting));
var canProject = matchedItem.Any(face => face.Project(sp) != null || face.Project(ep) != null);
if ((isInsect || canProject) && isLower)
{
return true;
}
}
}
}
}
}
}
catch (Exception)
{
return false;
} return false;
}
C. 判断梁构件是否为当前梁的支座,这块是最最最烦的。
为什么?因为:

下面是梁作为另一个梁的支座的完整思路:

如果两个构件不是上下关系,那就要检查侧面相交关系。
我这里使用了若干个条件:conditionOne && (conditionTwo || conditionThree || conditionSp)

private static bool IsBeamBeSeatForBeam(Element currentBeam, Element jointBeam)
{
try
{
var beamLocationCurve = currentBeam.Location as LocationCurve;
var seatBeamLocationCurve = jointBeam.Location as LocationCurve;
var beamFaces = FaceUtils.GetSideFaces(currentBeam);
var seatBeamFaces = FaceUtils.GetSideFaces(jointBeam);
var seatBeamBottomFace = FaceUtils.GetBottomFace(jointBeam); if (beamLocationCurve != null && seatBeamLocationCurve != null)
{
var bc = beamLocationCurve.Curve;
if (bc is Line)
{
var beamLine = (bc as Line).Direction;
var sp = bc.GetEndPoint();
var ep = bc.GetEndPoint(); var matchedItem =
seatBeamFaces.Where(x => (x as PlanarFace).SafelyFaceNormal().IsAlmostEqualTo(-beamLine) ||
(x as PlanarFace).SafelyFaceNormal().IsAlmostEqualTo(beamLine) ||
(x as PlanarFace).SafelyFaceNormal().AngleTo(beamLine) < UnitConverter.AngleToRad() ||
(x as PlanarFace).SafelyFaceNormal().AngleTo(-beamLine) < UnitConverter.AngleToRad()); if (matchedItem.Any())
{
//支座梁在主体梁的下方
var canBeamCurvePointProjectToSeatBeamBottomFace =
bc.Tessellate().Any(x => seatBeamBottomFace.Project(x) != null); if (canBeamCurvePointProjectToSeatBeamBottomFace)
{
return true;
}
} //支座梁在主体梁的侧面
//获取梁的两端的面
var terminalFaces =
beamFaces.Where(x => (x as PlanarFace).SafelyFaceNormal().IsAlmostEqualTo(beamLine) ||
(x as PlanarFace).SafelyFaceNormal().IsAlmostEqualTo(-beamLine)); if (terminalFaces.Count() != )
{
terminalFaces = beamFaces;
} //判断梁的两端面与支座梁的侧面有没有相交
var result = BeamHasSeatWithBeam(terminalFaces, seatBeamFaces, beamLine, matchedItem, sp, ep);
if (result)
{
return true;
}
}
else if (bc is Arc)
{
var sp = bc.GetEndPoint();
var ep = bc.GetEndPoint();
var points = bc.Tessellate().Where(x => !x.IsAlmostEqualTo(sp) && !x.IsAlmostEqualTo(ep));
var closeSp = points.FirstOrDefault();
var closeEp = points.LastOrDefault();
var tangentSp = closeSp - sp;
var tangentEp = closeEp - ep;
var matchedItem =
seatBeamFaces.Where(x => (x as PlanarFace).SafelyFaceNormal().AngleTo(-tangentSp) < UnitConverter.AngleToRad() ||
(x as PlanarFace).SafelyFaceNormal().AngleTo(tangentSp) < UnitConverter.AngleToRad() ||
(x as PlanarFace).SafelyFaceNormal().AngleTo(-tangentEp) < UnitConverter.AngleToRad() ||
(x as PlanarFace).SafelyFaceNormal().AngleTo(tangentEp) < UnitConverter.AngleToRad()); if (matchedItem.Any())
{
var isInsect = seatBeamFaces.Any(fc => beamFaces.Any(x => x.Intersect(fc) == FaceIntersectionFaceResult.Intersecting)); var canProject = matchedItem.Any(face => face.Project(sp) != null || face.Project(ep) != null);
if (isInsect || canProject)
{
return true;
}
}
}
}
}
catch (Exception)
{
return false;
} return false;
}
private static bool BeamHasSeatWithBeam(IEnumerable<Face> terminalFaces, IEnumerable<Face> seatBeamFaces, XYZ beamLine,
IEnumerable<Face> seatBeamSpecialFaces, XYZ startpoint, XYZ endpoint)
{
//梁任意端点能投影到支座梁的对迎面
var conditionSp = seatBeamSpecialFaces.Any() &&
seatBeamSpecialFaces.Any(x => x.Project(startpoint) != null || x.Project(endpoint) != null); foreach (var tf in terminalFaces)
{
foreach (var fc in seatBeamFaces)
{
//支座梁的Face生成Solid
var seatBeamCl = (fc as PlanarFace).GetEdgesAsCurveLoops().ToList();
Solid seatBeamTempSolid = GeometryCreationUtilities.CreateExtrusionGeometry(seatBeamCl,
fc.ComputeNormal(new UV().Negate()),
UnitUtils.ConvertToInternalUnits(0.5, DisplayUnitType.DUT_MILLIMETERS));
var seatBeamDestFaces = (from object f in seatBeamTempSolid.Faces where (f as PlanarFace).SafelyFaceNormal().IsAlmostEqualTo(beamLine) ||
(f as PlanarFace).SafelyFaceNormal().IsAlmostEqualTo(-beamLine) ||
(f as PlanarFace).Project(startpoint) != null ||
(f as PlanarFace).Project(endpoint) != null select f as PlanarFace).ToList();
if (!seatBeamDestFaces.Any())
{
seatBeamDestFaces = (from object f in seatBeamTempSolid.Faces select f as PlanarFace).ToList();
} //梁的Face生成Solid
var beamCL = (tf as PlanarFace).GetEdgesAsCurveLoops().ToList();
Solid beamTempSolid = GeometryCreationUtilities.CreateExtrusionGeometry(beamCL,
tf.ComputeNormal(new UV().Negate()),
UnitUtils.ConvertToInternalUnits(0.5, DisplayUnitType.DUT_MILLIMETERS));
var beamDestFaces = (from object f in beamTempSolid.Faces select f as PlanarFace).ToList(); //梁与支座梁有相交
var conditionOne = seatBeamDestFaces.Any(x=> tf.Intersect(x) == FaceIntersectionFaceResult.Intersecting ||
x.Project(startpoint) != null || x.Project(endpoint) != null) ||
seatBeamDestFaces.Any(x=> beamDestFaces.Any(y=>y.Intersect(x) == FaceIntersectionFaceResult.Intersecting)); var fc1 = (tf as PlanarFace).SafelyFaceNormal();
var conditionTwo = seatBeamDestFaces.Any(x=> fc1.IsAlmostEqualTo(x.SafelyFaceNormal()) ||
fc1.IsAlmostEqualTo(-x.SafelyFaceNormal()));
var conditionThree = seatBeamDestFaces.Any(x =>
fc1.AngleTo(x.SafelyFaceNormal()) < UnitConverter.AngleToRad() ||
fc1.AngleTo(x.SafelyFaceNormal()) < UnitConverter.AngleToRad());
if (conditionOne && (conditionTwo || conditionThree || conditionSp))
{
return true;
}
}
}
return false;
}
代码中有一些自己封装的函数,比如求构件所有底面,求构件所有侧面,比较简单,这里就不暴露了。本篇主要以思路为主,掌握了思路代码也就清晰了。
三、结尾
本文只是个抛砖引玉,改造的空间是非常大的,我这里只判断true,false。还可以输出梁的支座构件做进一步分析。
算法本身还可以改进,在Revit模型中扣减是一个大难题,如何应对复杂扣减情况下的梁支座判断是非常必要的,特别是判断梁作为另一个梁的支座时尤其小心,很容易就因为梁上面的一块板导致梁与梁之间的扣减关系变复杂从而导致IsBeamBeSeatForBeam()适应性变低。最好的解决方式是先检查构件之间的扣减关系是否正确(扣减部分一直是Revit二次开发的难点),修正之后再调用上述函数。
对算法有建议或者意见的欢迎在评论区留言!
《原创,转载请注明来源》
来自:airforce094
【Revit API】梁构件支座检查算法的更多相关文章
- Revit API 判断一个构件在某个视图中的可见性
查看 Revit API.发现有Element::IsHidden这个方法.通过UI创建一个element,注意要使得这个element在某些视图可见,但是在另一些视图不可见.运行下面的方法,你会发现 ...
- Revit API 操作共享参数和项目参数
1.获取共享参数 private string GetSharInfo(Autodesk.Revit.ApplicationServices.Application revitApp) { Strin ...
- Revit API射线法读取空间中相交的元素
Revit API提供根据射线来寻找经过的元素.方法是固定模式,没什么好说.关键代码:doc.FindReferencesWithContextByDirection(ptStart, (ptEnd ...
- Revit API 加载族并生成实例图元
在Revit API中加载族可以使用Doc.LoadFamily方法,传入要加载的族文件路径名,但是这种方式有一种缺点,就是如果族文件在当前工程中没有加载的话则返回成功,如果已经加载过,则返回失败,也 ...
- 百度地图API位置偏移的校准算法
转自极客人原文 百度地图API位置偏移的校准算法 在开始使用百度地图API进行开发时可能会遇到一件相当奇怪的事情,使用百度定位的经纬度在地图上显示相当不准确,这一问题我在微信开发和安卓开始时都遇到过. ...
- 【Revit API】获取链接模型中构件
话不多说,直接代码 var doc = commandData.Application.ActiveUIDocument.Document; FilteredElementCollector link ...
- 【Revit API】梁的净高分析
原理就是,先从梁的LocationCurve上取点,然后向板的上表面投影.如果有投影点,再从投影点(板上)向梁的底面投影,这时候如果有投影点的话就能得到距离了. 运用该分析的第一条件是梁是在板的上方, ...
- 【Revit API】调用Revit内部命令PostableCommand
Revit内置了一些命令,直接调用Revit操作方式. 可以去API文档查询PostableCommand枚举,还是很多的. 话不多说,直接上代码 var commandId = RevitComma ...
- 【Revit API】创建相机视角
在Revit中有一个相机功能可以以相机视角产生一个视图.一开始我在Revit2016的API文档中找关键词Camera,但是没什么收获. 其实这个相机功能的真正核心是创建透视视图:View3D.Cre ...
随机推荐
- python进阶学习(二)
本节学习图形用户界面 ------------------------ 本节介绍如何创建python程序的图形用户界面(GUI),也就是那些带有按钮和文本框的窗口.这里介绍wxPython : 下载地 ...
- 推荐一款接口文档在线管理系统-MinDoc
项目简介 MinDoc 是一款针对IT团队开发的简单好用的文档管理系统. MinDoc 的前身是 SmartWiki 文档系统.SmartWiki 是基于 PHP 框架 laravel 开发的一款文档 ...
- docker的简单搭建(java/tomcat 环境)
1.一副图简单了解下docker的布局,它是虚拟的,docker分为私服.镜像.容器三个模块 一般从私服pull镜像,镜像run一个容器,我们把容器作为一个虚拟服务,里面可以独立运行进程有独立的内网I ...
- asp.net core 2.0 web api基于JWT自定义策略授权
JWT(json web token)是一种基于json的身份验证机制,流程如下: 通过登录,来获取Token,再在之后每次请求的Header中追加Authorization为Token的凭据,服务端 ...
- FFmpeg 常用命令收集
FFmpeg 常用命令 合并视频 ffmpeg -i "KTDS-820A_FHD.mp4" -c copy -bsf:v h264_mp4toannexb -f mpegts i ...
- 团队作业8----第二次项目冲刺(beta阶段)5.25
Day7-05.25 1.每日会议 会议内容: 1.今日对整个项目进行了一个总结. 2.讨论了这次项目中的不足和每个人的贡献. 讨论照片:拍摄者 周迪 2.任务分配情况: 每个人的工作分配表: 队员 ...
- 201521123029《Java程序设计》第七周学习总结
1. 本周学习总结 以你喜欢的方式(思维导图或其他)归纳总结集合相关内容. 参考资料:XMind 答: 2. 书面作业 1. ArrayList代码分析 1.1 解释ArrayList的contain ...
- 201521123006 《Java程序设计》第4周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 本周除了继承,我们还重点学习了多态. (1)多态性在于有相同的形态,却是不同的行为或者说是不 ...
- JAVA课程设计——团队博客
JAVA课程设计--团队博客 1. 团队名称.团队成员介绍(需要有照片) 团队名称:"小羊吃蓝莓"小游戏 团队成员介绍: 成员 班级 学号 廖怡洁 网络1513 201521123 ...
- Java课程设计 学生基本信息管理个人博客
学生基本信息管理系统个人博客 团队课程设计链接 http://www.cnblogs.com/ll321/p/7067598.html 个人负责模块 负责部分界面设计,处理代码: 处理部分数据库数据. ...