【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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...