1. 程式人生 > >如何判斷兩條線(軌跡)的重疊區域

如何判斷兩條線(軌跡)的重疊區域

轉載於:http://www.cnblogs.com/naaoveGIS/

1.背景
假設有兩條軌跡,一條是預定軌跡,一條是實際軌跡,分別為L1、L2。L1由點(A1、A2、A3、…、AN)組成,L2由(B1、B2、B3、…、BM)組成。現在給出了一個容差範圍,即L2上的點能與L1這條預定路線的垂直容差範圍Range,求L2上滿足要求的實際點。

這個需求我們實際可以分為兩種情況來考慮,一種是此需求單純的僅僅是要求得到與L1能有一定匹配度的點。但是,如果我們深入分析,會發現L1作為一條線,其本身是有方向性的,如果我們還將線的方向性考慮進來,即L2的點不僅要在與L1的Range範圍內,還要此時的點的前進趨勢與L1是相同的。

當然,我們通過AGS或者GeoServer之類的NA服務是可以實現最鄰路徑生成的方法的,這個方法我們留在我的從底層談WebGIS的設計實現系列中跟大家一起探討。這裡我要跟大家討論一種效率更高的方法,直接通過資料庫的儲存過程來實現。

我在上面提到的兩種情況(不考慮方向性和考慮方向性),這兩者是層層遞進的。我們首先考慮如何通過不考慮方向性來解決。然後再進一步探討如果有方向性,我們該用什麼思路去實現。

2.不考慮方向性的演算法實現
2.1進一步簡化問題
這裡,首先我們將問題進一步簡化,即如何判斷一個點是否落在兩個點組成的線的容差範圍內,距離描述為:a點、b點兩個計劃點,c點為實際點,現在要判斷c點是否在a點和b點連線成的直線的容差範圍內。

2.2解決簡化問題的思路
我將解決步驟分為三步。分別為:1.粗略判斷;2.判斷是否落線上外;3.垂線判斷。

詳細過程便是:

A.粗略判斷,c點和a點以及b點的連線是否在容差範圍內,即ac或者bc是否在容差範圍內。如果是,返回true。否則,進一步判斷。

B.判斷c點是否在ab直線的外側,即c點到ab的垂足在ab的延長線上(如果是這種情況,只給一個容差範圍是很難確定是否符合標準的,需要多個與容差有關的引數,比如水平容差和垂直容差等,為了簡化,此種情況下,直接返回false)。如果垂足在ab上,則進行下一步。

C.算出c點到ab的垂線距離d。判斷d是否在容差範圍內,如果在,返回true;否則,返回false。

2.3實現判斷點是否線上範圍內(使用儲存過程)
利用海倫公式求點到線段的距離。

傳遞的引數中。x0、y0、x1、y1為預定軌跡的兩個座標(P0,P1),x2、y2為第三個座標(實際位置S)的座標, fRange為比對距離,return 0 超出,return 1未超出。

function getNearestDistance(x0 in number,y0 in number,x1 in number,y1 in number,x2 in number,y2 in number,fRange in number := 1,distance out number) return integer is

fa number(15,3);

fb number(15,3);

fc number(15,3);

fl number(15,3);

fs number(15,3);

begin

fa := sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));

fb := sqrt((x0-x2)*(x0-x2)+(y0-y2)*(y0-y2));

fc := sqrt((x0-x1)*(x0-x1)+(y0-y1)*(y0-y1));

if fa < fRange then --當fa邊長度小於警告距離時

  distance := fa;

  return 1;

end if;

if fb < fRange then --當fb邊長度小於警告距離時

  distance := fb;

  return 1;

end if;

if fc < 0.01 then --當軌跡的兩個座標點重合時

  return 0;

end if;

if(fa*fa>=fb*fb+fc*fc) then –P0處角度為(鈍(直)角),垂足在外

  distance := fb;

  return 0;

end if;

if(fb*fb>=fa*fa+fc*fc) then – P1處角度為(鈍(直)角),垂足在外

  distance := fa;

  return 0;

end if; 

--利用海倫公式求垂直距離

fl := (fa+fb+fc)/2;     --周長的一半    

fs := sqrt(fl*(fl-fa)(fl-fb)(fl-fc)); –海倫公式求面積,也可以用向量求

distance := 2*fs/fc; 

if distance < fRance then

  return 1;

end if;

return 0;

end;

2.4實現整個流程
先查詢得到整個預定線路的座標,再查詢出需要判斷的點S,遍歷整個預定線路判斷S是否在整個線路的某條線段的容差範圍內。

再查詢出實際線路中的第二個實際點,重複上面的過程。

第一個過程的實現如下:

isOutOfRanceErr := 1;

open rs2 for select a.X,a.Y,b.X,b.Y,c.預警距離 from 座標點表 a, 座標點表 b, 軌跡表 c where a.軌跡ID=b.軌跡ID and a.軌跡ID = c.軌跡ID and a.座標ID+1=b.座標ID order by a.軌跡ID,a.座標ID;

   loop

     Fetch rs2 into fP0X,fP0Y,fP1X,fP1Y,fToleRance;

     Exit when rs%Notfound;

       dummy := getNearestDistance(fP0X,fP0Y,fP1X,fP1Y,fCoordinateX,fCoordinateY,fToleRance,fDistance);

       if dummy = 1 then

          isOutOfRanceErr := 0;

          exit;

       end if;

     end loop;

   close rs2; 

3.考慮方向性的演算法的實現
如果軌跡的對比還考慮方向性,即線路a-b-c-d與線路a-c-b-d是不同,其實,此時只需要用一個變數來標記每一次吻合時,陣列已經對比到的地方,下次對比時應該從標記處開始後推就能實現方向性問題了。

                                                                       -----歡迎轉載,但保留版權,請於明顯處標明出處:http://www.cnblogs.com/naaoveGIS/