CellGrid.cs (5703B)
1 // 2 // Copyright 2020 Electronic Arts Inc. 3 // 4 // The Command & Conquer Map Editor and corresponding source code is free 5 // software: you can redistribute it and/or modify it under the terms of 6 // the GNU General Public License as published by the Free Software Foundation, 7 // either version 3 of the License, or (at your option) any later version. 8 9 // The Command & Conquer Map Editor and corresponding source code is distributed 10 // in the hope that it will be useful, but with permitted additional restrictions 11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 12 // distributed with this program. You should have received a copy of the 13 // GNU General Public License along with permitted additional restrictions 14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection 15 using System; 16 using System.Collections; 17 using System.Collections.Generic; 18 using System.Drawing; 19 20 namespace MobiusEditor.Model 21 { 22 public enum FacingType 23 { 24 None, 25 North, 26 NorthEast, 27 East, 28 SouthEast, 29 South, 30 SouthWest, 31 West, 32 NorthWest 33 } 34 35 public class CellChangedEventArgs<T> : EventArgs 36 { 37 public readonly int Cell; 38 39 public readonly Point Location; 40 41 public readonly T OldValue; 42 43 public readonly T Value; 44 45 public CellChangedEventArgs(CellMetrics metrics, int cell, T oldValue, T value) 46 { 47 Cell = cell; 48 metrics.GetLocation(cell, out Location); 49 OldValue = oldValue; 50 Value = value; 51 } 52 53 public CellChangedEventArgs(CellMetrics metrics, Point location, T oldValue, T value) 54 { 55 Location = location; 56 metrics.GetCell(location, out Cell); 57 OldValue = oldValue; 58 Value = value; 59 } 60 } 61 62 public class CellGrid<T> : IEnumerable<(int Cell, T Value)>, IEnumerable 63 { 64 private readonly CellMetrics metrics; 65 private readonly T[,] cells; 66 67 public T this[int x, int y] 68 { 69 get => cells[y, x]; 70 set 71 { 72 if (!EqualityComparer<T>.Default.Equals(cells[y, x], value)) 73 { 74 var lastValue = cells[y, x]; 75 cells[y, x] = value; 76 OnCellChanged(new CellChangedEventArgs<T>(metrics, new Point(x, y), lastValue, cells[y, x])); 77 } 78 } 79 } 80 81 public T this[Point location] { get => this[location.X, location.Y]; set => this[location.X, location.Y] = value; } 82 83 public T this[int cell] { get => this[cell % metrics.Width, cell / metrics.Width]; set => this[cell % metrics.Width, cell / metrics.Width] = value; } 84 85 public Size Size => metrics.Size; 86 87 public int Length => metrics.Length; 88 89 public event EventHandler<CellChangedEventArgs<T>> CellChanged; 90 public event EventHandler<EventArgs> Cleared; 91 92 public CellGrid(CellMetrics metrics) 93 { 94 this.metrics = metrics; 95 96 cells = new T[metrics.Height, metrics.Width]; 97 } 98 99 public void Clear() 100 { 101 Array.Clear(cells, 0, cells.Length); 102 OnCleared(); 103 } 104 105 public T Adjacent(Point location, FacingType facing) 106 { 107 return metrics.Adjacent(location, facing, out Point adjacent) ? this[adjacent] : default; 108 } 109 110 public T Adjacent(int cell, FacingType facing) 111 { 112 if (!metrics.GetLocation(cell, out Point location)) 113 { 114 return default; 115 116 } 117 return metrics.Adjacent(location, facing, out Point adjacent) ? this[adjacent] : default; 118 } 119 120 public bool CopyTo(CellGrid<T> other) 121 { 122 if (metrics.Length != other.metrics.Length) 123 { 124 return false; 125 } 126 127 for (var i = 0; i < metrics.Length; ++i) 128 { 129 other[i] = this[i]; 130 } 131 132 return true; 133 } 134 135 protected virtual void OnCellChanged(CellChangedEventArgs<T> e) 136 { 137 CellChanged?.Invoke(this, e); 138 } 139 140 protected virtual void OnCleared() 141 { 142 Cleared?.Invoke(this, new EventArgs()); 143 } 144 145 public IEnumerable<(int Cell, T Value)> IntersectsWith(ISet<int> cells) 146 { 147 foreach (var i in cells) 148 { 149 if (metrics.Contains(i)) 150 { 151 var cell = this[i]; 152 if (cell != null) 153 { 154 yield return (i, cell); 155 } 156 } 157 } 158 } 159 160 public IEnumerable<(int Cell, T Value)> IntersectsWith(ISet<Point> locations) 161 { 162 foreach (var location in locations) 163 { 164 if (metrics.Contains(location)) 165 { 166 var cell = this[location]; 167 if (cell != null) 168 { 169 metrics.GetCell(location, out int i); 170 yield return (i, cell); 171 } 172 } 173 } 174 } 175 176 public IEnumerator<(int Cell, T Value)> GetEnumerator() 177 { 178 for (var i = 0; i < metrics.Length; ++i) 179 { 180 var cell = this[i]; 181 if (cell != null) 182 { 183 yield return (i, cell); 184 } 185 } 186 } 187 188 IEnumerator IEnumerable.GetEnumerator() 189 { 190 return GetEnumerator(); 191 } 192 } 193 }