private static void PlaceLabels(MapSegment segment) { Console.WriteLine("==== " + segment.name + " ===="); int num_prefs = Constants.tower_preference_positions.Length; // My Linear Algebra library is apparently quite slow, so if you cache these, then it makes a // massive increase to the program's speed, particularly in the Simulated Annealing stage. Rect2 [] influenced_region = new Rect2 [segment.towers.Count]; Rect2 [] point_rects = new Rect2 [segment.towers.Count]; Rect2 [,] label_pref_rects = new Rect2 [segment.towers.Count, num_prefs]; Vector2 [,] label_pref_rect_centres = new Vector2 [segment.towers.Count, num_prefs]; #region Populate caches for (int i = 0; i < segment.towers.Count; i++) { segment.towers [i].ComputeLabelSize(); for (int j = 0; j < num_prefs; j++) { label_pref_rects [i, j] = segment.towers [i].GetLabelRectByPreference(j); label_pref_rect_centres [i, j] = label_pref_rects [i, j].centre; } influenced_region [i] = segment.towers [i].affected_region; point_rects [i] = Rect2.FromCentreAndSize(segment.towers [i].map_position, Vector2.one * Constants.point_radius_outer * 2); if (influenced_region [i].w >= Chunk.chunk_size.x) { Console.WriteLine("!!! CHUNK SIZE NOT WIDE ENOUGH !!! : " + segment.towers [i].name); } if (influenced_region [i].h >= Chunk.chunk_size.y) { Console.WriteLine("!!! CHUNK SIZE NOT TALL ENOUGH !!! : " + segment.towers [i].name); } } #endregion /* Note that this list/relation is symmetric; if (a, b) is in the list then so is (b, a). * This way, in order to check every combination symmetrically, only one iteration over the list * is required with no code duplication. */ List <(Tower, Tower)> close_tower_pairs = new List <(Tower, Tower)> (); #region Generate a list of close tower pairs to speed up comparisons int p = 0; int q = 0; int r = 0; int [] ref_counts = new int [segment.towers.Count]; foreach (Chunk chunk in segment.chunks) { foreach (Tower tower_2 in chunk.towers_to_compare) { foreach (Tower tower_1 in chunk.towers) { if (tower_1 == tower_2) { continue; } p++; if (Rect2.Overlaps( influenced_region [tower_1.index], influenced_region [tower_2.index] )) { q++; close_tower_pairs.Add((tower_1, tower_2)); ref_counts [tower_1.index]++; if (tower_1.index < tower_2.index) { r++; } } } } } #endregion Console.WriteLine(" >> " + p + " comparisons normally."); Console.WriteLine(" >> " + q + " comparisons with reductions (" + r + " unique comparisons)."); Console.WriteLine(" >> " + ref_counts.Where(x => x == 0).Count() + " towers will be completely ignored."); int [,] label_pref_orders = new int [segment.towers.Count, num_prefs]; #region Decide on the order of preference for label positions float [,] label_pref_weights = new float [segment.towers.Count, num_prefs]; foreach (Chunk chunk in segment.chunks) { foreach (Tower tower_2 in chunk.towers_to_compare) { foreach (Tower tower_1 in chunk.towers) { if (tower_1.index == tower_2.index) { continue; } if (Vector2.SquareDistanceBetween(tower_1.map_position, tower_2.map_position) > 900) { continue; } for (int i = 0; i < num_prefs; i++) { float d = label_pref_rects [tower_1.index, i].ClosestDistanceTo(tower_2.map_position); float dx = label_pref_rect_centres [tower_1.index, i].x - tower_2.map_position.x; float dy = label_pref_rect_centres [tower_1.index, i].y - tower_2.map_position.y; label_pref_weights [tower_1.index, i] += 1f / (dx * dx + dy * dy + 0.01f); } } } } // Sort weights for (int i = 0; i < segment.towers.Count; i++) { List <(int, float)> indices_in_order = Enumerable.Range(0, num_prefs).Select(x => (x, label_pref_weights [i, x])).ToList();
public Rect2 GetLabelRectByPreference(int preference) => Rect2.FromCentreAndSize( map_position + Constants.tower_preference_positions [preference] * (Vector2.one * Constants.point_radius_outer + label_size / 2), label_size );