CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

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 }