OverlapperSet.cs (4105B)
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 MobiusEditor.Interface; 16 using MobiusEditor.Utility; 17 using System.Collections; 18 using System.Collections.Generic; 19 using System.Drawing; 20 using System.Linq; 21 22 namespace MobiusEditor.Model 23 { 24 public class OverlapperSet<T> : IEnumerable<(Point Location, T Overlapper)>, IEnumerable where T : class, ICellOverlapper 25 { 26 private readonly CellMetrics metrics; 27 private readonly Dictionary<T, Rectangle> overlappers = new Dictionary<T, Rectangle>(); 28 29 public Rectangle? this[T overlapper] => Contains(overlapper) ? overlappers[overlapper] : default; 30 31 public IEnumerable<T> Overlappers => overlappers.Keys; 32 33 public OverlapperSet(CellMetrics metrics) 34 { 35 this.metrics = metrics; 36 } 37 38 public bool Add(Point location, T overlapper) 39 { 40 if ((overlapper == null) || Contains(overlapper)) 41 { 42 return false; 43 } 44 45 var rectangle = overlapper.OverlapBounds; 46 rectangle.Offset(location); 47 overlappers[overlapper] = rectangle; 48 return true; 49 } 50 51 public bool Add(int x, int y, T occupier) => Add(new Point(x, y), occupier); 52 53 public bool Add(int cell, T overlapper) => metrics.GetLocation(cell, out Point location) ? Add(location, overlapper) : false; 54 55 public void Clear() => overlappers.Clear(); 56 57 public bool Contains(T occupier) => overlappers.ContainsKey(occupier); 58 59 public void CopyTo(OverlapperSet<T> other) 60 { 61 foreach (var (Location, Occupier) in this) 62 { 63 other.Add(Location, Occupier); 64 } 65 } 66 67 public IEnumerator<(Point Location, T Overlapper)> GetEnumerator() => overlappers.Select(kv => (kv.Value.Location, kv.Key)).GetEnumerator(); 68 69 public bool Remove(T overlapper) 70 { 71 if ((overlapper == null) || !overlappers.TryGetValue(overlapper, out Rectangle overlapRect)) 72 { 73 return false; 74 } 75 76 overlappers.Remove(overlapper); 77 return true; 78 } 79 80 public ISet<Point> Overlaps(IEnumerable<Rectangle> rectangles) 81 { 82 var rectangleSet = new HashSet<Rectangle>(rectangles); 83 while (true) 84 { 85 var count = rectangleSet.Count; 86 var overlap = overlappers.Values.Where(x => rectangleSet.Any(y => x.IntersectsWith(y))).ToArray(); 87 rectangleSet.UnionWith(overlap); 88 if (rectangleSet.Count == count) 89 { 90 break; 91 } 92 } 93 94 return rectangleSet.SelectMany(x => x.Points()).ToHashSet(); 95 } 96 97 public ISet<Point> Overlaps(Rectangle rectangle) => Overlaps(rectangle.Yield()); 98 99 public ISet<Point> Overlaps(IEnumerable<Point> points) => Overlaps(points.Select(p => new Rectangle(p, new Size(1, 1)))); 100 101 public ISet<Point> Overlaps(Point point) => Overlaps(point.Yield()); 102 103 public IEnumerable<(Point Location, U Overlapper)> OfType<U>() where U : T => this.Where(i => i.Overlapper is U).Select(i => (i.Location, (U)i.Overlapper)); 104 105 IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 106 } 107 }