劉 藝 胡振聯(lián) 吳學林
(機械工業(yè)勘察設(shè)計研究院有限公司,陜西 西安 710043)
在線路工程勘察過程中,一旦線路調(diào)整,將導致勘探點里程和偏移量也隨之不斷地變化,在CAD中使用人工手動反復解算勘探點里程和偏移量的工作量很大。我們實現(xiàn)了一種智能解算的方法,能夠提高工作效率和解算精度,現(xiàn)在本文中介紹這種方法的原理和實現(xiàn)方法。
勘察專業(yè)確定一個勘探點的空間位置常常用坐標和高程來描述。但在線路勘察中的勘察對象是空間內(nèi)的線狀構(gòu)筑物,例如鐵路、公路和管線等。這種情況下,工程上就會以線狀對象為參照,采用里程、偏移量和高程來確定一個勘探點的空間位置。
使用坐標和高程或者使用里程、偏移量和高程來確定勘探點的位置這兩種方法只是在平面位置的描述上不同,而高程卻是相同的,所以接下來本文僅討論勘探點平面位置的問題。畫圖解釋一下上述概念。
如圖1所示,粗實線為帶有里程的線狀勘察對象,平面中布置有一個勘探點A。如果要確定A的平面位置,除了用坐標來表示以外還可以用里程和偏移量來表示。使用后者表示A的平面位置的原則為:首先通過A點對線路c作垂線,垂足為B(通常只有一個垂足,如果有多個垂足則選擇AB長度最短的B點作為垂足),那么B點在線路c上的里程就是勘探點A的里程,線段AB的長度就是勘探點相對于線路的偏移量。偏移量的正負按如下原則確定:站在線路上,面向大里程方向,左邊為負,右邊為正,那么圖1中勘探點A的偏移量為一個負值。
基于上述定義,一個固定位置的勘探點A的里程和偏移量會隨著線路的平面位置或者里程的變化而變化。當勘探點數(shù)量眾多時,手動解算里程和偏移量的工作量非常繁瑣。面對這種機械的工作,我們考慮采用電算的方法來解決。
我們需要抽象化這些工程元素以方便使用計算機來模擬。
對于線路c,我們使用了帶有方向的多段線對象來模擬。這種帶有方向的多段線實際上是一個數(shù)組{(x1,y1,z1),(x2,y2,z2),…,(xn,yn,zn)},這個數(shù)組中每個元素都包含xi,yi,zi三個實型變量,它可以描述空間中的一個點。那么多段線表示空間已知的n個點,這n個點按照數(shù)組中元素排列的先后順序連接起來形成一個有方向的多段線,它的起點為第1個點,終點為第n個點。
對于線段AB,我們使用了線段對象來模擬。線段對象可以用一個包含2個元素的數(shù)組來表示:{(xA,yA,zA),(xB,yB,zB)}。
對于散點元素,例如勘探點A,垂足B等等,我們可以使用一個點對象來表示:(xi,yi,zi)。
對于已經(jīng)給定的勘探點A和線路多段線c需要用如下方法來確定垂足B:連接A點和多段線c各節(jié)點,得到一組線段:AC1,AC2,…,ACn。解算這一組線段與多段線c的夾角。當多段線上某相鄰兩個節(jié)點Ci和Ci+1與A點構(gòu)成的三角形符合式(1)時,可以判定A點在多段線c上有垂足,且垂足位于線段CiCi+1上。
∠ACiCi+1≤90°且∠ACi+1Ci+2≥90°
(1)
當一個勘探點A在多段線c上存在垂足B的時候,我們需要判斷偏移量的正負以及數(shù)值。
為了方便代碼實現(xiàn),我們使用經(jīng)典幾何與解析幾何的方法來求解偏移量的正負和數(shù)值,方法如下:1)過Ci點作向右的水平線CiD,求解∠Ci+1CiD的角度β,見圖2。2)將三角形ΔACiCi+1按Ci點順時針旋轉(zhuǎn)角度β。旋轉(zhuǎn)之后,線段CiCi+1必然為一條水平線,且Ci的x坐標一定小于Ci+1的x坐標,見圖3。3)比較旋轉(zhuǎn)之后點A與點Ci的y坐標值。若yA>yCi,則偏移量為負;若yA=yCi,則偏移量為0;若yA yA-yCi即可直接作為偏移量的結(jié)果用于輸出。 勘探點A在多段線c上的投影里程就是垂足B點在多段線c上的里程。 已知垂足B位于線段CiCi+1上,則B的里程可以按下式求得: 其中,L為垂足在多段線上的里程;H為多段線的起點里程。 將第4節(jié)介紹的算法畫成程序框圖如圖4所示。 考慮到工程制圖常用的工具軟件是Autodesk公司開發(fā)的AutoCAD工具軟件,故本算法的實現(xiàn)使用了VBA語言。在本文編寫之前,我們已經(jīng)寫出了可以用于工程的數(shù)據(jù)健壯的完整程序。 顯然,程序框圖中最核心的代碼是步驟2和步驟3?,F(xiàn)將編譯通過的相關(guān)代碼列于以下: 步驟2:獲取多段線上的點。 If TypeOfreturnObjIsAcadLWPolyline Then n=(UBound(returnObj.Coordinates)+1)/2 ElseIfTypeOf poly Is AcadPolyline Then n=(UBound(returnObj.Coordinates)+1)/3 End If ’以上代碼得到多段線有n個點結(jié)束 ’以下代碼用于搜索多段線符合要求的段落 ’選取一個鉆孔 Dim w As IntegerDim ntxt As Integerntxt=0 For w=0 To 2 On Error GoTo err1 a=ThisDrawing.Utility.GetPoint(,"拾取一個點:") For i=1 To n-1 ’MsgBox("下標已經(jīng)到:"&i) judge=ifin(a,returnObj.Coordinate(i-1),returnObj.Coordinate(i)) If judge=0 Then ElseExit ForEnd If Next ’以上代碼完成’得到里程 Dim countformile As Integer Dim mile As Doublemile = 0 ’MsgBox (i) For countformile=1 To i mile=mile+distant(returnObj.Coordinate(countformile-1),returnObj.Coordinate(countformile)) Next mile=startmile.text+mile-Sqr(distant(returnObj.Coordinate(i),a)^2-offset^2) Dim strmile As String strmile=CStr(Format(Round(mile,2),"0+000.00")) result.text=strmile ’得到里程結(jié)束 步驟3:解析偏移量。 Public Function distofline(a,b,c As Variant) As Double ’點到線段的距離公式,a是點,b,c是線段的段點 ’根據(jù)這些點創(chuàng)建二維多段線 Dim pi As Variant Dim polyObj As AcadLWPolyline Dim vertices(0 To 5) As Double Dim offset As Double vertices(0)=a(0):vertices(1)=a(1) vertices(2)=b(0):vertices(3)=b(1) vertices(4)=c(0):vertices(5)=c(1) Set polyObj=ThisDrawing.ModelSpace.AddLightWeight Polyline_ (vertices) polyObj.closed=True offset=(polyObj.Area)*2/Sqr((b(0)-c(0))*(b(0)-c(0))+(b(1)-c(1))*(b(1)-c(1))) ’判別偏移量的正負 Dim aa(0 To 2) As Double Dim bb(0 To 2) As Double Dim cc(0 To 2) As Double aa(0)=a(0)aa(1)=a(1)aa(2)=0bb(0)=b(0)bb(1)=b(1) bb(2)=0cc(0)=c(0)cc(1)=c(1)cc(2)=0 Dim line1 As AcadLine Dim line2 As AcadLine Set line1 = ThisDrawing.ModelSpace.AddLine(aa, bb) Set line2 = ThisDrawing.ModelSpace.AddLine(aa, cc) polyObj.Rotateaa, -line1.angle ’ MsgBox (polyObj.Coordinate(1)(0) & ";" &polyObj.Coordinate(1)(1) &Chr(10) &polyObj.Coordinate(2)(0) & ";" &polyObj.Coordinate(2)(1)) Dim lineforang As AcadLine aa(0) = polyObj.Coordinate(1)(0) aa(1) = polyObj.Coordinate(1)(1) bb(0) = polyObj.Coordinate(2)(0) bb(1) = polyObj.Coordinate(2)(1) Set lineforang = ThisDrawing.ModelSpace.AddLine(aa, bb) If lineforang.angle>Atn(1) * 4 Then offset = Abs(offset Else offset = -Abs(offset) End If ’正負判別結(jié)束’ distofline = offset ’消除輔助線 lineforang.Delete line1.Delete line2.Delete ’ polyObj.Rotateaa, line1.angle polyObj.Delete ’輔助線消除完畢 End Function 程序框圖中的步驟8專門用來處理一些特殊情況。有如下幾種特殊情況和工程相關(guān)。 如圖5所示,從勘探點A是無法對線路c作垂線的。當然這種情況也是工程上不允許的。試想,無論是鐵路還是公路,都不會以角度的方式來拐彎。出現(xiàn)這種情況通常是技術(shù)員用多段線擬合線路時在轉(zhuǎn)彎處的點間距太大所致。解決的方法就是增加描線的節(jié)點密度,如圖6所示。 如圖7所示的情況,勘探點A在線路c上有多個垂足。工程上這也是不可能的,但在理論上,這種情況卻非常有可能。處理的方式就是選擇偏移量絕對值最小的那個垂足。 如果用多段線來擬合實際線路,在直線段是不存在偏差的,可是在線路拐彎處則會不可避免地出現(xiàn)偏差,如圖8所示。 因為無論多段線的節(jié)點多么密集也無法擬合成弧線。對于這種情況的處理方式如下。 首先要滿足勘察的精度。規(guī)范允許勘探點在實際施工中進行必要的挪動。相比之下線路上的弧形拐彎帶來的里程偏差則十分微小。 其次,當多段線擬合的線路太長,拐彎太多,檢查程序輸出的里程和線路上標注的實際里程的差值已不能滿足規(guī)范要求時,可以采用打斷多段線的方式來處理。我們只需要準確地輸入打斷處的里程作為第二條多段線的起始里程,那么誤差就會歸零。這種方法同樣可以用來處理線路上的短鏈或長鏈問題。 上文說到我們已經(jīng)開發(fā)出可用于工程實踐的工具軟件,現(xiàn)演示如下。 輸入多段線擬合線路的起始里程然后點擊獲取里程和偏移量,詳見圖9。點選勘探點即可輸出勘探點的里程和偏移量,詳見圖10。 1)因為指定對象,所以這種算法可以用于非常復雜的平面圖,圖中復雜的底圖元素并不會對本算法的計算過程產(chǎn)生干擾。2)該方法是對AutoCAD采用VBA工具的二次開發(fā),所以我們得到的成果具有跨操作系統(tǒng)和跨CAD版本的廣泛兼容性。3)使用VBA工具開發(fā),可以提供友好的用戶界面。軟件的友好性、易用性和數(shù)據(jù)的健壯性都要優(yōu)于lisp代碼使用命令行人機交互的方式。 1)本算法雖然用于對平面圖中勘探點里程和偏移量的解算,但是算法中預(yù)留了高程數(shù)據(jù)接口,在有需要的情況下可以用來處理三維問題。 2)還可以考慮采用批處理方式將獲取數(shù)據(jù)直接輸出到各種勘察軟件預(yù)留的接口內(nèi)從而進一步提高工作效率。4.3 里程的確定
5 算法的實現(xiàn)
5.1 程序框圖
5.2 代碼實現(xiàn)
6 幾種特殊情況的討論
6.1 多段線上沒有勘探點的垂足
6.2 多段線上有多個垂足
6.3 精度問題
7 實例演示
8 算法特點及展望
8.1 算法特點
8.2 展望