<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【SU Ruby教程】幾何與變換(3):變換與變換矩陣

          共 11859字,需瀏覽 24分鐘

           ·

          2021-03-02 09:43

          這一篇繼續(xù)介紹 Geom 模塊的另一個重要概念——變換類。和前兩個部分的概念相同,變換類也有兩種具體的類定義,分別是 Geom:: Transformation 和 Geom:: Transformation2d。其中前者用于 SketchUp 中三維空間的變換;后者用于 Layout,則不在教程內(nèi)容范圍內(nèi)。


          Geom:: Transformation 類是移動圖元的操作工具,也是件實例定位的必要組成。




          幾何與變換(3):變換與變換矩陣


          【本期目錄】

          (1)五種基本變換

          ①單位變換

          ②平移變換

          ③旋轉(zhuǎn)變換

          ④縮放變換

          ⑤坐標(biāo)軸變換

          (3)變換組合

          ①矩陣乘法

          ②逆矩陣

          ③矩陣插值



          (2)應(yīng)用變換

          原點與坐標(biāo)軸變換

          點與向量的變換

          ③圖元的變

          (4)變換矩陣詳解

          ①變換對象的矩陣表示

          ②齊次坐標(biāo)變換矩陣


          (1)四種基本變換


          ①單位變換


          直接通過 .new 方法無參數(shù)創(chuàng)建的變換類實例就是一個單位變換,單位變換表示一個完全沒有變換的變換,相當(dāng)于乘法中的1。使用 .identity? 方法可以判斷一個 Geom:: Transformation 類實例是否是單位變換。

          t = Geom::Transformation.newt.identity?#>> true


          ②平移變換


          像某個方向移動一段距離的變換為平移變換,可以使用 .translation 方法創(chuàng)建這類變換類實例。

          t1 = Geom::Transformation.translation([0,1,2])t2 = Geom::Transformation.translation(Geom::Point3d.new([0,1,2]))t3 = Geom::Transformation.translation(Geom::Vector3d.new([0,1,2]))


          以上三種方法均可以創(chuàng)建平移變換實例,點坐標(biāo)參數(shù)表示將原點移動到該點,而向量參數(shù)的含義亦是如此。另外,也可以將 .translation 改為 .new 方法,以上三種參數(shù)形式同樣可以創(chuàng)建平移變換的實例。不過由于默認(rèn)的創(chuàng)建對象方法參數(shù)形式繁多,分別可以創(chuàng)建不同類型的變換對象。因此為了避免不必要的混淆,推薦使用 .translation 來創(chuàng)建平移變換對象。


          ③旋轉(zhuǎn)變換


          繞一條直線旋轉(zhuǎn)一定角度的變換為旋轉(zhuǎn)變換,可以使用 .rotation 方法創(chuàng)建。

          t1 = Geom::Transformation.rotation([0,0,0],[0,0,1],90.degrees)center = Geom::Point3d.new([0,0,0])normal = Geom::Vector3d.new([0,0,1])t2 = Geom::Transformation.rotation(center,normal,90.degrees)


          以上兩種方法都能夠創(chuàng)建一個繞z軸正半軸90°旋轉(zhuǎn)的變換對象, [center, normal] 即該變換的旋轉(zhuǎn)軸。這里的角度是根據(jù)第二個參數(shù)向量的方向確定的,可以用右手定則記憶(下圖)。



          同樣地,保持參數(shù)類型不變,將 .rotation 換成 .new 也同樣可以創(chuàng)建旋轉(zhuǎn)變換對象,但是出于相同的理由并不推薦。


          ④縮放變換


          以原點為縮放中心,在x軸、y軸和z軸上分別縮放若干倍數(shù)的變換為縮放變換,可以使用 .scaling 方法創(chuàng)建。

          t1 = Geom::Transformation.scaling(3)t2 = Geom::Transformation.scaling(2,3,4)
          pt = Geom::Point3d.new([100,100,-100])t3 = Geom::Transformation.scaling(pt,3)t4 = Geom::Transformation.scaling(pt,2,3,4)


          縮放變換有四種創(chuàng)建方式,其中: t1 表示以原點為縮放中心放大3倍的變換; t2 表示以原點為縮放中心,在x軸、y軸、z軸上分別放大2、3、4倍的變換; t3 表示以 (100, 100, -100) 為縮放中心放大3倍的變換; t2 表示以 (100, 100, -100) 為縮放中心,在x軸、y軸、z軸上分別放大2、3、4倍。


          同樣地,保持參數(shù)類型不變,將 .scaling 換成 .new 也同樣可以創(chuàng)建旋轉(zhuǎn)變換對象,也不推薦這樣使用。


          ⑤坐標(biāo)軸變換


          有時需要這樣一種變換,將諸如 (x, z, -y) 這樣的坐標(biāo)轉(zhuǎn)換成 (x, y, z) 坐標(biāo),這時就需要使用到坐標(biāo)軸變換。

          t1 = Geom::Transformation.axes([0,0,0],[1,0,0],[0,0,1],[0,-1,0])t2 = Geom::Transformation.axes(ORIGIN, X_AXIS, Z_AXIS, Y_AXIS.reverse)


          其中, t2 是官方文檔中的例子,使用到了 ORIGIN、 X_AXIS、 Y_AXIS 和 Z_AXIS 這些常量來表示特定的空間概念:


          (2)應(yīng)用變換


          ①原點與坐標(biāo)軸的變換


          一個 Geom:: Transformation 類實例預(yù)設(shè)有一些能夠返回變換基本特征的方法,其中包括原點和坐標(biāo)軸方向在這個變換后的空間位置。此處使用平移變換和坐標(biāo)軸變換作為例子:

          tr1 = Geom::Transformation.translation([0,1,2])tr2 = Geom::Transformation.axes([0,0,0],[1,0,0],[0,0,1],[0,-1,0])
          tr1.origin#>> Geom::Point3d(0, 1, 2)tr1.xaxis#>> Geom::Vector3d(1, 0, 0)tr1.yaxis#>> Geom::Vector3d(0, 1, 0)tr1.zaxis#>> Geom::Vector3d(0, 0, 1)
          tr2.origin#>> Geom::Point3d(0, 0, 0)tr2.xaxis#>> Geom::Vector3d(1, 0, 0)tr2.yaxis#>> Geom::Vector3d(0, 0, 1)tr2.zaxis#>> Geom::Vector3d(0, -1, 0)


          ②點與向量的變換


          Geom:: Point3d 和 Geom:: Vector3d 類實例都有 .transform 和 .transform! 兩個方法,用于應(yīng)用具體的變換。很顯然,兩者區(qū)別在于前者只返回新的、變換后的實例;而以感嘆號結(jié)尾的后者同時修改此實例的值。

          pt = Geom::Point3d.new(2,-4,9)pt.transform!(tr1)puts pt#>> Geom::Point3d(2, -3, 11)
          vr = Geom::Vector3d.new(193,61,205)vr.transform!(tr2)puts vr#>> Geom::Vector3d(193, -205, 61)


          ③圖元的變換


          變換類最直觀的作用就是用于移動當(dāng)前模型中的圖元,而移動圖元需要使用的是 Sketchup:: Entities 類的 .transform_entities 方法,這個方法可以一次性變換一系列圖元。

          ents = Sketchup.active_model.entitiestrans = Geom::Transformation.rotation([0,0,0],[0,0,1],30.degrees)#令當(dāng)前模型至少有兩個群組ents.transform_entities(trans, ents.to_a)groups = ents.grep(Sketchup::Group)ents.transform_entities(trans, groups)ents.transform_entities(trans, groups[0], groups[1])


          以上例子中,第4行表示將整個模型中的所有圖元進(jìn)行繞z軸正半軸30°的旋轉(zhuǎn),第5行則表示只旋轉(zhuǎn)模型中所有群組,而第6行表示只旋轉(zhuǎn)模型中第一個和第二個群組。 .transform_entities 的第一個參數(shù)必須是 Geom:: Transformation 類實例,而之后可以有多個參數(shù),每個參數(shù)都可以是圖元類或者是圖元類的數(shù)組。可以理解成如下的定義:

          module Sketchup  class Entities    def transform_entities(trans,*arg)      entities_list = arg.flatten      #對entities_list進(jìn)行trans變換    end  endend


          (3)變換組合


          ①矩陣乘法


          當(dāng)圖元進(jìn)行依次多個變換時,可以使用如下的變換方式:

          t1 = Geom::Transformation.scaling(2,3,4)t2 = Geom::Transformation.rotation([0,0,0],[0,0,1],45.degrees)ents = Sketchup.active_model.entitiesent = ents[0]
          ents.transform_entities(t1,ent)ents.transform_entities(t2,ent)


          如果變換的數(shù)量繼續(xù)增加,不僅代碼量會提高,每執(zhí)行一次 .transform_entities 方法后就需要進(jìn)行一次的模型更新也會大大影響代碼執(zhí)行效率。好在多個變換對象依次組合可以得到一個新的組合變換,而只需要通過 .*() 方法就可以實現(xiàn)。以上例子可以直接寫成這樣:

          ents.transform_entities(t1*t2,ent)


          ②逆矩陣


          如果依次應(yīng)用兩個變換對象后,圖元最終回到了沒有變換之前的狀態(tài),就說這兩個變換對象是互為對方的逆變換,通過 .inverse 和 .invert! 方法實現(xiàn)。可以從方法名稱得出,前者只是返回一個變換對象的逆變換,而后者是在返回的基礎(chǔ)上同時將此對象改為這個逆變換。

          t3 = Geom::Transformation.translation([20,10,-30])puts t3.origin#>> Geom::Point(20, 10, -30)t3.invert!puts t3.origin#>> Geom::Point(-20, -10, 30)


          根據(jù)逆變換的定義可以得知以下代碼返回結(jié)果一定為 true

          # tn 為任意一個 Geom::Transformation 實例(tn*tn.inverse).identity?#>> true


          ③矩陣插值


          Geom:: Transformation類中包含了五個類方法: .axes、 .translation.rotation、 .scaling 和 .interpolate,另外還有 .new 這樣的構(gòu)造方法。它們都是直接在類名之后使用,而不需要在類的實例之后使用。這意味著這些方法與具體的類實例沒有關(guān)系,其執(zhí)行內(nèi)容是普遍的,而非針對具體某一個實例。Transformation 類的這幾個類方法都可以理解成特定限定的 .new 方法,用以創(chuàng)建特定的變換類實例。


          其他方法在前文都已經(jīng)進(jìn)行了介紹,都是返回特定意義的特殊變換對象。而 .interpolate 方法與這些方法有一點顯著差異,它根據(jù)兩個變換對象返回它們的線性插值結(jié)果。


          例如以下的例子:

          ents=Sketchup.active_model.entitiest=Geom::Transformation.newt1=Geom::Transformation.rotation([0,0,0],[0,0,1],180.degrees)t2=Geom::Transformation.translation([0,0,100])ttmp=Geom::Transformation.interpolate(t,t1*t2,1.0/18)acc=0timer=UI.start_timer(0.1,true){  ents.transform_entities(ttmp, ents.to_a)  if acc>=18 then UI.stop_timer(timer) end  acc+=1}


          其中, t1 為一個繞z軸旋轉(zhuǎn)變換, t2 為沿z軸平移上升變換, t1*t2 表示這兩個變換的組合。 .interpolate 方法在單位矩陣 t 和 t1*t2 之間尋找兩個變換的中間狀態(tài)。例如,第三個參數(shù)為 1.0/18,這就意味著方法返回了一個變換對象給 ttmp,使得連續(xù)變換18次 ttmp 就可以達(dá)到 t1*t2 的效果。如果參數(shù)是 1.0/4,那就是連續(xù)變換4次。


          第6-11行是一個“超綱”的內(nèi)容,大意為:每個0.1秒給整個模型應(yīng)用一個 ttmp 變換,循環(huán)18次。最終的效果如下:



          (4)變換矩陣詳解


          ①變換對象的矩陣表示


          變換對象所代表的空間變換可以用矩陣來表示,使用 .to_a 方法就可以得到這個矩陣。

          t = Geom::Transformation.scaling(2,3,4)t.to_a#>> [2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 4, 0, 0, 0, 0, 1]

          相反,使用 .set! 方法可以通過這樣形式的數(shù)組修改一個變換對象,或者直接使用 .new 方法。

          mat=[2,0,0,0,0,3,0,0,0,0,4,0,0,0,0,1]t1 = Geom::Transformation.new(mat)
          t2 = Geom::Transformation.newt2.set!(mat)


          只不過這里的“矩陣”是一個一維數(shù)組,并不符合對矩陣的直觀感受。如果需要顯示成矩陣的行列形式就需要額外的進(jìn)行一些過程。


          首先這個數(shù)組有16個元素,所以是一個4×4的矩陣,是三維空間的齊次坐標(biāo)變換矩陣,一般情況下二維數(shù)組都是默認(rèn)行排列,所以對于一個數(shù)組 t,其矩陣表示應(yīng)該是這樣的:

          或者用數(shù)組的子界數(shù)組表示:

          不過需要提前說明的是,這里使用行排列產(chǎn)生的矩陣結(jié)果適用于行向量的變換,而不是線性代數(shù)中更常使用的列向量。所以如果按照列向量變換的規(guī)則,變換矩陣應(yīng)該寫成以下形式:

          若無特殊說明,本篇以下內(nèi)容中出現(xiàn)的坐標(biāo)均為行向量形式。


          了解了這個規(guī)則以后,就可以自行在 Geom:: Transformation 類中追加顯示矩陣的方法了:

          module Geom  class Transformation    def mat      self.to_a.each_slice(4).to_a.unshift("").inject{|out,arr|        "#{out}\r\n"+arr.unshift("").inject{|res,ele|"#{res}\t"+ele.round(3).to_s}      }+"\r\n"    end    def matt      self.to_a.each_slice(4).to_a.transpose.unshift("").inject{|out,arr|        "#{out}\r\n"+arr.unshift("").inject{|res,ele|"#{res}\t"+ele.round(3).to_s}      }+"\r\n"    end  endend


          其中定義了兩個方法, mat 方法返回行向量變換的矩陣形式,而 matt 方法返回列向量變換的矩陣形式;之后的例子中都使用前者。


          簡單介紹一下實現(xiàn)方法: .each_slice(n) 方法可以將數(shù)組每n個一組作為新的數(shù)組返回給迭代器作為迭代變量。迭代器在之前的教程中有過一定的舉例,這里使用了迭代器對象的 .to_a 方法將所有迭代值組成一個新的數(shù)組,以達(dá)到一維數(shù)組向二維數(shù)組的轉(zhuǎn)換。在 matt 方法定義中的 .transpose 方法就是在這個二維數(shù)組的基礎(chǔ)上進(jìn)行的行列互換。至于 .round(n) 方法是可選項,可以將矩陣每個元素進(jìn)行小數(shù)部分的長度限制。


          關(guān)于其中的 .inject(res, item, &block) 方法,需要單獨解釋一下,這是一個帶累計變量的迭代器。迭代器的兩個參數(shù) res 和 item 分別表示返回值和迭代變量,從數(shù)組的第1個元素開始迭代, res 的初始值為數(shù)組的第0個元素。常用于計算整個數(shù)組的特征值:

          puts [1,2,3,4].inject{|res,item|res+=item}#>> 10  (返回各元素算數(shù)加和)puts [1,2,3,4].inject{|res,item|res=item if res<item}#>> 4   (返回數(shù)組中的最大值)
          #第二個例子如果用each來實現(xiàn)會變成這樣:res=-Float::INFINITY    #先給res一個最小值,使之小于數(shù)組中的任何一個元素[1,2,3,4].each{|item|res=item if res<item}puts res#此時res依然可以訪問;#如果是inject,res作用域僅在塊中。


          ②齊次坐標(biāo)變換矩陣


          Sketchup中的三維空間坐標(biāo)變換為仿射變換,即一個線性變換加上一個平移變換。而三階矩陣只能表示三維空間的線性變換,不能表示平移,因此就需要使用齊次坐標(biāo)變換來表示。


          (3階線性變換矩陣)

          (3+1階齊次坐標(biāo)變換矩陣)


          齊次方程通過引入啞元 ω 來表示原點的平移情況:當(dāng)?shù)谒脑?ω≠0 時坐標(biāo)表示三維空間內(nèi)一點;當(dāng)?shù)谒脑?ω=0 時坐標(biāo)表示三維空間內(nèi)一個向量。向量的坐標(biāo)與前三元一致;當(dāng) ω=1 時,點坐標(biāo)與前三元一致。齊次坐標(biāo)所有元同時乘一個非零常數(shù)k后,表示的依然是同一個點。因此如果點的齊次坐標(biāo) ω≠1 時,可以通過四元同時除以ω得到標(biāo)準(zhǔn)化的齊次坐標(biāo):

          (齊次坐標(biāo)與笛卡爾坐標(biāo)的轉(zhuǎn)換)


          因此,對于變換矩陣 [a, b, c, d, e, f, g, h, j, k, l, m, n, p, q, r] 來說,點 (x, y, z) 變換后的坐標(biāo)可以用以下方程表示:


          我們可以把這個矩陣拆成四個部分:

          表示仿射變換中的線性變換,也就是以原點為中心的縮放、旋轉(zhuǎn)、錯切等變換。 表示仿射變換中平移的方向和距離。 p 與投影變換有關(guān),其值的改變與 SketchUp 中的變換似乎并無關(guān)系[注]。r 則為整體的比例系數(shù),相當(dāng)于點的齊次坐標(biāo)中的啞元ω。


          具體來看一下幾個基本變換的矩陣形式


          (i)單位矩陣

          t1=Geom::Transformation.newt1.mat#>>  1.0   0.0   0.0   0.0#>>  0.0   1.0   0.0   0.0#>>  0.0   0.0   1.0   0.0#>>  0.0   0.0   0.0   1.0

          單位矩陣對角線全為1,其余全為0:

          (ii)平移矩陣

          t2=Geom::Transformation.translation([100,200,-300])t2.mat#>>  1.0    0.0     0.0     0.0#>>  0.0    1.0     0.0     0.0#>>  0.0    0.0     1.0     0.0#>>  100.0  200.0  -300.0   1.0

          平移矩陣在單位矩陣基礎(chǔ)上令 v 為平移向量坐標(biāo):

          (iii)旋轉(zhuǎn)矩陣

          t3=Geom::Transformation.rotation([100,100,0],[0,0,1],90.degrees)t3.mat#>>  0.0    1.0   0.0   0.0#>> -1.0    0.0   0.0   0.0#>>  0.0    0.0   1.0   0.0#>>  200.0  0.0   0.0   1.0

          旋轉(zhuǎn)矩陣中, T 為三維旋轉(zhuǎn)的線性變換矩陣, v 為旋轉(zhuǎn)后的原點坐標(biāo)(以下為繞z軸方向旋轉(zhuǎn)的例子):

          (iv)縮放矩陣

          t4=Geom::Transformation.scaling([100,-100,0],2,2,2)t4.mat#>>   2.0    0.0    0.0   0.0#>>   0.0    2.0    0.0   0.0#>>   0.0    0.0    2.0   0.0#>>  -100.0  100.0  0.0   1.0

          縮放矩陣在對角線以外均為0。對于等比例縮放S倍的矩陣 M,有 diag(M) (1, 1, 1, S);對于不等比例的縮放矩陣 N,則有 diag(N) (Sx, Sy, Sz, 1。當(dāng)然,如果不是以原點為縮放中心, v 則是原點縮放后的坐標(biāo)。

          (v)組合變換

          tt = t1*t4tt.mat#>>   2.0    0.0    0.0    0.0#>>   0.0    2.0    0.0    0.0#>>   0.0    0.0    2.0    0.0#>>  -100.0  100.0  0.0    1.0

          多個變換的依次組合在 Geom:: Transformation 類中使用的是 .*() 方法,對應(yīng)矩陣的乘法,以下用二階舉個例子:

          SketchUp提供的變換都是不改變圖形形狀的變換,其組合也都保持這一特點,但是可以自己通過齊次坐標(biāo)變換矩陣的定義實現(xiàn)一些特殊的改變圖元形狀的變換,例如:錯切變換和投影變換。


          (vi)錯切變換

          mat_1 = [1,1,0,0,         0,1,1,0,         1,0,1,0,         0,0,0,2]t5=Geom::Transformation.new(mat_1)#令當(dāng)前模型有且只有一個正方體群組ents = Sketchup.active_model.entitiesents.transform_entities(t5,ents[0])

          在三個軸方向上都進(jìn)行了等比例的錯切后:

          (錯切變換)


          (vii)投影變換

          mat_2 = [1,0,0,0,         0,1,0,0,         0,0,0,0,         0,0,0,1]t6=Geom::Transformation.new(mat_2)t7=Geom::Transformation.rotation([0,0,0],[0,1,0],45.degrees)t8=t7*t6*t7.inverse#令當(dāng)前模型有且只有一個正方體群組ents = Sketchup.active_model.entitiesents.transform_entities(t8,ents[0])

          使用“旋轉(zhuǎn)-投影-恢復(fù)旋轉(zhuǎn)”的方式組合一個新的變換,并將正方體投影在平面 x+z=0 上:

          (投影變換)


          不過需要額外說明:投影變換只是作為自定義變換的例子存在,并不是那么有應(yīng)用意義,它會導(dǎo)致大量重合圖元,應(yīng)當(dāng)采用更好的方法來生成新的圖元。而根據(jù)特定條件生成特定圖元則需要在之后的教程中涉及。


          以上就是本篇教程的全部內(nèi)容,篇末為文中一處的注釋內(nèi)容和補充內(nèi)容。




          :關(guān)于 Geom:: Transformation 類對象對應(yīng)的的矩陣,相關(guān)資料描述較少。再加上本人也是第一次接觸齊次坐標(biāo)系,找不到很好的切入點深究這個問題。初步的測試結(jié)果是向量 p 的值變化不會對一個具體變換產(chǎn)生影響,因此只能暫時粗略地得出“似乎并無關(guān)系”。


          另外,矩陣插值中介紹的 .interpolate 方法作為類方法,進(jìn)行兩個矩陣的線性插值。而在向量的計算中也有一個類似的方法,即 .linear_combination 方法,它也根據(jù)兩個空間概念和一個0~1的位置數(shù)值進(jìn)行線性插值。不過在向量的教程中并沒有專門提及,因為這個方法可以很輕松的實現(xiàn)。




          本文編號:SU-R08



          瀏覽 130
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  无码人妻精品一区二区蜜桃91 | 人人色人人摸人人干 | 久久一次 | 丁香五月婷婷中文字幕 | 国产宴妇精品久久久久久 |