/// <summary> /// returns an ideally spaced grid over the actual detected spots /// </summary> /// <param name="grid"></param> /// <returns></returns> private static grid2D OverlayIdealGrid(CalibrationDot[,] grid, List<CalibrationDot> corners, ref int grid_offset_x, ref int grid_offset_y, int random_seed) { grid2D overlay_grid = null; int grid_tx = -1; int grid_ty = -1; int grid_bx = -1; int grid_by = -1; int offset_x = 0; int offset_y = 0; bool found = false; int max_region_area = 0; // try searching horizontally and vertically // then pick the result with the greatest area for (int test_orientation = 0; test_orientation < 2; test_orientation++) { bool temp_found = false; int temp_grid_tx = -1; int temp_grid_ty = -1; int temp_grid_bx = -1; int temp_grid_by = -1; int temp_offset_x = 0; int temp_offset_y = 0; switch (test_orientation) { case 0: { while ((temp_offset_y < 5) && (!temp_found)) { temp_offset_x = 0; while ((temp_offset_x < 3) && (!temp_found)) { temp_grid_tx = temp_offset_x; temp_grid_ty = temp_offset_y; temp_grid_bx = grid.GetLength(0) - 1 - temp_offset_x; temp_grid_by = grid.GetLength(1) - 1 - temp_offset_y; if ((temp_grid_bx < grid.GetLength(0)) && (temp_grid_tx < grid.GetLength(0)) && (temp_grid_by < grid.GetLength(1)) && (temp_grid_ty < grid.GetLength(1)) && (temp_grid_ty >= 0) && (temp_grid_by >= 0) && (temp_grid_tx >= 0) && (temp_grid_bx >= 0)) { if ((grid[temp_grid_tx, temp_grid_ty] != null) && (grid[temp_grid_bx, temp_grid_ty] != null) && (grid[temp_grid_bx, temp_grid_by] != null) && (grid[temp_grid_tx, temp_grid_by] != null)) { temp_found = true; } } temp_offset_x++; } temp_offset_y++; } break; } case 1: { while ((temp_offset_x < 3) && (!temp_found)) { temp_offset_y = 0; while ((temp_offset_y < 5) && (!temp_found)) { temp_grid_tx = temp_offset_x; temp_grid_ty = temp_offset_y; temp_grid_bx = grid.GetLength(0) - 1 - temp_offset_x; temp_grid_by = grid.GetLength(1) - 1 - temp_offset_y; if ((temp_grid_bx < grid.GetLength(0)) && (temp_grid_tx < grid.GetLength(0)) && (temp_grid_by < grid.GetLength(1)) && (temp_grid_ty < grid.GetLength(1)) && (temp_grid_ty >= 0) && (temp_grid_by >= 0) && (temp_grid_tx >= 0) && (temp_grid_bx >= 0)) { if ((grid[temp_grid_tx, temp_grid_ty] != null) && (grid[temp_grid_bx, temp_grid_ty] != null) && (grid[temp_grid_bx, temp_grid_by] != null) && (grid[temp_grid_tx, temp_grid_by] != null)) { temp_found = true; } } temp_offset_y++; } temp_offset_x++; } break; } } temp_offset_y = temp_grid_ty - 1; while (temp_offset_y >= 0) { if ((temp_offset_y < grid.GetLength(1)) && (temp_offset_y >= 0)) { if ((grid[temp_grid_tx, temp_offset_y] != null) && (grid[temp_grid_bx, temp_offset_y] != null)) { temp_grid_ty = temp_offset_y; temp_offset_y--; } else break; } else break; } temp_offset_y = temp_grid_by + 1; while (temp_offset_y < grid.GetLength(1)) { if ((temp_offset_y < grid.GetLength(1)) && (temp_offset_y >= 0)) { if ((grid[temp_grid_tx, temp_offset_y] != null) && (grid[temp_grid_bx, temp_offset_y] != null)) { temp_grid_by = temp_offset_y; temp_offset_y++; } else break; } else break; } if (temp_found) { int region_area = (temp_grid_bx - temp_grid_tx) * (temp_grid_by - temp_grid_ty); if (region_area > max_region_area) { max_region_area = region_area; found = true; grid_tx = temp_grid_tx; grid_ty = temp_grid_ty; grid_bx = temp_grid_bx; grid_by = temp_grid_by; offset_x = temp_offset_x; offset_y = temp_offset_y; } } } if (found) { // record the positions of the corners corners.Add(grid[grid_tx, grid_ty]); corners.Add(grid[grid_bx, grid_ty]); corners.Add(grid[grid_bx, grid_by]); corners.Add(grid[grid_tx, grid_by]); double dx, dy; double x0 = grid[grid_tx, grid_ty].x; double y0 = grid[grid_tx, grid_ty].y; double x1 = grid[grid_bx, grid_ty].x; double y1 = grid[grid_bx, grid_ty].y; double x2 = grid[grid_tx, grid_by].x; double y2 = grid[grid_tx, grid_by].y; double x3 = grid[grid_bx, grid_by].x; double y3 = grid[grid_bx, grid_by].y; polygon2D perimeter = new polygon2D(); perimeter.Add((float)x0, (float)y0); perimeter.Add((float)x1, (float)y1); perimeter.Add((float)x3, (float)y3); perimeter.Add((float)x2, (float)y2); int grid_width = grid_bx - grid_tx; int grid_height = grid_by - grid_ty; int min_hits = 0; double min_dx = 0, min_dy = 0; // try various perimeter sizes double min_dist = double.MaxValue; int max_perim_size_tries = 100; polygon2D best_perimeter = perimeter; Random rnd = new Random(random_seed); for (int perim_size = 0; perim_size < max_perim_size_tries; perim_size++) { // try a small range of translations for (int nudge_x = -10; nudge_x <= 10; nudge_x++) { for (int nudge_y = -5; nudge_y <= 5; nudge_y++) { // create a perimeter at this scale and translation polygon2D temp_perimeter = perimeter.Scale(1.0f + (perim_size * 0.1f / max_perim_size_tries)); temp_perimeter = temp_perimeter.ScaleSideLength(0, 0.95f + ((float)rnd.NextDouble() * 0.1f)); temp_perimeter = temp_perimeter.ScaleSideLength(2, 0.95f + ((float)rnd.NextDouble() * 0.1f)); for (int i = 0; i < temp_perimeter.x_points.Count; i++) { temp_perimeter.x_points[i] += nudge_x; temp_perimeter.y_points[i] += nudge_y; } // create a grid based upon the perimeter grid2D temp_overlay_grid = new grid2D(grid_width, grid_height, temp_perimeter, 0, false); // how closely does the grid fit the actual observations ? double temp_min_dist = min_dist; BestFit(grid_tx, grid_ty, grid, temp_overlay_grid, ref min_dist, ref min_dx, ref min_dy, ref min_hits, ref grid_offset_x, ref grid_offset_y); // record the closest fit if (temp_min_dist < min_dist) { best_perimeter = temp_perimeter; overlay_grid = temp_overlay_grid; } } } } if (min_hits > 0) { dx = min_dx; dy = min_dy; Console.WriteLine("dx: " + dx.ToString()); Console.WriteLine("dy: " + dy.ToString()); x0 += dx; y0 += dy; x1 += dx; y1 += dy; x2 += dx; y2 += dy; x3 += dx; y3 += dy; perimeter = new polygon2D(); perimeter.Add((float)x0, (float)y0); perimeter.Add((float)x1, (float)y1); perimeter.Add((float)x3, (float)y3); perimeter.Add((float)x2, (float)y2); overlay_grid = new grid2D(grid_width, grid_height, perimeter, 0, false); } } return (overlay_grid); }