/// <summary> /// returns a polygon representing the periphery of a square region /// </summary> /// <param name="edges"> /// edges within the square region <see cref="List`1"/> /// </param> /// <param name="erode_dilate"> /// erosion or dilation level <see cref="System.Int32"/> /// </param> /// <param name="perim"> /// returned periphery <see cref="polygon2D"/> /// </param> /// <returns> /// set of edges around the periphery <see cref="List`1"/> /// </returns> private static List<List<int>> GetSquarePeriphery(List<int> edges, int erode_dilate, ref polygon2D perim) { List<List<int>> result = new List<List<int>>(); perim = new polygon2D(); // find the bounding box for all edges int tx = 99999; int ty = 99999; int bx = -99999; int by = -99999; for (int i = edges.Count-2; i >= 0; i -= 2) { int x = edges[i]; int y = edges[i+1]; if (x < tx) tx = x; if (y < ty) ty = y; if (x > bx) bx = x; if (y > by) by = y; } int w = bx - tx; int h = by - ty; if ((w > 0) && (h > 0)) { int[] left = new int[h+1]; int[] right = new int[h+1]; int[] top = new int[w+1]; int[] bottom = new int[w+1]; for (int i = edges.Count - 2; i >= 0; i -= 2) { int x = edges[i]; int x2 = x - tx; int y = edges[i+1]; int y2 = y - ty; // left side if ((left[y2] == 0) || (x < left[y2])) left[y2] = x; // right side if ((right[y2] == 0) || (x > right[y2])) right[y2] = x; // top if ((top[x2] == 0) || (y < top[x2])) top[x2] = y; // bottom if ((bottom[x2] == 0) || (y > bottom[x2])) bottom[x2] = y; } #if SHOW_TIMINGS stopwatch timer_best_fit = new stopwatch(); timer_best_fit.Start(); #endif // find a best fit line for the left side int best_start = 0; int best_end = 0; int hits = BestFitLine(left, ref best_start, ref best_end); float left_x0 = left[best_start]; float left_y0 = ty + best_start; float left_x1 = left[best_end]; float left_y1 = ty + best_end; /* BestFitLineAverage(left, ref left_x0, ref left_y0, ref left_x1, ref left_y1); left_y0 += ty; left_y1 += ty; */ // find a best fit line for the right side best_start = 0; best_end = 0; hits = BestFitLine(right, ref best_start, ref best_end); float right_x0 = right[best_start]; float right_y0 = ty + best_start; float right_x1 = right[best_end]; float right_y1 = ty + best_end; /* BestFitLineAverage(right, ref right_x0, ref right_y0, ref right_x1, ref right_y1); right_y0 += ty; right_y1 += ty; */ // find a best fit line for the top side best_start = 0; best_end = 0; hits = BestFitLine(top, ref best_start, ref best_end); float top_x0 = tx + best_start; float top_y0 = top[best_start]; float top_x1 = tx + best_end; float top_y1 = top[best_end]; /* BestFitLineAverage(top, ref top_x0, ref top_y0, ref top_x1, ref top_y1); top_x0 += tx; top_x1 += tx; */ // find a best fit line for the bottom side best_start = 0; best_end = 0; hits = BestFitLine(bottom, ref best_start, ref best_end); float bottom_x0 = tx + best_start; float bottom_y0 = bottom[best_start]; float bottom_x1 = tx + best_end; float bottom_y1 = bottom[best_end]; /* BestFitLineAverage(bottom, ref bottom_x0, ref bottom_y0, ref bottom_x1, ref bottom_y1); bottom_x0 += tx; bottom_x1 += tx; */ #if SHOW_TIMINGS timer_best_fit.Stop(); if (timer_best_fit.time_elapsed_mS > 20) Console.WriteLine("GetSquarePeriphery: best fit " + timer_best_fit.time_elapsed_mS.ToString() ); #endif // find the intersection between the left side and the top side float ix=0; float iy = 0; geometry.intersection(left_x1, left_y1, left_x0, left_y0, top_x1, top_y1, top_x0, top_y0, ref ix, ref iy); perim.Add(ix, iy); // find the intersection between the right side and the top side ix = 0; iy = 0; geometry.intersection(right_x1, right_y1, right_x0, right_y0, top_x0, top_y0, top_x1, top_y1, ref ix, ref iy); perim.Add(ix, iy); // find the intersection between the right side and the bottom side ix = 0; iy = 0; geometry.intersection(right_x1, right_y1, right_x0, right_y0, bottom_x0, bottom_y0, bottom_x1, bottom_y1, ref ix, ref iy); perim.Add(ix, iy); // find the intersection between the left side and the bottom side ix = 0; iy = 0; geometry.intersection(left_x1, left_y1, left_x0, left_y0, bottom_x0, bottom_y0, bottom_x1, bottom_y1, ref ix, ref iy); perim.Add(ix, iy); // left and right List<int> left_edges = new List<int>(); List<int> right_edges = new List<int>(); for (int y = h; y >= 0; y--) { if (left[y] != 0) { left_edges.Add(left[y]); left_edges.Add(ty + y); } if (right[y] != 0) { right_edges.Add(right[y]); right_edges.Add(ty + y); } } // top and bottom List<int> top_edges = new List<int>(); List<int> bottom_edges = new List<int>(); for (int x = w; x >= 0; x--) { if (top[x] != 0) { top_edges.Add(tx + x); top_edges.Add(top[x]); } if (bottom[x] != 0) { bottom_edges.Add(tx + x); bottom_edges.Add(bottom[x]); } } float aspect_check = perim.getShortestSide() / perim.getLongestSide(); if (aspect_check > 0.2f) { result.Add(left_edges); result.Add(right_edges); result.Add(top_edges); result.Add(bottom_edges); } else perim = null; } // shrink the perimeter according to the erosion/dilation value if ((perim != null) && (erode_dilate != 0)) { if (perim.x_points != null) { float shrink_percent = (erode_dilate*2) / (perim.getPerimeterLength()/4.0f); perim = perim.Scale(1.0f - shrink_percent); } else perim = null; } return(result); }