從這一篇開始,教程進入第三個部分,開始對SU Ruby API中的各個模塊和類的方法和相關概念進行詳細的介紹。首先不可避免的要談及SU模型表示三維空間的方法。包括空間坐標、空間範圍、空間變換以及更廣域意義上的地理坐標表示等內容:這就需要使用到Geom模塊。
Geom模塊是幾何與變換的核心模塊,教程將分為四個部分介紹。以下是第一篇,有關如何表示一個點、一條直線或者一個平面。
幾何與變換(1):向量與點線面
【本期目錄】(1)長度與角度單位
①長度單位
②角度單位
③自定義單位轉換
④模型單位格式
(4)直線
①點向式表示法
②與Sketchup::Edge的關係
(2)點
①用數組表示點
②Geom::Point
③與Sketchup::Vertex的區別
(5)平面
①點法式表示法
②原點距式表示法
③與Sketchup::Face的關係
(3)向量
①用數組表示向量
②Geom::Vector
③向量計算
(6)立體幾何
①交錯與投影
②位置關係
③距離計算
(1)長度與角度單位
①長度單位
Sketchup的默認長度尺寸為英寸,因此在使用數字坐標的時候,(1000,0,0)並不代表距離原點1000毫米的點,而是距離原點1000英寸的點。這時如果需要使用1000毫米的尺寸,就需要使用 1000.mm。
如上圖可以發現 1000.mm 返回的並不是一個數字類(::Numeric),而是::Length類。這個類繼承自::Numeric類,所有數值都繼承自這個ruby自帶的類,SU在其中追加了一些方法使之可以直接進行單位轉換。而轉換之後使用 .inspect 方法查看這個數值的存儲值可以發現依然是以英寸作為單位的。
相似地,還可以將英寸轉換為釐米(cm)、米(m)、千米(km)、英尺(feet)、英碼(yard)和英裡(mile),當然也可以是轉換成英寸本身。下圖是這些轉換方式的測試,由於當前模型的單位為毫米,所以顯示時為毫米單位:
1.feet1.yard1.inch1.mile1.km1.cm1.m隨便打一個數字,查看數字以「to_」開頭的方法,可以看到ruby風格的轉換方法,其中除了 to_s、 to_f、 to_i、 to_c 這些ruby自帶的數據類型轉換以外,還有SU提供的單位轉換。
這些是與上文相對應的逆過程方法,將以英寸計的尺寸轉換成指定單位下的數值。例如:
1.m.to_mm1.mile.to_yard1.feet.to_inch1.km.to_m1.yard.to_feet1.mile.to_m1.inch.to_mm②角度單位
SketchUp的角度單位默認是弧度制,因此如果需要使用角度制,需在角度數值之後添加 .degrees 。這裡需要與前文長度單位區別一下,不同於 .mm 返回的是Length類, .degrees 方法返回的並不是一個特定的Angle類實例,而是浮點數類型(::Float)。這意味著這個返回值與原數值一樣,都是不帶單位的數字。因此這個方法是純粹的數值轉化,可以直接理解成是如下的定義:
class Numeric def degrees return(self / 180 * Math::PI) end def radians return(self / Math::PI * 180) endend
同理,還有一個 .radians 方法,用於將弧度制轉換為角度制,同樣返回的是Float類型。因此,角度制弧度制的轉換不是像英寸和毫米的轉換那樣有主次關係,表現為一對 .mm 和 .to_mm ,而是 .degrees 和 .radians 對稱的轉換方法。
③自定義單位轉換
在理解了角度單位轉換的方式之後,也可以使用相同的手法追加其他自定義方法到Numeric類以實現其他單位轉換。由於Length繼承自Numeric類,因此在往Numeric中追加新方法的同時,Length類也會同步更新這些方法。以下以英制單位「弗隆」和市制單位「寸」「尺」「丈」「引」「裡」為例子:
class Numeric def furlong return (self*220*3*12).to_l end def to_furlong return (self/220/3/12) end def cun return (self*100/3).mm end def to_cun return (self.to_mm*3/100) end def chi return (self*10).cun end def to_chi return (self.to_cun/10) end def zhang return (self*100).cun end def to_zhang return (self.to_cun/100) end def yin return (self*1000).cun end def to_yin return (self.to_cun/1000) end def li return (self*15000).cun end def to_li return (self.to_cun/15000) endend其中furlong的轉換方法中出現了 .to_l 方法,這是將Numeric類轉換成英寸單位的Length類的方法;而市制單位的換算中都是用 .mm 方法繞開了這一步驟。下圖為效果測試:
1.li.to_m1.zhang.to_cm1.cun.to_inch1.chi.to_feet1.zhang.to_yard1.yin.to_furlong1.li.to_mile1.m.to_cun1.mile.to_furlong④模型單位格式
在Sketchup模塊下定義有這樣一系列的方法,它們通過給定的英寸單位的數據返回當前模型的單位數值。包括 .format_length、 .format_area、 .format_angle、 .format_degrees 和 .format_volume 。如下圖,如果是2019.2以前的版本,是沒有 .format_volume 這個方法的。
在當前模型以毫米為單位時,就會是以下的結果:
puts Sketchup.format_degrees(Math::PI.radians)puts Sketchup.format_angle(Math::PI)puts Sketchup.format_length(100.m)puts Sketchup.format_length(1.mile)puts Sketchup.format_area(1)puts Sketchup.format_area(3.mm*9.mm)puts Sketchup.format_volume(3.mm*4.mm*5.mm)對於2019以前的版本,也可以通過追加的方法在Sketchup模塊中自己添加 .format_volume 方法,不過需要涉及到判斷當前模型的單位設置,這會在之後有關Sketchup:: OptionsManager的章節中涉及。
(2)點
①用數組表示空間點
Sketchup 中可以使用數組來表示空間坐標,例如坐標 (0,100,100) 在ruby中表示為 [0,100,100]。其中三個維度的順序是 [x,y,z],或說 [width, height, depth],同時也接受xy平面上的二維坐標 [x,y],或者說 [width, height]。
了解了這種最簡易的表示空間點坐標的方式,就已經可以利用Entities類中的添加圖元方法,向圖元容器中繪製新圖形了:
②用Geom::Point表示空間點
數組只是方便使用者快速地表示空間坐標,而模型中的圖元的存檔則有專門的定義,二維和三維的空間坐標有分別的類定義,即Geom:: Point2d 和 Geom:: Point3d。
這裡以Geom:: Point3d為例,同樣繪製上一部分中的那條線段,同時額外展示一些創建Point3d實例的方法:
point_O = Geom::Point3d.new(0,0,0)point_P = Geom::Point3d.new([100.mm,100.mm,0])point_P1 = Geom::Point3d.new(point_P)point_P2 = point_P.clone
Sketchup.active_model.entities.add_line(point_O,point_P)
puts point_O==point_P puts point_P==point_P1 puts point_P==point_P2其中第一行和第二行是比較常見的創建點的方式,一種是使用三個參數表示xyz,另一種則是使用數組表示三維坐標。第三行是通過已有點的坐標創建新的點,其實它與第二行的表達只有一步之遙,可以寫成這樣: point_P1 = Geom:: Point3d. new( point_P. to_a) 。第四行則完全不需要使用類名,直接使用已有點創建副本,是比較方便的做法。8-10行對這些點進行比較,P1和P2是通過P創建的,因此相等;O與P則不相等。
如果需要訪問Point類實例的坐標,有兩種方式可以選擇:
p = Geom::Point3d.new(4.mm,8.mm,12.mm)puts p.x puts p.y puts p.z puts p[0] puts p[1] puts p[2]如果需要修改Point類實例的坐標,有三種方式可以選擇:
p = Geom::Point3d.new(4.mm,8.mm,12.mm)p.x=1.mmp.y=2.mmp.z=4.mmputs p p[0]=0.mmp[1]=1.mmp[2]=2.mmputs p p.set!([3.mm,6.mm,12.mm])p.set!(3.mm,6.mm,12.mm)puts p訪問與修改共五種方法,其中除了 .set! 以外,其餘四種方法對於用數組形式的坐標也有效, .[] 和 .[]= 還是Array類固有的方法。
Geom:: Point2d 和 Geom:: Point3d 是專門的點類型,使用這種方式表示空間點坐標不如數組表示來得方便,但是具有兩個優勢:一是數組不僅可以用來表示空間坐標,還可以用來表示向量,混合使用數組可能會造成混淆,影響代碼的可讀性;二是這兩個類的實例有數組類沒有的方法,這些方法在點與向量的計算中能夠提供方便。
③與Sketchup::Vertex的關係
Vertex是Sketchup模塊下定義的端點類,是圖元的一種,是直接與Geom:: Point類對標的圖元類。Point類側重於空間計算,而Vertex類是具體模型中的數據類型,包括了模型中端點與其它圖元的關係,例如該端點參與了哪些邊線、面的組成。Vertex作為表示端點的圖元,包含空間點坐標的信息,所以每一個實例中包含一個Point類實例,通過Vertex類的 .position 方法可以訪問:
edge=Sketchup.active_model.entities[0]vertex=edge.vertice[1]puts vertex.position其中, edge. vertice 返回邊線的兩個端點, edge. vertice[1] 表示的是其中的終點。這部分內容會在涉及Sketchup:: Edge類的章節中詳解。
(3)向量
①使用數組表示向量
向量的表達方式與點坐標的表達方式如出一轍,同樣是 [x,y,z] 或者 [x,y] 的順序。在SU Ruby中,向量經常用於表示平面的方向。例如繪製一個圓時, .add_circle 中的第二個參數就是向量,表示繪製圓所在平面的法向量。
Sketchup::Entities.add_circle( centre, normal, radius [,segnum=24] ) => Array of Sketchup::Edge以下為了便於展示,在畫圓的基礎上創建了相應的面域:
②使用Geom::Vector表示向量
向量類Geom::Vector類與Geom::Point類一樣,分為2d和3d兩種,即 Geom:: Vector2d 和 Geom:: Vector3d ,前者用來表示xy平面上的向量。
center = Geom::Point3d.new(0,0,0)normal = Geom::Vector3d.new([1,1,1])normal_1 = Geom::Vector3d.new(normal)normal_2 = normal.cloneradius = 100.mm
es=Sketchup.active_model.entities.add_circle(center,normal,radius)Sketchup.active_model.entities.add_face esVector類與Point類有著相似的聲明方式,同樣支持多種創建實例的方式。向量的坐標訪問與修改也與點坐標一致,同樣包括 .[]、 .[]=、 .x、 .x= 和 .set! 五種。與Point類不同的是,向量有一些特殊的概念:
向量是有方向的,因此Vector類提供反向變換方法:
vector = Geom::Vector3d.new([1,1,1])puts vector.reverse puts vector vector.reverse! puts vector向量是有長度的,因此Vector類實例能對長度進行訪問和修改。還可以判斷向量是否為單位向量以及對向量進行標準化。
vector = Geom::Vector3d.new([1,1,1])puts vector.length vector.length=500.mm puts vector puts vector.unitvector? vector.normalize! puts vector.length.to_inch vector.unitvector? puts vector③向量計算
向量與點存在一系列的運算和轉換方法,Vector類提供了 .+、 .-、 .==、 .cross 和 .dot 等方法,分別用於表示向量加法、減法、比較、叉乘和點乘;其中前三個方法通過運算符重載使得向量計算和解析幾何上的表示非常相似。
以下通過在三角形OPQ中的PQ上作中點M的例子,展示向量與點之間的加減運算方法:
point_O = Geom::Point3d.new(0,0,0)point_P = Geom::Point3d.new(3,0,0)point_Q = Geom::Point3d.new(0,4,0)vector_OP = point_P - point_Ovector_OQ = point_Q - point_O vector_PQ = vector_OQ - vector_OPvector_PM = vector_PQ.clonevector_PM.length= 0.5 * vector_PQ.length point_M1 = point_P + vector_PM point_M2 = point_P.offset(vector_PM) vector_OM = vector_OP + vector_PM point_M3 = Geom::Point3d.new(vector_OM.to_a)puts point_M.to_a puts point_M1 == point_M2 puts point_M1 == point_M3 puts point_M1 == point_P在前一個例子的基礎上,展示向量間關係的判斷:
puts vector_OP == vector_OQ puts vector_PM == vector_PQ puts vector_PM == vector_PM.clone puts vector_OP.perpendicular?(vector_OQ) puts vector_OP.perpendicular?(vector_PQ) puts vector_PM.parallel?(vector_PQ) puts vector_PM.parallel?(vector_PQ.reverse) puts vector_PM.samedirection?(vector_PQ) puts vector_PM.samedirection?(vector_PQ.reverse) puts vector_OP.angle_between(vector_OQ).radians puts vector_OP.angle_between(vector_PQ).radians puts vector_OP.angle_between(vector_PQ.reverse).radians除此之外,向量計算還有叉乘和點乘,分別常用於構造正交和投影:
vector_OA=Geom::Vector3d.new(3,1,-4)vector_OB=Geom::Vector3d.new(-2,4,1)vector_OC=vector_OA.cross(vector_OB)puts vector_OCputs vector_OC.perpendicular?(vector_OA)puts vector_OC.perpendicular?(vector_OB)
vector_OA = Geom::Vector3d.new(1,6,3)vector_OB = Geom::Vector3d.new(-2,4,6)dot_OA_OB = vector_OA.dot(vector_OB)vector_OM = vector_OA.clonevector_OM.length = dot_OA_OB / vector_OA.lengthvector_MB = vector_OB - vector_OMputs vector_MB.perpendicular?(vector_OA)以上代碼中的坐標如下圖所示:
使用叉乘構造所在平面法線
使用點乘獲得向量的投影(4)直線
①表示直線的數組
SketchUp中的直線使用點向式表示,即直線上一點加方向向量的形式。具體在ruby中是一個有兩個元素的數組。第0個元素為直線上任意一點,第1個元素為直線的方向向量。
例如以下兩段代碼均定義了直線line: x=y=z-1:
point_1 = Geom::Point3d.new(0,0,1)vector_1 = Geom::Vector3d.new(1,1,1)line_1 = [point_1,vector_1]
point_2 = Geom::Point3d.new(-1,-1,0)vector_2 = Geom::Vector3d.new(-2,-2,-2)line_2 = [point_2,vector_2]這種直線的表達存在一個問題,就是同一個直線有無數中表達方式,因此在判斷兩個表達是否是同一個直線時就會比較麻煩,需要比較兩個直線方程的方向向量是否相同,然後再判斷他們是否存在至少一個共同點。由於直線沒有專門的類定義,沒有專門的判斷是否相等的方法,也就不能通過運算符重載來實現相等的判斷,所以需要在Geom模塊中追加一個函數判斷:
module Geom def Geom.line_line_equal?(la,lb) la[1].parallel?(lb[1]) and la[0].on_line?(lb) endend②與Sketchup::Edge的關係
直線在空間中是無限延伸的,而Sketchup::Edge是邊線圖元,是有限的線段。儘管如此,Edge類圖元可以通過 .line 方法返回其所在的直線。使用 .line 方法得到的直線,其點坐標為邊線的起始點(第一個端點),而方向向量是與兩個端點坐標之差同向的單位向量。因此可以理解成如下的方法定義:
module Sketchup class Edge def line res = [self.start.position] vec = self.end.position - self.start.position res << vec.normalize end end end其中, edge. start 返回邊線的起點,相當於 edge. vertice[0]; edge. end 返回邊線的終點,相當於 edge. vertice[1] 。這部分內容會在涉及Sketchup:: Edge類的章節中詳解。
(5)平面
①表示平面的數組
SketchUp中的平面有兩種表示方法,一種是「點法式」,另一個是「原點距式」。
點法式。與直線的表示形式完全相同,表現為由1個點坐標和1個向量組成的數組。第0元素為平面上任意一點,第1元素為平面法向量。所以有著相同形式的直線與平面一定相互垂直,並且相交於第0元素表示的點。
原點距式。和直線的點向式一樣,平面的點法式也存在同一個平面有多個表達方式這情況,這對於比較平面是否相等十分不方便。不過平面的情況比直線好一些,不同於直線要五個參數才能確定唯一性,平面只需要四個參數;並且這四個參數都有幾何意義。也就是說,在法向量確定的情況下,原點和交點在法向量方向上的位置對於每一個不同的平面是唯一的。所以如下圖,可以用四個數表示三維空間中的所有平面,記為 [x, y, z, d],前三位 x, y, z 為平面的單位法向量PQ, d 則表示交點到原點沿PQ方向的有向距離。
所以平面plane: x+y+z-1=0的「原點距式」就是:
plane = [0.5773502691896258, 0.5773502691896258, 0.5773502691896258, -0.5773502691896258]對於平面 plane 來說, plane[0..2] 表示該平面的法向量, plane[3] 表示該平面的「原點距」。將數組的四個元素分別取相反數,即 plane. map{|i| -i} 或 plane. map(&:-@),也是相同的平面,只不過法向量相反。
Geom模塊中提供了一個名為 .fit_plane_to_points 的方法,能夠通過已知點坐標列表最大程度地創建擬合平面,可以通過這個方法,用三個點坐標創建平面。其返回結果也是「原點距式」。
points=[]points<<[0,0,0]points<<[0,1,0]points<<[1,0,0]points<<[1,1,0]Geom.fit_plane_to_points(points)
points=[]points<<[1,0,0]points<<[0,1,0]points<<[0,0,1]Geom.fit_plane_to_points(points)②與Sketchup::Face的關係
平面和直線一樣,在空間中無限延伸,與之相關的Sketchup:: Face則是有具體形狀的面域。Face類圖元可以通過 .plane 方法返回其所在的平面,返回格式為「原點距式」。
法向量相反的兩個表達方式對於平面來說是相同的,但對於 Face 圖元 .plane 方法的返回結果而言,卻有一點區別。如下圖代碼所展示,這一點區別能夠反映該平面圖元的材質正面是朝向原點還是背向原點,相關內容在涉及 Sketchup:: Face 的章節中詳解。
face=Sketchup.active_model.entities.grep(Sketchup::Face)[0]puts "#{face.plane.map{|i|i.round(3)}}"face.reverse!puts "#{face.plane.map{|i|i.round(3)}}"(6)立體幾何
現在已經完整地介紹了點線面在SU Ruby中的表達方式,其中連帶地也涉及了一些有關同類圖形之間的立體幾何計算。在最後這一部分會補充不同圖形之間關係判斷和有關的計算方法。
本部分中灰色字體部分不是 SU Ruby API 目前提供的方法,系額外追加的方法,這部分段落之後代碼為個人實現方案,可選擇性閱讀。
①交錯與投影
Geom模塊中提供了三個交錯方法 : .intersect_line_line、.intersect_line_plane 和 .intersect_plane_plane 。分別用於返回線線交點、線面交點和面面交線。三個方法均只返回唯一的結果,如果是兩線重合、兩線異面、線在面上、線面平行或者面面重合的情況,則返回nil。
Geom:: Point類實例提供 .project_to_line 和 .project_to_plane 兩個方法,用於將點投影到線或面上。
point_1 = Geom::Point3d.new(0,0,0)point_2 = Geom::Point3d.new(500.mm,300.mm,1000.mm)line_1 = [point_1,Geom::Vector3d.new(0,0,1)]line_2 = [point_1,Geom::Vector3d.new(0,1,1)]plane_1 = [point_2,Geom::Vector3d.new(0,0,1)]plane_2 = [point_1,Geom::Vector3d.new(1,1,1)]
intersect_point_1 = Geom.intersect_line_line(line_1,line_2)intersect_point_2 = Geom.intersect_line_plane(line_1,plane_2)intersect_line = Geom.intersect_plane_plane(plane_1,plane_2)
proj_pt1=point_2.project_to_line(line_1)proj_pt2=point_2.project_to_line(line_2)②位置關係
Geom:: Point類中提供了兩個方法用於判斷點是否在直線或者平面上,分別是: .on_line? 和 .on_plane? 。
point_1 = Geom::Point3d.new(0,0,0)point_2 = Geom::Point3d.new(0,0,1000.mm)line_1 = [point_1,Geom::Vector3d.new(0,0,1)]line_2 = [point_1,Geom::Vector3d.new(0,1,1)]plane_1 = [point_2,Geom::Vector3d.new(0,0,1)]plane_2 = [point_1,Geom::Vector3d.new(0,0,1)]puts point_1.on_line?(line_1)puts point_2.on_line?(line_2)puts point_1.on_plane?(plane_1)puts point_1.on_plane?(plane_2)至於線線關係、線面關係和面面關係則可以在向量關係的基礎上進行補充。例如,判斷線與線、線與面和面與面之間是否垂直或平行,可以如此實現:
module Geom def Geom.line_line_perpendicular?(la,lb) return la[1].perpendicular?(lb[1]) end def Geom.line_line_parallel?(la,lb) return la[1].parallel?(lb[1]) end def Geom.line_plane_perpendicular?(l,p) case p.count when 2 then return l[1].parallel?(p[1]) when 4 then return l[1].parallel?(p[0..2]) end end def Geom.line_plane_parallel?(l,p) case p.count when 2 then return l[1].perpendicular?(p[1]) when 4 then return l[1].perpendicular?(p[0..2]) end end def Geom.plane_plane_perpendicular?(p1,p2) case p1.count when 2 then n1 = p1[1] when 4 then n1 = p1[0..2] end case p2.count when 2 then n2 = p2[1] when 4 then n2 = p2[0..2] end return Geom::Vector3d.new(n1).perpendicular?(n2) end def Geom.plane_plane_parallel?(p1,p2) case p1.count when 2 then n1 = p1[1] when 4 then n1 = p1[0..2] end case p2.count when 2 then n2 = p2[1] when 4 then n2 = p2[0..2] end return Geom::Vector3d.new(n1).parallel?(n2) endend在這幾個方法的基礎上,結合上文三個計算交點交線的方法,就可以綜合判斷點線面之間的位置關係了。
③距離
Geom:: Point 類提供了點-點、點-線和點-面距離的計算方法。這些方法也追加到 Array 類中,因此直接使用數組表示點坐標也可以使用這些方法。
p1 = Geom::Point3d.new(0,0,0)p2 = Geom::Point3d.new(3000.mm,4000.mm,0)line = [p2,Geom::Vector3d.new(-1,1,-1)]plane1 = [p2,Geom::Vector3d.new(-1,1,-1)]plane2 = [0,0,1,1000.mm]
puts Sketchup.format_length p1.distance(p2)puts Sketchup.format_length p1.distance_to_line(line)puts Sketchup.format_length p1.distance_to_plane(plane1)puts Sketchup.format_length p1.distance_to_plane(plane2)對於線-面距離,Geom 模塊中有一個 .closest_points 方法,可以獲取兩條直線中彼此距離最近的一對點坐標。如果兩條直線為異面直線,則返回唯一的最近距離點對。如果兩條直線相交或重合,則返回的兩點相等且為交點(相交)或第一條直線的定位點(重合)。如果兩條線平行而不重合,點對為第一條直線的定位點和另一直線上對應的最近點。
由於沒有直線與直線最近距離的方法,可以在 .closest_points 方法的基礎上在 Geom 模塊中追加一個自定義的方法:
module Geom def Geom.distance_line_line(la,lb) points = closest_points(la,lb) return(points[0].distance(points[1])) endend對於面-面距離就只針對平行面了,因而適用範圍更小,在此處僅列出一小部分實現方法僅供參考:
module Geom def Geom.distance_plane_plane(pa,pb) if pa.count==4 and pb.count==4 then unless Geom::Vector3d.new(pa[0..2]).parallel?(pb[0..2]) then return 0 else if Geom::Vector3d.new(pa[0..2]).samedirection?(pb[0..2]) then return (pa[3]-pb[3]).abs else return (pa[3]+pb[3]).abs end end else end endend最後還是按照慣例放一些補充內容:
①文中例子的點或者向量的定義都採用的「point_」/「vector_」+大寫字母的規則來命名。這一方面是為了區分點和向量,更重要的是,ruby中大寫字母開頭的標識符為模塊、類或者常量名。例子中雖然沒有去編輯這幾個點和向量的坐標,但也視之為變量,因此還是應該使用小寫字母或者下劃線開頭。
②一個關於方法定義名稱的疑問。為什麼判斷向量是否為單位向量的方法 .unitvector? 不用構詞上更具有聯繫的 .normalized? 的表述,或至少將其列為別名呢?
③以下提供一個簡易的點法式轉原點距式的函數:
def plane2_to_plane4(p2) vec=p2[1] dist=p2[0].distance_to_plane(p2) axis=[Geom::Point3d.new,vec] intersect=Geom.intersect_line_plane(axis,p2) vec_ori=intersect.vector_to([0,0,0]) res=vec.normalize.to_a case vec_ori.dot(vec)<=>0 when 1 then res << vec_ori.length when -1 then res << -vec_ori.length when 0 then res << 0 end return resend這是一個圖省事的做法,用到了Geom中的種種構造。但實際上這是一個純粹的數學問題,可以僅使用數組坐標的計算就能很好地解決這個問題。
這是Apiglio SU Ruby教程的第三篇,編號為「SU-R06」,本系列的其他文章可以在公眾號後臺輸入「SU-R」+兩位數編號查看,或者直接點擊菜單中的「SU Ruby」選項獲得全部有關SketchUp文章的目錄。