OverlapperSet.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  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. // The Command & Conquer Map Editor and corresponding source code is distributed
  9. // in the hope that it will be useful, but with permitted additional restrictions
  10. // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
  11. // distributed with this program. You should have received a copy of the
  12. // GNU General Public License along with permitted additional restrictions
  13. // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
  14. using MobiusEditor.Interface;
  15. using MobiusEditor.Utility;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Drawing;
  19. using System.Linq;
  20. namespace MobiusEditor.Model
  21. {
  22. public class OverlapperSet<T> : IEnumerable<(Point Location, T Overlapper)>, IEnumerable where T : class, ICellOverlapper
  23. {
  24. private readonly CellMetrics metrics;
  25. private readonly Dictionary<T, Rectangle> overlappers = new Dictionary<T, Rectangle>();
  26. public Rectangle? this[T overlapper] => Contains(overlapper) ? overlappers[overlapper] : default;
  27. public IEnumerable<T> Overlappers => overlappers.Keys;
  28. public OverlapperSet(CellMetrics metrics)
  29. {
  30. this.metrics = metrics;
  31. }
  32. public bool Add(Point location, T overlapper)
  33. {
  34. if ((overlapper == null) || Contains(overlapper))
  35. {
  36. return false;
  37. }
  38. var rectangle = overlapper.OverlapBounds;
  39. rectangle.Offset(location);
  40. overlappers[overlapper] = rectangle;
  41. return true;
  42. }
  43. public bool Add(int x, int y, T occupier) => Add(new Point(x, y), occupier);
  44. public bool Add(int cell, T overlapper) => metrics.GetLocation(cell, out Point location) ? Add(location, overlapper) : false;
  45. public void Clear() => overlappers.Clear();
  46. public bool Contains(T occupier) => overlappers.ContainsKey(occupier);
  47. public void CopyTo(OverlapperSet<T> other)
  48. {
  49. foreach (var (Location, Occupier) in this)
  50. {
  51. other.Add(Location, Occupier);
  52. }
  53. }
  54. public IEnumerator<(Point Location, T Overlapper)> GetEnumerator() => overlappers.Select(kv => (kv.Value.Location, kv.Key)).GetEnumerator();
  55. public bool Remove(T overlapper)
  56. {
  57. if ((overlapper == null) || !overlappers.TryGetValue(overlapper, out Rectangle overlapRect))
  58. {
  59. return false;
  60. }
  61. overlappers.Remove(overlapper);
  62. return true;
  63. }
  64. public ISet<Point> Overlaps(IEnumerable<Rectangle> rectangles)
  65. {
  66. var rectangleSet = new HashSet<Rectangle>(rectangles);
  67. while (true)
  68. {
  69. var count = rectangleSet.Count;
  70. var overlap = overlappers.Values.Where(x => rectangleSet.Any(y => x.IntersectsWith(y))).ToArray();
  71. rectangleSet.UnionWith(overlap);
  72. if (rectangleSet.Count == count)
  73. {
  74. break;
  75. }
  76. }
  77. return rectangleSet.SelectMany(x => x.Points()).ToHashSet();
  78. }
  79. public ISet<Point> Overlaps(Rectangle rectangle) => Overlaps(rectangle.Yield());
  80. public ISet<Point> Overlaps(IEnumerable<Point> points) => Overlaps(points.Select(p => new Rectangle(p, new Size(1, 1))));
  81. public ISet<Point> Overlaps(Point point) => Overlaps(point.Yield());
  82. 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));
  83. IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
  84. }
  85. }