關(guān)日釗,陳新度,吳 磊
廣東工業(yè)大學(xué) 機(jī)電工程學(xué)院,廣州 510006
STL文件格式最早是由美國3D System公司推出,是三維實(shí)體模型系統(tǒng)的一個(gè)接口標(biāo)準(zhǔn),其接口格式規(guī)范,目前已被工業(yè)界認(rèn)為是快速成型領(lǐng)域的標(biāo)準(zhǔn)描述文件格式,廣泛應(yīng)用于制造業(yè)、地理信息系統(tǒng)、醫(yī)學(xué)影像等領(lǐng)域[1-2]。其采用以點(diǎn)云數(shù)據(jù)為基礎(chǔ),組成一系列無序三角面來表達(dá)三維實(shí)體模型的表面,在快速成型制造系統(tǒng)中已經(jīng)成為了一種標(biāo)準(zhǔn)的數(shù)據(jù)輸入,可以通過三維建模軟件或三維掃描儀生成[3]。
目前,STL模型的位姿調(diào)整工作主要利用Solid-Works、UG等建模軟件,通過建模時(shí)確定模型的建模坐標(biāo)系和輸出STL模型格式時(shí)改變模型的輸出坐標(biāo)系這兩種方式來完成。由于建模軟件不能直接操作只有點(diǎn)云數(shù)據(jù)的STL格式文件以及在修改模型建模坐標(biāo)系上缺乏靈活性,本文開發(fā)出一套面向點(diǎn)云模型的交互式位姿調(diào)整系統(tǒng),其直接的操作對象為STL模型文件,與普通的調(diào)整方式相比,其在操作上更加方便和靈活。
系統(tǒng)軟件由Qt與OpenGL作為開發(fā)平臺,其中Qt是一個(gè)跨平臺應(yīng)用程序和UI開發(fā)框架。使用Qt只需一次性開發(fā)應(yīng)用程序,無需重新編寫源代碼,便可跨不同桌面和嵌入式操作系統(tǒng)部署這些應(yīng)用程序。而OpenGL是專業(yè)的圖形程序接口,功能強(qiáng)大的底層圖形庫,因其硬件無關(guān)性、建模方便性、出色編程性等優(yōu)點(diǎn),在仿真領(lǐng)域有著廣泛應(yīng)用[4-5]。
在本系統(tǒng)中OpenGL只處理與3D圖形的繪制,基本上不提供創(chuàng)建用戶界面的功能,所以為OpenGL應(yīng)用程序創(chuàng)建用戶界面必須使用其他的圖形工其包。而Qt的OpenGL模塊很好地解決了這個(gè)問題,它提供了一個(gè)繼承自QWidget的OpenGL部件類QGLWidget,使得該部件類能夠像Qt其他部件那樣使用,還可以在繪制窗口部件時(shí)直接使用OpenGL的API接口。在Qt中為OpenGL提供支持的類主要有以下幾個(gè):
(1)QGLWidget:用來渲染OpenGL場景的Qt部件。
(2)QGLContext:用來封裝用于OpenGL場景渲染的部件。
(3)initializeGL():注冊函數(shù),在此設(shè)置GL的渲染繪制屬性、定義顯示列表、載入固定紋理等初始化工作。initializeGL()在調(diào)用paintGL()之前只被調(diào)用一次,之后不再調(diào)用。
(4)paintGL():繪制函數(shù),在此使用OpenGL中的接口進(jìn)行場景繪制,QGLWidget的paintEvent()將會自動調(diào)用paintGL()進(jìn)行部件的顯示繪制。
系統(tǒng)框架主要分為6個(gè)模塊,分別為GL模塊、UI模塊、IO模塊、圖元模塊、變換模塊和約束模塊。如圖1所示。
圖1 系統(tǒng)框架圖
其中GL模塊負(fù)責(zé)管理OpenGL各種場景和模型渲染等操作;UI模塊主要負(fù)責(zé)窗口、菜單等UI界面元素的管理以及鼠標(biāo)工具的管理;IO模塊負(fù)責(zé)STL模型文件的輸入與輸出管理;圖元模塊主要負(fù)責(zé)基本圖元的構(gòu)建和管理;變換模塊負(fù)責(zé)模型位姿的變換;約束模塊負(fù)責(zé)檢測模型變換是否引起沖突。
系統(tǒng)基本操作流程如圖2所示。
下面將對關(guān)鍵的步驟進(jìn)行簡單的描述,具體的實(shí)現(xiàn)過程和原理將在第3章論述。
(1)“打開STL文件”操作包含模型載入和顯示兩個(gè)過程。在模型載入的過程中,由于STL存在較多的冗余點(diǎn),因此在載入的過程中需要對冗余點(diǎn)進(jìn)行濾除。在顯示的過程中,主要利用了OpenGL中的顯示列表對模型進(jìn)行渲染。
(2)“構(gòu)建圖元”操作是利用鼠標(biāo)通過選擇點(diǎn)云來構(gòu)建直線和平面兩種基本圖元。其中包含了圖元拾取和圖元構(gòu)建這個(gè)兩個(gè)方面的內(nèi)容。
(3)“選擇配合方式”操作是利用直線和平面這兩種基本圖元進(jìn)行軸配合或平面配合。系統(tǒng)提供5種配合關(guān)系選擇,分別是軸平行配合、軸重合配合、平面平行配合、平面重合配合和原點(diǎn)配合。
STL文件的最大特點(diǎn)是由一系列以頂點(diǎn)為基礎(chǔ)的三角形面片以無序排列方式組合在一起,每條邊只能被兩個(gè)三角面片共用,而且每一個(gè)小三角形面片必須與相鄰的三角形面片共用兩個(gè)頂點(diǎn),每個(gè)頂點(diǎn)通常被重用6次左右,造成了巨大的數(shù)據(jù)冗余。一般情況下,冗余頂點(diǎn)數(shù)約為面片數(shù)的5/6倍[6-7]。
冗余點(diǎn)的濾除主要在載入文件時(shí)進(jìn)行,若省略這個(gè)過程,會給后面構(gòu)建圖元操作帶來不便。目前對于冗余點(diǎn)濾除的方法主要有平衡二叉樹法[8]、三軸分塊排序法[9]、哈希表法[10-11]等。衛(wèi)煒[12]等人實(shí)驗(yàn)表明,在三角片數(shù)量在5萬以上時(shí),哈希表法在上述三種方法中效率最高的,因此本文選擇哈希表法進(jìn)行冗余點(diǎn)濾除。
圖2 系統(tǒng)操作流程圖
哈希表是將一組關(guān)鍵字映射到一個(gè)有限的連續(xù)的地址集上,并以關(guān)鍵字在地址集中的“像”作為記錄在表中的存儲位置的一種表。本算法中使用鏈地址法處理沖突的哈希表[13],如圖3所示,Array是一個(gè)鏈表數(shù)組,每一個(gè)元素代表鏈表的頭指針,其大小是隨STL頂點(diǎn)數(shù)變化而變化的。Node是鏈表中的節(jié)點(diǎn)存儲結(jié)構(gòu),如圖4所示,每一個(gè)節(jié)點(diǎn)包含了一個(gè)點(diǎn)的X、Y、Z坐標(biāo)和一個(gè)指向下一個(gè)節(jié)點(diǎn)的指針。
圖3 哈希表結(jié)構(gòu)圖
圖4 節(jié)點(diǎn)結(jié)構(gòu)圖
哈希函數(shù)的“好壞”直接影響出現(xiàn)出圖的頻繁程度,也即直接影響哈希表的查詢效率。STL冗余節(jié)點(diǎn)濾除的依據(jù)是頂點(diǎn)坐標(biāo),即哈希表的關(guān)鍵字為頂點(diǎn)坐標(biāo)(X,Y,Z)。本算法根據(jù)關(guān)鍵字可以計(jì)算出哈希表鍵值,取值為:
其中
由上述可知,Q代表記錄在哈希表的位置,通過每一個(gè)頂點(diǎn)坐標(biāo)計(jì)算出來的鍵值可以馬上定位到該點(diǎn)所屬的鏈表,然后在所屬鏈表中通過與每個(gè)節(jié)點(diǎn)數(shù)據(jù)進(jìn)行比較去篩選出相同或者相近的點(diǎn)出來,本文是通過篩選相近的點(diǎn)來進(jìn)一步減少冗余點(diǎn)數(shù)量。表1為算法針對4個(gè)不同的STL三維模型篩選后的結(jié)果。
表1 哈希表冗余點(diǎn)濾除算法結(jié)果
圖元拾取過程是利用鼠標(biāo)拾取OpenGL渲染環(huán)境下的各種圖元,是圖元構(gòu)建和圖元配合兩個(gè)步驟的實(shí)現(xiàn)基礎(chǔ)。
3.2.1圖元拾取原理
OpenGL為了解決拾取問題,提供了一種基于名字堆棧和命終記錄的選擇機(jī)制。在OpenGL中,拾取物體是利用拾取矩陣和投影變換,將拾取的范圍限制在鼠標(biāo)熱點(diǎn)的有效區(qū)中,一旦觸發(fā)鼠標(biāo)事件就進(jìn)入選擇模式并將有效區(qū)初始化,最后利用拾取矩陣拾取有效區(qū)內(nèi)的物體。有效區(qū)的定義由glPickMatrix()函數(shù)來完成。一旦拾取成功,就以記錄的形式返回與拾取物體相關(guān)的信息,并生成一個(gè)記錄表示一個(gè)物體被命中。
3.2.2 圖元拾取步驟
(1)調(diào)用void glSelectBuffer()函數(shù)指定用于返回點(diǎn)擊記錄的數(shù)組,其中size決定了拾取一次最多可以返回多少個(gè)被選取對象。
(2)調(diào)用 Glint glRenderMode()函數(shù)并傳入 GL_SELECT作為參數(shù)進(jìn)入選擇模式。
(3)使用void glInitNames()和glPushName()對名字棧進(jìn)行初始化,其中name是一個(gè)無符號整型參數(shù),代表了每一個(gè)物體的ID,選取操作就是利用這個(gè)ID來獲取被選中的物體對象。
(4)定義用于選擇的視景體并且通過gluPickMatrix()函數(shù)構(gòu)造出一個(gè)挑選矩陣,并協(xié)同投影矩陣,把繪圖限制在視口的一個(gè)小區(qū)域內(nèi),一般是靠近光標(biāo)的位置。在確立了選擇模式并使用了特殊的挑選矩陣之后,在靠近光標(biāo)位置處繪制物體就會導(dǎo)致選擇點(diǎn)擊[5]。
(5)交替調(diào)用繪制圖元的函數(shù)和操縱名字棧的函數(shù),為每一個(gè)相關(guān)的圖元分配一個(gè)適當(dāng)?shù)拿Q。
(6)退出選擇模式,并處理返回的選擇數(shù)據(jù)。
圖元的構(gòu)建需要通過STL模型的點(diǎn)云數(shù)據(jù)進(jìn)行構(gòu)建,如圖5所示。圖中淺藍(lán)色的點(diǎn)云為工業(yè)機(jī)器人底座的STL模型數(shù)據(jù)。本系統(tǒng)提供直線圖元和平面圖元構(gòu)建功能。
圖5 底座模型點(diǎn)云渲染圖
3.3.1 直線圖元構(gòu)建
直線圖元的構(gòu)建需要通過選擇兩個(gè)頂點(diǎn)來進(jìn)行構(gòu)建,如圖6所示。紅色直線是利用鼠標(biāo)在點(diǎn)云中選擇兩個(gè)點(diǎn)構(gòu)建出來的。
圖6 直線圖元構(gòu)建圖
3.3.2 圓形平面圖元構(gòu)建
圓形平面圖元的構(gòu)建是根據(jù)“三點(diǎn)一面”原理。如圖7所示。圖中紅色平面是利用鼠標(biāo)在點(diǎn)云中選擇三個(gè)點(diǎn)構(gòu)建出來的。
圖7 平面圖元構(gòu)建圖
3.3.3 對稱平面圖元構(gòu)建
對稱面的構(gòu)建必須構(gòu)造兩個(gè)面,并且兩個(gè)面之間的夾角不為0°或180°,如圖8所示。
圖8 對稱面構(gòu)造示意圖
構(gòu)建步驟主要為:
(1)將Normal2和Normal1進(jìn)行叉乘得:
(2)將Normal1和CrossLine1進(jìn)行叉乘得:
(3)將模型上所有的點(diǎn)同時(shí)投影到CrossLine2上,投影過程中通過比較獲得在CrossLine2上投影距離最長的兩個(gè)點(diǎn)P1和P2。
(4)過P1點(diǎn)沿Normal1的方向上確定一個(gè)點(diǎn)P3,過P1、P2、P3三點(diǎn)作一圓面,該圓面便是模型的對稱面,如圖9所示,紅色平面為對稱面。
圖9 對稱平面圖元構(gòu)建圖
3.4.1 配合關(guān)系
整個(gè)配合過程是利用新構(gòu)建的直線或者平面圖元對已知的坐標(biāo)系進(jìn)行軸配合、平面配合或點(diǎn)配合,此坐標(biāo)系是一個(gè)自定義的右手坐標(biāo)系,可以當(dāng)作新的建模坐標(biāo)系,如圖10所示,紅線、綠線和藍(lán)線分別代表X軸、Y軸和Z軸。圖中模型為機(jī)器人底座的STL模型渲染圖。
圖10 建模坐標(biāo)系與STL模型圖
軸配合中的“軸”指的此坐標(biāo)系的X軸、Y軸和Z軸,平面配合中的“平面”指的是此坐標(biāo)系X-Y平面、Y-Z平面和Z-X平面,點(diǎn)配合中的“點(diǎn)”指的是此坐標(biāo)系的原點(diǎn)。
(1)當(dāng)選擇直線圖元進(jìn)行軸配合的時(shí)候,可分為兩種情況,一種是軸平行配合,如圖11所示。另一種是軸重合配合,如圖12所示。圖中黑線為選中的直線圖元,與X軸進(jìn)行軸配合。
圖11 軸平行配合
圖12 軸重合配合
(2)當(dāng)選擇平面圖元進(jìn)行面配合的時(shí)候,也可以分為兩種情況,一種是面平行配合,如圖13所示。另外一種是面重合配合,如圖14所示。圖中黑線為選中平面圖元的法線,平面圖元與平面Z-X進(jìn)行面配合。
圖13 面平行配合
圖14 面重合配合
當(dāng)選擇原點(diǎn)配合的時(shí)候,此時(shí)配合的圖元可以是直線圖元的首點(diǎn)或者平面圖元的圓心。圖15為直線原點(diǎn)配合,圖中黑線為所選直線圖元。圖16為面原點(diǎn)配合,圖中黑色透明平面為所選平面圖元。
圖15 直線原點(diǎn)配合
圖16 平面原點(diǎn)配合
3.4.2配合原理
整個(gè)配合的結(jié)果是通過進(jìn)行直線或平面配合而得出一個(gè)旋轉(zhuǎn)平移矩陣,然后利用這個(gè)矩陣對模型進(jìn)行相對于新的建模坐標(biāo)系的一次位姿變換,從而實(shí)現(xiàn)了改變模型建模坐標(biāo)系位姿的效果。
上面提到在配合過程中需要計(jì)算一個(gè)旋轉(zhuǎn)平移矩陣。其中旋轉(zhuǎn)矩陣是一個(gè)可以繞任意軸的旋轉(zhuǎn)矩陣,計(jì)算此矩陣需要用到旋轉(zhuǎn)四元數(shù)法。四元數(shù)是一種高級的數(shù)學(xué)工具,被應(yīng)用于各種工程領(lǐng)域,如導(dǎo)航、機(jī)器人和計(jì)算機(jī)圖形學(xué)[14],它是一種高階復(fù)數(shù),可以表示為式(5)[15]:
其中,i,j,k滿足式(6)和式(7):
由于i,j,k的性質(zhì)和笛卡爾坐標(biāo)系三個(gè)軸叉乘的性質(zhì)很像,所以可以將四元數(shù)寫成一個(gè)向量和一個(gè)實(shí)數(shù)組合的形式,如式(8)所示:
假設(shè)向量V繞任意軸N(nx,ny,nz)旋轉(zhuǎn)α角度得到向量V1,定義此變換過程的四元數(shù)表示為Q(x,y,z),那么 Q(x,y,z)可以表示為式(9)[16]:
在實(shí)際OpenGL編程中要實(shí)現(xiàn)模型的旋轉(zhuǎn)操作需要利用到旋轉(zhuǎn)矩陣去實(shí)現(xiàn),所以就需要把四元數(shù)公式轉(zhuǎn)化成矩陣形式來表示,如式(10)所示:
其中nx,ny,nz為任意旋轉(zhuǎn)軸,α為旋轉(zhuǎn)角度。
結(jié)合式(9)和式(10)可推導(dǎo)出式(11)為:
把式(11)代進(jìn)旋轉(zhuǎn)矩陣可以得出四元數(shù)的矩陣表現(xiàn)形式,如式(12)所示:
當(dāng)對直線進(jìn)行X軸平行配合時(shí),假設(shè)所選擇的直線圖元由a和b兩點(diǎn)組成,可以表示成一個(gè)向量Vab,設(shè)向量Vx=(1,0,0),則根據(jù)式(13)計(jì)算出Vab與Vx之間的夾角θ1:
在求出夾角后,對Vab與Vx進(jìn)行叉乘得到旋轉(zhuǎn)軸Vr。最后把θ1和Vr代入式(12)便可求出旋轉(zhuǎn)矩陣。
當(dāng)對平面進(jìn)行X-Y面平行配合時(shí),求出所選擇平面的法向量Vn,已知X-Y面的法向量為Vxoy=(0,0,1),利用Vn和Vxoy兩個(gè)向量則可以根據(jù)上述直線配合中求夾角和旋轉(zhuǎn)軸的方法算出最后的旋轉(zhuǎn)矩陣。
非掃描型STL模型指的是利用三維建模軟件建模導(dǎo)出的STL文件。圖17為一個(gè)待調(diào)姿機(jī)器人底座的STL模型。
圖17 待調(diào)姿機(jī)器人底座模型
通過構(gòu)建底座平面作為變換對象,再進(jìn)行“原點(diǎn)配合”變換操作來完成調(diào)姿工作。圖18為最終的調(diào)整效果。
圖18 調(diào)姿后機(jī)器人底座模型
掃描型STL模型指的是利用三維掃描儀掃描導(dǎo)出的STL文件,圖19為一個(gè)待調(diào)姿的馬桶STL模型。
圖19 待調(diào)姿馬桶模型
由于馬桶模型不是通過一般的軟件來建模,而是通過三維掃描儀進(jìn)行三維重建建模的,所以通過簡單的構(gòu)建平面去進(jìn)行調(diào)整是比較困難的,因此需要通過構(gòu)建模型的對稱面作為變換對象,當(dāng)對稱面與Z-X平面重合便達(dá)到所需要的效果,如圖20所示。
圖20 調(diào)姿后馬桶模型
本文結(jié)合Qt+OpenGL平臺開發(fā)出一套面向STL點(diǎn)云模型的交互式位姿調(diào)整系統(tǒng)可以改變STL模型建模坐標(biāo)系的位置姿態(tài)。通過交互式的手段構(gòu)建出輔助圖元,利用這些輔助圖元來實(shí)現(xiàn)模型建模坐標(biāo)系的位姿調(diào)整。適用于通過建模軟件導(dǎo)出的STL模型和通過三維掃描儀生成的STL模型。此外,在機(jī)器人離線編程領(lǐng)域中經(jīng)常需要用到STL模型建立仿真環(huán)境,無可避免需要對導(dǎo)入的STL模型進(jìn)行位置姿態(tài)調(diào)整。因此,本系統(tǒng)在離線編程軟件的開發(fā)中具有輔助性的作用。