代碼已經po上遠程倉庫,需要的同學可以自取:
https://github.com/XiaoZhong233/GIS_ALG/blob/master/src/scau/gz/zhw/Raster.java
目錄
一、邊界代數法算法思想
邊界代數多邊形填充算法是一種基於積分思想的矢量轉柵格的轉換算法。
這個和格林公式很像,就是根據邊界關系求積分,邊界代數的思想應該是從這里來的
“設閉區域 由分段光滑的曲線
圍成,函數
及
在
上具有一階連續偏導數,則有
其中 是
的取正向的邊界曲線。”
不過我的算法實現過程和高數沒什么關系。先來一波高數勸退哈哈。
沿着多邊形的邊界進行順時針環繞。當當前環繞方向向上時,則位於該邊界左側(前進方向看為左側)的具有相同行坐標的所有柵格的值減去a;當當前環繞方向向下時,則位於該邊界左側(前進方向看為右側)的具有相同行坐標的所有柵格個的值加上a。
當環繞方向為水平方向則不用管。
但在實際操作過程中,如果多邊形內部有孔洞,則有可能造成填充值不唯一的情況,不過這沒關系,一樣可以把多邊形的內部和外部區分開,因為外部的值怎么樣都為0。內部的值雖然不一定都為a,但是一定不為0。
二、算法步驟
①遍歷多邊形的每一條邊
②判斷該邊是否為上行方向,若為上行則把前進方向左側全部-1,若不是則進入步驟③
③判斷該邊是否為下行方向,若為下行則把前進方向的右側全部+1。
④重復步驟②,③直至多邊形的邊遍歷完成。
三、算法實現
//矢量化多邊形(邊際代數法)
public void RasterPolygon2(Polygon polygon) {
List<Line> lines = polygon.getLines();
//RasterLine(polygon, 1);
for(Line line : lines) {
Point start = line.getStart();
Point end = line.getEnd();
int[] startPoint = transformRasterPoint(start, 0, 0);
int[] endPoint = transformRasterPoint(end, 0, 0);
int startRow = Math.max(startPoint[0], endPoint[0]);
int endRow = Math.min(startPoint[0], endPoint[0]);
if(line.isUp()) {
while(startRow>=endRow) {
int column = 0;
while(column<=Math.max(startPoint[1], endPoint[1])) {
Point p = transformVetorPoint(endRow, column, 0, 0);
//保證p在線段的左邊
if(Double.doubleToLongBits(p.getX()) < Double.doubleToLongBits(line.getXByY(p.getY()))
&& Double.doubleToLongBits(line.getXByY(p.getY()))>=Double.doubleToLongBits(Math.min(line.getStart().getX(),line.getEnd().getX()))
&& Double.doubleToLongBits(line.getXByY(p.getY()))<=Double.doubleToLongBits(Math.max(line.getStart().getX(), line.getEnd().getX()))) {
addValue(endRow, column, -1);
}
column++;
}
endRow++;
}
}else if(line.isDown()) {
while(startRow>=endRow) {
int column = 0;
while(column<=Math.max(startPoint[1], endPoint[1])) {
Point p = transformVetorPoint(endRow, column, 0, 0);
//保證p在線段的左邊
if(Double.doubleToLongBits(p.getX()) < Double.doubleToLongBits(line.getXByY(p.getY()))
&& Double.doubleToLongBits(line.getXByY(p.getY()))>=Double.doubleToLongBits(Math.min(line.getStart().getX(),line.getEnd().getX()))
&& Double.doubleToLongBits(line.getXByY(p.getY()))<=Double.doubleToLongBits(Math.max(line.getStart().getX(), line.getEnd().getX()))) {
addValue(endRow, column, 1);
}
column++;
}
endRow++;
}
}
}
}
四、測試結果
輸入數據:
Point d,e,r,t,y,o,q;
o=new Point(10, 22);
d=new Point(12, 25);
e=new Point(20, 25);
r=new Point(22, 18);
t=new Point(13, 18);
y=new Point(16, 10);
Point[] points = new Point[] {o,d,e,r,t,y};
Polygon polygon = new Polygon(points,true);
繪制結果(矢量繪制):
輸出結果(控制台輸出繪制):
當多邊形內部存在孔洞的情況下:
可以發現孔洞處(GIS上的概念對應的應該是島與洞)的值比外部更大(或者更小,取決於你是順時針環繞還是逆時針環繞,是上行方向+1還是下行方向+1抑或是別的條件的差異,不過都沒關系,不會影響是否在多邊形內部關系的判斷),這是因為在孔洞的邊界多環繞了一次。由這一點我們也可以發現,邊界代數法可以很好的保存多邊形的拓撲關系,無論這個孔洞是在內部,亦或者是多個多邊形鄰接,我們可以通過其屬性值判斷多邊形之間的關系。
五、總結
邊界代數法與前述面狀轉換算法(《GIS算法基礎(五)》)的不同之處,在於它不是逐個逐個的點判斷與邊界的關系,而是根據邊界的拓撲信息,通過簡單的加減代數運算將邊界位置信息動態地賦予各柵格點。這就是邊界代數法巧妙而優美的地方。實現了矢量格式到柵格格式的高速轉換(因為計算簡單,量也不大),並且不需要考慮搜索軌跡之間的關系,因此算法簡單、可靠性好、各邊界弧段只被遍歷一次,不需重復計算。