一、前言

        应该是第二次写关于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】梁构件支座检查算法的更多相关文章

  1. Revit API 判断一个构件在某个视图中的可见性

    查看 Revit API.发现有Element::IsHidden这个方法.通过UI创建一个element,注意要使得这个element在某些视图可见,但是在另一些视图不可见.运行下面的方法,你会发现 ...

  2. Revit API 操作共享参数和项目参数

    1.获取共享参数 private string GetSharInfo(Autodesk.Revit.ApplicationServices.Application revitApp) { Strin ...

  3. Revit API射线法读取空间中相交的元素

    Revit API提供根据射线来寻找经过的元素.方法是固定模式,没什么好说.关键代码:doc.FindReferencesWithContextByDirection(ptStart, (ptEnd  ...

  4. Revit API 加载族并生成实例图元

    在Revit API中加载族可以使用Doc.LoadFamily方法,传入要加载的族文件路径名,但是这种方式有一种缺点,就是如果族文件在当前工程中没有加载的话则返回成功,如果已经加载过,则返回失败,也 ...

  5. 百度地图API位置偏移的校准算法

    转自极客人原文 百度地图API位置偏移的校准算法 在开始使用百度地图API进行开发时可能会遇到一件相当奇怪的事情,使用百度定位的经纬度在地图上显示相当不准确,这一问题我在微信开发和安卓开始时都遇到过. ...

  6. 【Revit API】获取链接模型中构件

    话不多说,直接代码 var doc = commandData.Application.ActiveUIDocument.Document; FilteredElementCollector link ...

  7. 【Revit API】梁的净高分析

    原理就是,先从梁的LocationCurve上取点,然后向板的上表面投影.如果有投影点,再从投影点(板上)向梁的底面投影,这时候如果有投影点的话就能得到距离了. 运用该分析的第一条件是梁是在板的上方, ...

  8. 【Revit API】调用Revit内部命令PostableCommand

    Revit内置了一些命令,直接调用Revit操作方式. 可以去API文档查询PostableCommand枚举,还是很多的. 话不多说,直接上代码 var commandId = RevitComma ...

  9. 【Revit API】创建相机视角

    在Revit中有一个相机功能可以以相机视角产生一个视图.一开始我在Revit2016的API文档中找关键词Camera,但是没什么收获. 其实这个相机功能的真正核心是创建透视视图:View3D.Cre ...

随机推荐

  1. 百度鹰眼Java接口调用增删改查实例

    因感觉百度鹰眼的使用场景比较符合实际业务,于是对百度鹰眼做了简单功能调试.刚开始使用springframework封装的RestTemplate,但是测试提示ak参数不存在.后又试了几种方法,均提示a ...

  2. 利用Google浏览器调试js代码

    1.js有两种引入方式,外链和内嵌: 内嵌在浏览中直接调试,外链要在断点处写debugger; 示例代码: <!DOCTYPE html> <html lang="en&q ...

  3. TC358749XBG:HDMI转MIPI CSI芯片简介

    TC358749XBG是一颗HDMI转MIPI CSI功能的视频转换芯片,分辨率:1920*1080,电源3.3/1.8/1.2,通信方式:IIC,封装形式BGA80

  4. ASP.NET Core MVC I/O编程模型

    1. ASP.NET Core MVC I/O编程模型 1.1. I/O编程模型浅析 1.2. 同步阻塞I/O 1.3. 同步非阻塞I/O 1.4. 异步I/O 1.5. 总结 1.1. I/O编程模 ...

  5. CCIE-MPLS VPN-实验手册(上卷)

    看完了看完了看完了,豪爽豪爽豪爽,一个月了,写得挺棒.总共14个mpls vpn的实验,为留下学习的痕迹,原封不动献出. CCIE实验手册 (路由部分-MPLSVPN基础篇) [CCIE]  JUST ...

  6. 转:【Java集合源码剖析】LinkedHashmap源码剖析

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/37867985   前言:有网友建议分析下LinkedHashMap的源码,于是花了一晚上时 ...

  7. unity(Exploder插件)研究

    哎 好久没写博客了 不是因为最近忙 而是比较懒 学的东西不深入 前段时间发现一个很好用的插件叫Exploder(是一个可以制作任何物体的爆炸效果) 好!我们开始我们的炸学校旅程!(O(∩_∩)O哈哈~ ...

  8. 201521123100 《Java程序设计》第3周学习总结

    1. 本周学习总结 初学面向对象,会学习到很多碎片化的概念与知识.尝试学会使用思维导图将这些碎片化的概念.知识组织起来.请使用纸笔或者下面的工具画出本周学习到的知识点.截图或者拍照上传. 2. 书面作 ...

  9. 学号:201521123116 《java程序设计》第二周学习总结

    1. 本章学习总结 一:学习了string的类型,string的对象是不可变的,创建之后不能再修改 二:SET PATH/CLASSPATH和-cp的用法. 三:学习了Java API 文档的使用方法 ...

  10. 201521044091 java 第一周总结

    1.本周学习总结 (1)第一次开始接触java语言,有些用法还是和c和c++有点差异,需要不断去学习 (2)java其实不仅仅一种高级语言,它包括的还有它的整套体系. 2. 书面作业 1.为什么jav ...