tracingBorders
边界追踪。。
/** * Tracing contour borders of the grid data with undefined data. Grid data * are from left to right and from bottom to top. Grid data array: first * dimention is Y, second dimention is X. * * @param S0 input grid data * @param X x coordinate array * @param Y y coordinate array * @param S1 data flag array * @param undefData undefine data * @return borderline list */ public static ListtracingBorders(double[][] S0, double[] X, double[] Y, int[][] S1, double undefData) { List borderLines = new ArrayList<>(); int m, n, i, j; m = S0.length; //Y n = S0[0].length; //X //S1 = new int[m][n]; //---- New array (0 with undefine data, 1 with data) for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { if (doubleEquals(S0[i][j], undefData)) //Undefine data { S1[i][j] = 0; } else { S1[i][j] = 1; } } } //---- Border points are 1, undefine points are 0, inside data points are 2 //l - Left; r - Right; b - Bottom; t - Top; lb - LeftBottom; rb - RightBottom; lt - LeftTop; rt - RightTop int l, r, b, t, lb, rb, lt, rt; for (i = 1; i < m - 1; i++) { for (j = 1; j < n - 1; j++) { if (S1[i][j] == 1) //data point { l = S1[i][j - 1]; r = S1[i][j + 1]; b = S1[i - 1][j]; t = S1[i + 1][j]; lb = S1[i - 1][j - 1]; rb = S1[i - 1][j + 1]; lt = S1[i + 1][j - 1]; rt = S1[i + 1][j + 1]; if (l > 0 && r > 0 && b > 0 && t > 0 && lb > 0 && rb > 0 && lt > 0 && rt > 0) { S1[i][j] = 2; //Inside data point } if (l + r + b + t + lb + rb + lt + rt <= 2) { S1[i][j] = 0; //Data point, but not more than 3 continued data points together. } //So they can't be traced as a border (at least 4 points together). } } } //---- Remove isolated data points (up, down, left and right points are all undefine data). boolean isContinue; while (true) { isContinue = false; for (i = 1; i < m - 1; i++) { for (j = 1; j < n - 1; j++) { if (S1[i][j] == 1) //data point { l = S1[i][j - 1]; r = S1[i][j + 1]; b = S1[i - 1][j]; t = S1[i + 1][j]; lb = S1[i - 1][j - 1]; rb = S1[i - 1][j + 1]; lt = S1[i + 1][j - 1]; rt = S1[i + 1][j + 1]; if ((l == 0 && r == 0) || (b == 0 && t == 0)) //Up, down, left and right points are all undefine data { S1[i][j] = 0; isContinue = true; } if ((lt == 0 && r == 0 && b == 0) || (rt == 0 && l == 0 && b == 0) || (lb == 0 && r == 0 && t == 0) || (rb == 0 && l == 0 && t == 0)) { S1[i][j] = 0; isContinue = true; } } } } if (!isContinue) //untile no more isolated data point. { break; } } //Deal with grid data border points for (j = 0; j < n; j++) //Top and bottom border points { if (S1[0][j] == 1) { if (S1[1][j] == 0) //up point is undefine { S1[0][j] = 0; } else if (j == 0) { if (S1[0][j + 1] == 0) { S1[0][j] = 0; } } else if (j == n - 1) { if (S1[0][n - 2] == 0) { S1[0][j] = 0; } } else if (S1[0][j - 1] == 0 && S1[0][j + 1] == 0) { S1[0][j] = 0; } } if (S1[m - 1][j] == 1) { if (S1[m - 2][j] == 0) //down point is undefine { S1[m - 1][j] = 0; } else if (j == 0) { if (S1[m - 1][j + 1] == 0) { S1[m - 1][j] = 0; } } else if (j == n - 1) { if (S1[m - 1][n - 2] == 0) { S1[m - 1][j] = 0; } } else if (S1[m - 1][j - 1] == 0 && S1[m - 1][j + 1] == 0) { S1[m - 1][j] = 0; } } } for (i = 0; i < m; i++) //Left and right border points { if (S1[i][0] == 1) { if (S1[i][1] == 0) //right point is undefine { S1[i][0] = 0; } else if (i == 0) { if (S1[i + 1][0] == 0) { S1[i][0] = 0; } } else if (i == m - 1) { if (S1[m - 2][0] == 0) { S1[i][0] = 0; } } else if (S1[i - 1][0] == 0 && S1[i + 1][0] == 0) { S1[i][0] = 0; } } if (S1[i][n - 1] == 1) { if (S1[i][n - 2] == 0) //left point is undefine { S1[i][n - 1] = 0; } else if (i == 0) { if (S1[i + 1][n - 1] == 0) { S1[i][n - 1] = 0; } } else if (i == m - 1) { if (S1[m - 2][n - 1] == 0) { S1[i][n - 1] = 0; } } else if (S1[i - 1][n - 1] == 0 && S1[i + 1][n - 1] == 0) { S1[i][n - 1] = 0; } } } //---- Generate S2 array from S1, add border to S2 with undefine data. int[][] S2 = new int[m + 2][n + 2]; for (i = 0; i < m + 2; i++) { for (j = 0; j < n + 2; j++) { if (i == 0 || i == m + 1) //bottom or top border { S2[i][j] = 0; } else if (j == 0 || j == n + 1) //left or right border { S2[i][j] = 0; } else { S2[i][j] = S1[i - 1][j - 1]; } } } //---- Using times number of each point during chacing process. int[][] UNum = new int[m + 2][n + 2]; for (i = 0; i < m + 2; i++) { for (j = 0; j < n + 2; j++) { if (S2[i][j] == 1) { l = S2[i][j - 1]; r = S2[i][j + 1]; b = S2[i - 1][j]; t = S2[i + 1][j]; lb = S2[i - 1][j - 1]; rb = S2[i - 1][j + 1]; lt = S2[i + 1][j - 1]; rt = S2[i + 1][j + 1]; //---- Cross point with two boder lines, will be used twice. if (l == 1 && r == 1 && b == 1 && t == 1 && ((lb == 0 && rt == 0) || (rb == 0 && lt == 0))) { UNum[i][j] = 2; } else { UNum[i][j] = 1; } } else { UNum[i][j] = 0; } } } //---- Tracing borderlines PointD aPoint; IJPoint aijPoint; BorderLine aBLine; List pointList; List ijPList; int sI, sJ, i1, j1, i2, j2, i3 = 0, j3 = 0; for (i = 1; i < m + 1; i++) { for (j = 1; j < n + 1; j++) { if (S2[i][j] == 1) //Tracing border from any border point { pointList = new ArrayList<>(); ijPList = new ArrayList<>(); aPoint = new PointD(); aPoint.X = X[j - 1]; aPoint.Y = Y[i - 1]; aijPoint = new IJPoint(); aijPoint.I = i - 1; aijPoint.J = j - 1; pointList.add(aPoint); ijPList.add(aijPoint); sI = i; sJ = j; i2 = i; j2 = j; i1 = i2; j1 = -1; //Trace from left firstly while (true) { int[] ij3 = new int[2]; ij3[0] = i3; ij3[1] = j3; if (traceBorder(S2, i1, i2, j1, j2, ij3)) { i3 = ij3[0]; j3 = ij3[1]; i1 = i2; j1 = j2; i2 = i3; j2 = j3; UNum[i3][j3] = UNum[i3][j3] - 1; if (UNum[i3][j3] == 0) { S2[i3][j3] = 3; //Used border point } } else { break; } aPoint = new PointD(); aPoint.X = X[j3 - 1]; aPoint.Y = Y[i3 - 1]; aijPoint = new IJPoint(); aijPoint.I = i3 - 1; aijPoint.J = j3 - 1; pointList.add(aPoint); ijPList.add(aijPoint); if (i3 == sI && j3 == sJ) { break; } } UNum[i][j] = UNum[i][j] - 1; if (UNum[i][j] == 0) { S2[i][j] = 3; //Used border point } //UNum[i][j] = UNum[i][j] - 1; if (pointList.size() > 1) { aBLine = new BorderLine(); aBLine.area = getExtentAndArea(pointList, aBLine.extent); aBLine.isOutLine = true; aBLine.isClockwise = true; aBLine.pointList = pointList; aBLine.ijPointList = ijPList; borderLines.add(aBLine); } } } } //---- Form borders List borders = new ArrayList<>(); Border aBorder; BorderLine aLine, bLine; //---- Sort borderlines with area from small to big. //For inside border line analysis for (i = 1; i < borderLines.size(); i++) { aLine = borderLines.get(i); for (j = 0; j < i; j++) { bLine = borderLines.get(j); if (aLine.area > bLine.area) { borderLines.remove(i); borderLines.add(j, aLine); break; } } } List lineList; if (borderLines.size() == 1) //Only one boder line { aLine = borderLines.get(0); if (!isClockwise(aLine.pointList)) { Collections.reverse(aLine.pointList); Collections.reverse(aLine.ijPointList); } aLine.isClockwise = true; lineList = new ArrayList<>(); lineList.add(aLine); aBorder = new Border(); aBorder.LineList = lineList; borders.add(aBorder); } else //muti border lines { for (i = 0; i < borderLines.size(); i++) { if (i == borderLines.size()) { break; } aLine = borderLines.get(i); if (!isClockwise(aLine.pointList)) { Collections.reverse(aLine.pointList); Collections.reverse(aLine.ijPointList); } aLine.isClockwise = true; lineList = new ArrayList<>(); lineList.add(aLine); //Try to find the boder lines are inside of aLine. for (j = i + 1; j < borderLines.size(); j++) { if (j == borderLines.size()) { break; } bLine = borderLines.get(j); if (bLine.extent.xMin > aLine.extent.xMin && bLine.extent.xMax < aLine.extent.xMax && bLine.extent.yMin > aLine.extent.yMin && bLine.extent.yMax < aLine.extent.yMax) { aPoint = bLine.pointList.get(0); if (pointInPolygon(aLine.pointList, aPoint)) //bLine is inside of aLine { bLine.isOutLine = false; if (isClockwise(bLine.pointList)) { Collections.reverse(bLine.pointList); Collections.reverse(bLine.ijPointList); } bLine.isClockwise = false; lineList.add(bLine); borderLines.remove(j); j = j - 1; } } } aBorder = new Border(); aBorder.LineList = lineList; borders.add(aBorder); } } return borders; }
参考:https://blog.csdn.net/weixin_39633134/article/details/116031614
参考2:https://www.researchgate.net/profile/Yaqiang-Wang
参考3:https://github.com/2008nmj/wContour