1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        【SketchUp圖元的族譜】附庸的附庸

        共 10700字,需瀏覽 22分鐘

         ·

        2024-03-21 06:30

        本系列“圖元族譜”的上一篇“對影成三人”介紹了 SketchUp 一個組件(或組件內(nèi)的圖元)的“影子”圖元,提供了一個返回所有“影子”圖元路徑(InstancePath)的方法,通過一個組件實例或組件定義,向上查找包含該圖元的父模型,從而查找所有在其他位置的同定義組件實例。這是一種自下而上的路徑搜索邏輯,將關(guān)注另一種查找方向,即自上而下的路徑搜索。

        501f98cdeaa682e8dc84998e16ad5672.webp

        通過一個組件實例向下查找全部其包含的全部子模型

        例如下圖展示的一個群組,其內(nèi)部是 20 個定義相同的組件,每個組件中有 6 個面 12 條邊,所以群組中總計有 120 個面 240 條邊。但是對于模型存儲來說,群組中僅有 20 個位置信息(Transformation)不同的組件實例(ComponentInstance),所有組件共用 6 個面 12 條邊的定義。如果現(xiàn)在需要知道群組中每一個平面和邊線的位置,則需要從這個群組出發(fā),向下查找所有 120 個面和 240 條邊;如果群組內(nèi)的組件實例內(nèi)部還有組件,就繼續(xù)向下查找。由于這 20 個組件內(nèi)部的圖元在模型定義中和上兩層的群組沒有直接的關(guān)聯(lián),需要借助中間層實現(xiàn)下一層的查找,就像歐洲中世紀的諺語“我的附庸的附庸不是我的附庸”一樣,因此用“附庸的附庸”作為本期的題目。

        ae62f76753d9aca3aaf29c9e9f89687c.webp

        群組中包含20個相同定義的組件,每個組件中有6個面12條邊

        一、子模型的搜索

        SketchUp 模型中呈現(xiàn)的每一個圖元,都通過實例路徑進行表示,無論組件復(fù)用多少次,每一個組件的每一個圖形要素都有唯一的實例路徑(InstancePath)用于空間定位(詳見上一篇第二部分)。所以獲取一個組件內(nèi)所有圖形的位置,關(guān)鍵在于逐層獲取這些圖形的實例路徑,這同樣需要使用到遞歸的方法,與上一篇查找“影子”圖元的邏輯是相似的。只不過當時是通過組件定義(definition)去尋找所有同定義的實例(instance),而現(xiàn)在是通過組件實例去找所有定義中的圖元,查找路徑的邏輯可以用下圖表示。

        363987aa1c2ac06f9fae29a1f1d4a2b8.webp

        上一篇文章中構(gòu)造了一個 InstancePathTree 類,通過 add_child 方法將父模型記錄為當前模型的子節(jié)點,從而實現(xiàn)組件嵌套樹狀結(jié)構(gòu)的解析。這里同樣可以使用 InstancePathTree 類,將子模型作為當前模型的子節(jié)點,即可反方向構(gòu)建樹狀結(jié)構(gòu)。

        在本部分末,呈現(xiàn)了在 InstancePathTree 類中新增的幾個類方法和實例方法,第 6 行的 subordinates 方法通過調(diào)用先前的 recur_paths 方法遞歸生成樹狀結(jié)構(gòu)的每一條路徑。由于創(chuàng)建樹的方向不同,需要用 .reverse 方法對先前自下而上的路徑結(jié)果進行翻轉(zhuǎn)。

        第 15 行的 recur_find_subordinate 類方法,用于遞歸創(chuàng)建當前節(jié)點模型的子節(jié)點,當模型擁有 :definition 方法時,說明當前模型是群組或者組件,存在子模型,所以調(diào)用 add_child 方法將組件定義中的所有子模型創(chuàng)建為子節(jié)點,并分別對子節(jié)點進行相同的遞歸運算。如果當前節(jié)點的模型是 nil 則表示當前節(jié)點是世界模型,從 Sketchup .active_model .entities 中讀取子模型信息。 如果不是組件或者群組,其他圖元調(diào)用此方法不會有任何動作,也就不會進入下一層遞歸,不過更好的處理方式是先判斷圖元類型再決定是否遞歸,性能效果要好些。

        第 32 行和第 48 行的兩個類方法都是通過特定的條件返回所有子模型的實例路徑。其中 check_subordinate_instancepath 方法通過一個路徑返回所有次級路徑,例如文章開頭的案例中,如果雙擊打開群組,將當前路徑作為參數(shù)執(zhí)行該方法,即可返回 120 個平面和 240 條邊線。

        a56f1daef4b5b0f608b7f26ae6dba15e.webp

          check_subordinate_definition  方法則以一個組件定義為參數(shù),判斷組件定義內(nèi)的所有圖元路徑,這個方法對于繪制臨時的組件圖形很有幫助。

        以下是 InstancePathTree 類新增的代碼部分:

              
                
                  class InstancePathTree
                
              
              
                  # 此處省略了部分上一篇文章中呈現(xiàn)的代碼
              
              
                  # 只展示新增的代碼
              
              
                  # 因此直接復(fù)制粘貼是無法運行的
              
              
                  # 如需復(fù)制完整代碼可以見文末的鏈接
              
              
                  def subordinates
              
              
                    root_path = @instpath.to_a
              
              
                    result=[]
              
              
                    recur_paths(result,[])
              
              
                    return result.map{|path|Sketchup::InstancePath.new(root_path+path.compact.reverse)}
              
              
                  end
              
              
              
                  class << self
              
              
                    # 此處省略了部分上一篇文章中呈現(xiàn)的代碼
              
              
                    def recur_find_subordinate(node)
              
              
                      entity = node.instance
              
              
                      if entity.respond_to?(:definition) then
              
              
                        entity.definition.entities.each{|ent|
              
              
                          child = node.add_child(ent)
              
              
                          recur_find_subordinate(child)
              
              
                        }
              
              
                      elsif node.instance.nilthen
              
              
                        Sketchup.active_model.entities.each{|ent|
              
              
                          child = node.add_child(ent)
              
              
                          recur_find_subordinate(child)
              
              
                        }
              
              
                      end
              
              
                    end
              
              
                    private :recur_find_subordinate
              
              
              
                    # 返回path之下的所有path
              
              
                    def check_subordinate_instancepath(instance_path)
              
              
                      instance_path=[] if instance_path.nil?
              
              
                      instpath = Sketchup::InstancePath.new(instance_path)
              
              
                      if instpath.empty? then
              
              
                        result = InstancePathTree.new(nil)
              
              
                        result.instpath = []
              
              
                      else
              
              
                        instpath_ary = instpath.to_a
              
              
                        result = InstancePathTree.new(instpath_ary.pop)
              
              
                        result.instpath = instpath_ary
              
              
                      end
              
              
                      recur_find_subordinate(result)
              
              
                      return result
              
              
                    end
              
              
              
                    # 返回definition之下的所有path
              
              
                    def check_subordinate_definition(definition)
              
              
                      instpath=[] if instpath.nil?
              
              
                      raise ArgumentError.new("參數(shù)definition必須要有entities成員。") unless definition.respond_to?(:entities)
              
              
                      result = InstancePathTree.new(nil)
              
              
                      result.instpath = []  
              
              
                      definition.entities.each{|ent|
              
              
                        child = result.add_child(ent)
              
              
                        recur_find_subordinate(child)
              
              
                      }
              
              
                      return result
              
              
                    end
              
              
              
                    # 根據(jù)參數(shù)選擇性調(diào)用前兩個方法
              
              
                    def check_subordinate(instpath_or_definition)
              
              
                      if instpath_or_definition.respond_to?(:entities) then
              
              
                        check_subordinate_definition(instpath_or_definition)
              
              
                      else
              
              
                        check_subordinate_instancepath(instpath_or_definition)
              
              
                      end
              
              
                    end
              
              
                  end
              
              
                
                  end
                
              
            


        二、具體的使用示例

        首先將整個 InstancePathTree 類的代碼復(fù)制到控制臺中執(zhí)行,或者直接用 load 方法加載 “instpath_helper.rb” 文件(在本人github/gitee主頁中可以找到,鏈接在文末)。之后就可以在控制臺中測試前文介紹的方法,以下提供幾個案例。

        ①返回整個模型的全部路徑

        其中第 1 行最后的 ;nil 用于避免將 paths 結(jié)果打印在控制臺輸出中。這是因為,如果模型很大,打印結(jié)果將會消耗大量時間,造成軟件假死。

              
                paths = InstancePathTree.check_subordinate([]).subordinates;nil
              
              
                paths.length
              
              
                
                  #=> 1319
                
              
            


        ②返回當前路徑之下的全部路徑

        其中第 1 行將當前路徑保存在變量 apath 中,在第 2 行作為參數(shù)返回此路徑下的結(jié)果。

              
                apath = Sketchup.active_model.active_path
              
              
                paths = InstancePathTree.check_subordinate(apath).subordinates;nil
              
              
                paths.length
              
              
                
                  #=> 348
                
              
            


        ③返回某個組件內(nèi)部的全部路徑

        其中第 1~2 行將名稱為 "組件#1" 的組件的定義保存在變量 cpmdef 中,在第 4 行作為參數(shù)返回該組件定義之下的全部路徑。

              
                defs = Sketchup.active_model.definitions
              
              
                cpmdef = defs.select{|d|d.name=="組件#1"}[0]
              
              
                
                  #=> #<Sketchup::ComponentDefinition:0x000001bac7641300>
                
              
              
                paths = InstancePathTree.check_subordinate(cpmdef).subordinates;nil
              
              
                paths.length
              
              
                
                  #=> 35
                
              
            


        ④僅返回邊線的路徑

        借用上一個案例中返回的 paths 結(jié)果,可以進一步篩選組件中的所有以邊線圖元為末梢的路徑。其中 .select 方法表示篩選,其后的花括號內(nèi)條件中的 .leaf 是 InstancePath 的方法,返回最末梢的圖元。

              
                spath = paths.select{|path|path.leaf.is_a? Sketchup::Edge}
              
              
                p spaths
              
              
                
                  #=> [#<Sketchup::InstancePath:0x000001bacf8a35f0>, 
                
              
              
                
                  #=> ...,
                
              
              
                
                  #=> #<Sketchup::InstancePath:0x000001bacf8a1ae8>]
                
              
            


        ⑤具體實例路徑下所有邊線的坐標顯示

        多層的嵌套會讓組件中的坐標處理變得復(fù)雜而不易想象,通過路徑的獲取可以簡化這個坐標轉(zhuǎn)換的過程,因為每一個路徑都能直接返回對應(yīng)的相對位置變換矩陣,給多層嵌套的模型坐標計算提供便利。例如以下代碼返回一個具體路徑的組件內(nèi)所有邊線的端點坐標。

              
                
                  # 先打開要測試的組件實例路徑
                
              
              
                test_path = Sketchup.active_model.active_path
              
              
                Sketchup.active_model.active_path = []
              
              
                
                  # 自動退出組件編輯,避免圖元所在entities與active_entities一致而返回世界坐標
                
              
              
                paths = InstancePathTree.check_subordinate(test_path).subordinates;nil
              
              
                paths.select!{|path|path.leaf.is_a? Sketchup::Edge}
              
              
                paths.each{|path|
              
              
                  trans = path.transformation
              
              
                  v1 = path.leaf.vertices[0]
              
              
                  v2 = path.leaf.vertices[1]
              
              
                  p1 = trans*v1.position
              
              
                  p2 = trans*v2.position
              
              
                  puts "Line #{p1} To #{p2}"
              
              
                };nil
              
              
                
                  #=> Line (254 m, 254 m, 0 m) To (254 m, 254 m, 168.4105 m)
                
              
              
                
                  #=> Line (254 m, 254 m, 0 m) To (254 m, 508 m, 0 m)
                
              
              
                
                  #=> Line (508 m, 508 m, 0 m) To (508 m, 254 m, 0 m)
                
              
              
                
                  #=> ...
                
              
            


        三、圖元族譜的總結(jié)

        到目前為止,“SketchUp 圖元的族譜”系列的三篇文章已經(jīng)全部結(jié)束,第一篇“包含與嵌套”介紹 SketchUp 中群組和組件的嵌套方式,區(qū)分了組件實例與組件定義的區(qū)別,并對世界坐標系和組件坐標系進行了辨析,為后兩篇內(nèi)容提供了一些背景內(nèi)容。而第二篇“對影成三人”和本篇“附庸的附庸”則分別從向上和向下兩個搜索方向介紹如何通過模型中一個確切的結(jié)構(gòu)位置,計算出與之相關(guān)的所有圖元實例路徑。兩個功能都需要借助遞歸的方式構(gòu)建模型結(jié)構(gòu)樹,因此都需要使用 InstancePathTree 類實現(xiàn)。

        e33787d6438c33658991ede21d07e85a.webp

        三篇文章對應(yīng)的模型嵌套結(jié)構(gòu)

        而兩篇如此不厭其煩地 構(gòu)造 自定義類 現(xiàn)路徑的查找,都是為了更便捷地對嵌套模型的坐標轉(zhuǎn)換進行描述。模型嵌套往往會讓人對不同層圖元的坐標產(chǎn)生困惑,而 InstancePath 是模型坐標定位的本質(zhì),直接計算符合條件的 InstancePath 就可以通過 .transformation 方法便捷地獲取代表相對位置的變換矩陣 ,只需要將路徑末端圖元 .leaf 的坐標與相對位置變換矩陣相乘,就能輕易得到這個末端圖元的世界坐標,這也就是兩篇文章中 InstancePathTree 類的意義。

        (完)



        從SU-2022-01期開始,本人的 SketchUp Ruby “小功能與靈感” 的文章中涉及的功能會在 Gitee/GitHub 中相應(yīng)更新。這樣一來,如果日后發(fā)現(xiàn)存在bug需要修正或者是想追加相關(guān)的功能,都有極大的便利。

        這個代碼倉庫同樣也包含大部分之前文章的代碼,可以訪問以下網(wǎng)址查看,也歡迎大家共同提交修改:

        https://gitee.com/apiglio/sketchup-script-tool

        https://github.com/Apiglio/SketchupScriptTool

        本期代碼在 class/ instpath_helper.rb  文件中,文中的 InstancePathTree 類 按如下方式調(diào)用:

              
                
                  #選擇一個組件
                
              
              
                sels = Sketchup.active_model.selection
              
              
                inst = sels[0]
              
              
                
                  # 如果查找當前組件定義中的所有路徑:
                
              
              
                n = InstancePathTree.check_subordinate(inst.definition)
              
              
                
                  # 如果查找整個模型的所有路徑:
                
              
              
                n = InstancePathTree.check_definition(nil)
              
              
                p n.subordinates
              
              
                
                  #=> [...]
                
              
            

        之前更新的教程到組件部分之后一直就沒有再更新,總覺得需要一個比較好的講述邏輯,又希望能夠統(tǒng)一組件、群組和圖像三種圖元,又要兼顧組件定義和定義列表這兩個實體,所以總顯得雜亂無章。因此打算先在這個系列大概聊一聊組件的一些特點,也是給詳細的組件教程進行一個預(yù)熱。

        SketchUp ruby的中文資料相對較少,并且相對小眾,歡迎加入 SketchUp Ruby 自學(xué)俱樂部 Q群(群號:368842817)。



        本文編號:SU-2023-04


        瀏覽 141
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            黄色三级片在线观看 | 乖乖怀孕高h调教1v1小说 | 尤物视频在线观看 | 久久午夜免费 | 性欧美性少妇 | 日韩国一级 | 扒下小娇妻的内裤打屁股 | 成人性生交大片免费观看嘿嘿视频 | 国产欧美日韩一级大片 | 无码操逼在线观看 |