【Revit API】梁構件支座檢查演算法

来源:http://www.cnblogs.com/lovecsharp094/archive/2017/10/04/7624208.html
-Advertisement-
Play Games

一、前言 應該是第二次寫關於Revit API的博文了。雖然在BIM企業中工作,從事桌面BIM軟體開發,但是我是不怎麼喜歡寫Revit API相關的代碼。平時更多的是在寫界面展示,架構維護,授權驗證這塊。為什麼不喜歡Revit API呢?其實Autodesk封裝的這套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 = 0; //獲取相交構件 var jointElements = BaseGeomUtils.GetJointElements(element); if (jointElements != null && jointElements.Any()) { //檢查柱的 foreach (var column in jointElements) { if (column.IsStructuralColumn() && IsCoulmnBeSeatForBeam(element, column)) { counter++; } if (counter == 2) { return true; } } //檢查牆的 foreach (var wall in jointElements) { if (IsWallBeSeatForBeam(element, wall)) { counter++; } if (counter == 2) { return true; } } //檢查梁的 foreach (var beam in jointElements) { if (beam.IsStructuralBeam() && IsBeamBeSeatForBeam(element, beam)) { counter++; } if (counter == 2) { 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(0);
                      var ep = line.GetEndPoint(1);

                      //梁的端點能否投影到柱的相交面上
                      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(0);
                            var ep = bc.GetEndPoint(1);

                            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(30) ||
                                (x as PlanarFace).SafelyFaceNormal().AngleTo(tangentSp) < UnitConverter.AngleToRad(30) ||
                                (x as PlanarFace).SafelyFaceNormal().AngleTo(-tangentEp) < UnitConverter.AngleToRad(30) ||
                                (x as PlanarFace).SafelyFaceNormal().AngleTo(tangentEp) < UnitConverter.AngleToRad(30));

                            //梁的端點能否投影到柱的相交面上
                            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(0);
                                var ep = line.GetEndPoint(1);

                                //梁的端點能否投影到牆的相交面上
                                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(0);
                                var ep = bc.GetEndPoint(1);

                                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(30) ||
                                (x as PlanarFace).SafelyFaceNormal().AngleTo(tangentSp) < UnitConverter.AngleToRad(30) ||
                                (x as PlanarFace).SafelyFaceNormal().AngleTo(-tangentEp) < UnitConverter.AngleToRad(30) ||
                                (x as PlanarFace).SafelyFaceNormal().AngleTo(tangentEp) < UnitConverter.AngleToRad(30));


                                //梁的端點能否投影到牆的相交面上
                                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(0);
                        var ep = bc.GetEndPoint(1);

                        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(30) ||
                                               (x as PlanarFace).SafelyFaceNormal().AngleTo(-beamLine) < UnitConverter.AngleToRad(30));

                        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() != 2)
                        {
                            terminalFaces = beamFaces;
                        }

                        //判斷梁的兩端面與支座梁的側面有沒有相交
                        var result = BeamHasSeatWithBeam(terminalFaces, seatBeamFaces, beamLine, matchedItem, sp, ep);
                        if (result)
                        {
                            return true;
                        }
                    }
                    else if (bc is Arc)
                    {
                        var sp = bc.GetEndPoint(0);
                        var ep = bc.GetEndPoint(1);
                        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(30) ||
                            (x as PlanarFace).SafelyFaceNormal().AngleTo(tangentSp) < UnitConverter.AngleToRad(30) ||
                            (x as PlanarFace).SafelyFaceNormal().AngleTo(-tangentEp) < UnitConverter.AngleToRad(30) ||
                            (x as PlanarFace).SafelyFaceNormal().AngleTo(tangentEp) < UnitConverter.AngleToRad(30));


                        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(30) || fc1.AngleTo(x.SafelyFaceNormal()) < UnitConverter.AngleToRad(30)); if (conditionOne && (conditionTwo || conditionThree || conditionSp)) { return true; } } } return false; }

 

代碼中有一些自己封裝的函數,比如求構件所有底面,求構件所有側面,比較簡單,這裡就不暴露了。本篇主要以思路為主,掌握了思路代碼也就清晰了。

 

三、結尾

       本文只是個拋磚引玉,改造的空間是非常大的,我這裡只判斷true,false。還可以輸出梁的支座構件做進一步分析。

        演算法本身還可以改進,在Revit模型中扣減是一個大難題,如何應對複雜扣減情況下的梁支座判斷是非常必要的,特別是判斷梁作為另一個梁的支座時尤其小心,很容易就因為梁上面的一塊板導致梁與梁之間的扣減關係變複雜從而導致IsBeamBeSeatForBeam()適應性變低。最好的解決方式是先檢查構件之間的扣減關係是否正確(扣減部分一直是Revit二次開發的難點),修正之後再調用上述函數。

        對演算法有建議或者意見的歡迎在評論區留言!

 

《原創,轉載請註明來源》

來自:airforce094


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...