2.4 .Thuật toán lấy dữ liệu AOT từ vùng chọn trên Google Map
2.4.2 .Thuật toán đọc giá trị AOT từ điểm thuộc đa giác vùng chọn
Để có thể thống kê được các điểm AOT nằm trong đa giác thuộc vùng chọn thì đầu tiên ta cần kiểm tra xem điểm đó có nằm trong đa giác này hay khơng. Bởi vì ta khơng biết được điểm nào là điểm thuộc đa giác nhưng ta biết rằng với mọi đa giác có thể tạo ra 1 hình chữ nhật bao bên ngồi (minX = min(x1, x2,...xn) với x thuộc Polygon), minY = min(y1, y2,...yn) với y thuộc Polygon, maxX = max(x1, x2,...xn) với x thuộc Polygon, maxY = max(y1, y2,...yn) với y thuộc Polygon.
Như vậy, ta sẽ giới hạn khơng gian tìm kiếm là: duyệt tất cả các điểm thuộc hình chữ nhật bao quanh đa giác và kiểm tra xem nó có nằm trong đa giác Polygon khơng (thay vì duyệt tồn bộ ma trận điểm ảnh mà khơng giới hạn vùng tìm kiếm). Để làm được điều đó, ta sử dụng thuật toán Ray Casting - một thuật toán được sử dụng rất
rộng rãi trong đồ họa máy tính, GIS,...để kiểm tra 1 điểm thuộc hay không thuộc đa giác (tên khác là Point in Polygon - PIP).
Tư tưởng của thuật toán là: nếu điểm A cắt các cạnh của đa giác tại các điểm với số lần là lẻ thì là ở trong đa giác, cịn nếu số lần là chẵn thì ở ngồi đa giác.
Ví dụ ở đây là điểm A nằm trong đa giác vì số giao điểm với đa giác là 3, cịn điểm B nằm ngồi đa giác vì số giao điểm với đa giác là 4.
Hình 2.16. Thuật tốn Ray Casting xác đỉnh điểm thuộc đa giác
Như vậy, để nhận biết điểm A (xA, yA) bất kỳ có thuộc trong đa giác cần xét thì ta sẽ đi kiểm tra mối liên hệ của phương trình đường thẳng đi qua A, y = xA và phương trình đường thẳng đi qua từng cặp cạnh của đa giác.
Tại mỗi bước, lấy ra 2 đỉnh Pi(x1, y1) và Pi +1(x2, y2) của đa giác liền kề nhau, viết phương trình đường thẳng đi qua 2 đỉnh này và kiểm tra mối liên hệ giao cắt với phương trình đường thẳng đi qua điểm A (y = xA).
Ta có phương trình đường thẳng đi qua pi(x1, y1) và pi + 1(x2, y2) bất kỳ dạng tổng quát như sau:
y = k.x + m với
Sau khi tính được hệ số góc k, ta có thể tính m với cơng thức: m = y1 – k.x1. Thay k và m ở 2 biểu thức trên ta có được phương trình đi qua 2 đỉnh của đa giác: y = k.x + m.
Theo Hình 2.17. các trường hợp xét điểm thuộc đa giác chia làm 4 trường hợp:
Điểm A nằm ngoài đa giác (P1) nếu nó nằm ngồi hình chữ nhật bao đa giác: kết quả là không nằm trong đa giác, không cần xét tiếp các trường hợp khác.
Điểm A thuộc 1 đỉnh của đa giác (P2): chỉ cần duyệt dẫy các đỉnh của đa giác, kết quả là nằm trong đa giác, không cần xét tiếp các trường hợp khác.
Điểm A thuộc 1 cạnh của đa giác (P3) hoặc điểm A nằm trong đa giác (P4): lần lượt xét phương trình đường thẳng y = xA với các phương trình đường thẳng đi qua các cặp cạnh của đa giác (AB, BC, CD, DA). Đặt biến kiểm tra inside = False, nếu y = xA cắt đường thẳng đi qua 2 đỉnh Pi(x1, y1) và Pi + 1(x2, y2) tại điểm P (xp, yp) với điều kiện:
(xp >= x1 và xp <= x2) và (yA <= max(y1, y2)) và (yA <= k.xA + m)
Tại vì ta chỉ xét điểm P được y = xA cắt cạnh pipi +1 tại điểm P thuộc cạnh này, và chỉ xét trường hợp là xét điểm A: y = xA cắt cạnh ở trên nó, không xét trường hợp y = xA cắt cạnh ở bên dưới nó. Nếu thỏa mãn điều kiện trên thì inside = not inside, lặp lại đến khi xét hết các cặp cạnh của đa giác, nếu inside = True (số lẻ lần cắt cạnh thì nằm
trong đa giác), nếu biến inside = False (số chẵn lần cắt cạnh thì nằm ngồi đa giác). Thuật toán được cài đặt trong 1 Python script với đầu vào là dẫy các điểm thuộc Polyon và các cặp tọa độ của hình chữ nhật bao quanh đa giác (có 1 hàm PHP có nhiệm vụ tìm hình chữ nhật bao quanh 1 đa giác bất kỳ để giới hạn khơng gian tìm kiếm). Và chương trình Python này sẽ duyệt lần lượt các điểm trong hình chữ nhật từ trên xuống dưới, trái qua phải, mỗi điểm sẽ kiểm tra xem là điểm này có nằm trong Polygon trên khơng. Nếu có thì lấy giá trị AOT của nó để thống kê, nếu khơng thì bỏ qua điểm này và xét các điếm tiếp theo đến khi duyệt hết điểm trong hình bao ngồi.
Giả mã của thuật toán Point In Polygon:
// n là số đỉnh của đa giác bool inside = false;
for ( int i = 0; i < n; i++ ) {
/* Kiểm tra điều kiện điểm P(xp, yp) có thể cắt được phương trình đi qua 2 điểm Pi(x[i], y[i]) và P(i + 1)(x[i+1], y[i+1]) */
if ( xp > x[i] && xp <= x[i+1] && (yp <= max(y[i], y[i+1] )) { /* Tìm phương trình đường thẳng đi qua PiPi + 1: y = k.x + m */ float dx = x[i + 1] - x[i]; // delta X
float dy = y[i + 1] - y[i]; // delta Y float k = dy / dx; // hệ số góc k
float m = y[i] - k * x[i]; // tham số m
// Kiểm tra xem y = yA có cắt y = k.x + m (cạnh PiP(i + 1) ở phía trên điểm A) float Y = k*x + m;
if ( yp <= Y ){
inside = not inside; }
} // endif }// endfor
return inside;
Thuật toán thực hiện với thời gian khá nhanh vì đã tối ưu khi giới hạn khơng gian tìm kiếm và giới hạn trường hợp tìm kiếm. Tuy nhiên, với ảnh viễn thám MODIS 4 Level 2 nếu Polygon vùng chọn tìm kiếm là dạng quốc gia thì số điểm (latitude, longtitude) sau khi chuyển sang (x, y) bị trùng nhau liên tiếp rất nhiều. Ví dụ: 1000, 1000, 1000,...,1001, 1001,...1002,...Vì vậy có 1 hàm PHP để làm nhiệm vụ là lọc bỏ các điểm trùng nhau liên tiếp này do chúng chỉ làm chậm thuật toán, tăng số điểm đầu vào dẫn đến vòng lặp duyệt các đỉnh thuộc đa giác tăng lên và khơng có tác dụng gì khác.