Advertisement
Guest User

ConvexPolygon.cs

a guest
Dec 10th, 2019
127
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 12.41 KB | None | 0 0
  1. using Figures;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Collections.ObjectModel;
  5. using System.Drawing;
  6. using System.Dynamic;
  7. using System.Linq;
  8.  
  9. namespace Polygons
  10. {
  11.     // Todo: equals for all non-static classes
  12.     // Todo: make class diagram
  13.     // Todo: написать документацию
  14.     public class ConvexPolygon : IEquatable<ConvexPolygon>, IOriginator
  15.     {
  16.         #region Properties
  17.         public Color VertexColor { get; set; }
  18.         public Color LineColor { get; set; }
  19.         public int LineWidth { get; set; }
  20.         public int VertexRadius { get; set; }
  21.         #endregion
  22.  
  23.         private readonly List<Vertex> _vertices;
  24.         public int Count => _vertices.Count;
  25.         public ReadOnlyCollection<Vertex> Vertices => _vertices.AsReadOnly();
  26.  
  27.         #region Constructors
  28.         public ConvexPolygon(in Color? VertexColor = null, in Color? LineColor = null, in int? LineWidth = null, in int? VertexR = null)
  29.         {
  30.             _vertices = new List<Vertex>();
  31.  
  32.             this.VertexColor = VertexColor.GetValueOrDefault(Color.DarkCyan);
  33.             this.LineColor = LineColor.GetValueOrDefault(Color.Cyan);
  34.             this.LineWidth = LineWidth ?? 6;
  35.             this.VertexRadius = VertexR ?? 30;
  36.         }
  37.  
  38.         public ConvexPolygon(in List<Vertex> Vertices, in Color? VertexColor = null, in Color? LineColor = null, in int LineWidth = 6, in int VertexR = 30)
  39.         {
  40.             _vertices = new List<Vertex>(Vertices ?? throw new ArgumentNullException(nameof(Vertices)));
  41.             ConvexHull(new List<IPolygonCommand>());
  42.  
  43.             this.VertexColor = VertexColor.GetValueOrDefault(Color.DarkCyan);
  44.             this.LineColor = LineColor.GetValueOrDefault(Color.Cyan);
  45.             this.LineWidth = LineWidth;
  46.             this.VertexRadius = VertexR;
  47.         }
  48.  
  49.         public ConvexPolygon(in ConvexPolygon other)
  50.         {
  51.             if (other == null) throw new ArgumentNullException(nameof(other));
  52.  
  53.             _vertices = new List<Vertex>(other._vertices);
  54.  
  55.             VertexColor = other.VertexColor;
  56.             LineColor = other.LineColor;
  57.             LineWidth = other.LineWidth;
  58.             VertexRadius = other.VertexRadius;
  59.         }
  60.         #endregion
  61.  
  62.         #region Memento
  63.  
  64.         public IMemento CreateMemento()
  65.         {
  66.             return new PolygonMemento(VertexColor, LineColor, LineWidth, VertexRadius, _vertices);
  67.         }
  68.  
  69.         public void SetMemento(in IMemento memento)
  70.         {
  71.             dynamic state = (memento as PolygonMemento).GetState();
  72.  
  73.             VertexColor = state.VertexColor;
  74.             LineColor = state.LineColor;
  75.             LineWidth = state.LineWidth;
  76.             VertexRadius = state.VertexRadius;
  77.             _vertices.Clear(); _vertices.AddRange(state.Vertices);
  78.         }
  79.  
  80.         #endregion
  81.  
  82.         #region List-like actions
  83.         public IList<IPolygonCommand> Add(in Vertex newItem)
  84.         {
  85.             _vertices.Add(newItem ?? throw new ArgumentNullException(nameof(newItem)));
  86.             return new List<IPolygonCommand>() { new VertexAdd(newItem) };
  87.         }
  88.  
  89.         public IList<IPolygonCommand> AddRange(in IList<Vertex> newItems)
  90.         {
  91.             if (newItems == null) throw new ArgumentNullException(nameof(newItems));
  92.             if (newItems.Count < 1) throw new ArgumentException();
  93.             _vertices.AddRange(newItems);
  94.             return ConvexHull(new List<IPolygonCommand>(newItems.Select(i => new VertexAdd(i))));
  95.         }
  96.  
  97.         public IList<IPolygonCommand> RemoveAt(in int index)
  98.         {
  99.             if (index < 0 || index >= Count - 1) throw new IndexOutOfRangeException("index");
  100.             var action = new VertexDelete(_vertices[index]);
  101.             _vertices.RemoveAt(index);
  102.             return new List<IPolygonCommand>() { action };
  103.         }
  104.  
  105.         public IList<IPolygonCommand> Remove(in Vertex item)
  106.         {
  107.             if (item == null) throw new ArgumentNullException(nameof(item));
  108.             var action = new VertexDelete(item);
  109.             _vertices.Remove(item);
  110.             return new List<IPolygonCommand>() { action };
  111.         }
  112.  
  113.         public IList<IPolygonCommand> RemoveRange(in int start, int count)
  114.         { // start is the first element to remove. The next count - 1 elements will be removed as well
  115.             if (start < 0 || start + count > Count || count < 0) throw new ArgumentOutOfRangeException();
  116.             var history = new List<IPolygonCommand>();
  117.             if (count == 0) return history;
  118.             for (; count != 0; --count)
  119.             {
  120.                 history.Add(new VertexDelete(_vertices[count]));
  121.                 _vertices.RemoveAt(count);
  122.             }
  123.             return history;
  124.         }
  125.  
  126.         public IList<IPolygonCommand> RemoveRange(in IEnumerable<Vertex> items)
  127.         {
  128.             if (items == null) throw new ArgumentNullException(nameof(items));
  129.  
  130.             var history = new List<IPolygonCommand>();
  131.             foreach (var i in items)
  132.             {
  133.                 history.Add(new VertexDelete(i));
  134.                 _vertices.Remove(i);
  135.             }
  136.             return history;
  137.         }
  138.  
  139.         public int IndexOf(in Vertex item)
  140.         {
  141.             if (item == null) throw new ArgumentNullException(nameof(item));
  142.             return _vertices.IndexOf(item);
  143.         }
  144.         #endregion
  145.  
  146.         private static int VectorMul(in Point A1, in Point A2, in Point B1, in Point B2)
  147.         {
  148.             Point v1 = new Point(A2.X - A1.X, A1.Y - A2.Y);
  149.             Point v2 = new Point(B2.X - B1.X, B1.Y - B2.Y);
  150.             return (v1.X) * (v2.Y) - (v2.X) * (v1.Y);
  151.         }
  152.  
  153.         public bool Check(in Point point)
  154.         { // O(log n)
  155.             if (point == null) throw new ArgumentNullException(nameof(point));
  156.             if (_vertices.Count < 3)
  157.                 return false;
  158.  
  159.             int L = 0, R = _vertices.Count;
  160.  
  161.             for (int mid = (R + L) / 2; R - L > 1; mid = (R + L) / 2)
  162.             {
  163.                 if (VectorMul(_vertices[0], _vertices[mid], _vertices[0], point) > 0)
  164.                     L = mid;
  165.                 else
  166.                     R = mid;
  167.             }
  168.  
  169.             int OtherVertexIndex = R + 1;
  170.             if (OtherVertexIndex >= _vertices.Count)
  171.                 OtherVertexIndex = L - 1;
  172.  
  173.             if ((VectorMul(_vertices[L], _vertices[R % _vertices.Count], _vertices[L], point) > 0) ==
  174.                 (VectorMul(_vertices[L], _vertices[R % _vertices.Count], _vertices[L], _vertices[OtherVertexIndex]) > 0))
  175.                 return true;
  176.             return false;
  177.         }
  178.  
  179.         public IList<IPolygonCommand> ConvexHull() => ConvexHull(new List<IPolygonCommand>());
  180.  
  181.         public IList<IPolygonCommand> ConvexHull(in IList<IPolygonCommand> history)
  182.         { // O(n log n)
  183.             if (history == null) throw new ArgumentNullException(nameof(history));
  184.  
  185.             if (_vertices.Count < 3)
  186.                 return history;
  187.             // поиск самой нижней точки, если несколько - с наибольшим X; O(n)
  188.             int LowestRightestIndex = 0;
  189.             for (int i = 1; i < _vertices.Count; i++)
  190.             {
  191.                 if (_vertices[i].Y > _vertices[LowestRightestIndex].Y ||
  192.                     (_vertices[i].Y == _vertices[LowestRightestIndex].Y && _vertices[i].X > _vertices[LowestRightestIndex].X))
  193.                     LowestRightestIndex = i;
  194.             }
  195.             (_vertices[_vertices.Count - 1], _vertices[LowestRightestIndex]) = (_vertices[LowestRightestIndex], _vertices[_vertices.Count - 1]); // ставим её в конец списка
  196.                                                                                                                                                  // сортировка по полярному углу относительно последней точки Vertices[Vertices.Count - 1]; O(n log n)
  197.             _vertices.Sort(
  198.                 delegate (Vertex A, Vertex B)
  199.                 {
  200.                     if (VectorMul(_vertices[_vertices.Count - 1], A, _vertices[_vertices.Count - 1], B) > 0)
  201.                         return -1;
  202.                     else
  203.                         return 1;
  204.                 });
  205.             // правка выпуклости; O(n)
  206.             for (int i = 2; i < _vertices.Count; i++)
  207.             {
  208.                 while (i > 1 && _vertices.Count > 1 &&
  209.                        0 >= VectorMul(_vertices[i - 2], _vertices[i - 1],
  210.                                       _vertices[i - 1], _vertices[i]))
  211.                 {
  212.                     history.Add(new VertexDelete(_vertices[i - 1]));
  213.                     _vertices.RemoveAt(i - 1);
  214.                     i--;
  215.                 }
  216.             }
  217.             return history;
  218.         }
  219.  
  220.         public void Draw(in Graphics e, in Random rand = null)
  221.         {
  222.             if (e == null) throw new ArgumentNullException(nameof(e));
  223.             if (Count < 1) return;
  224.  
  225.             List<Point> Hull = new List<Point>();
  226.             //Hull.AddRange(from )
  227.             for (int i = 0; i < _vertices.Count; i++)
  228.             {
  229.                 Hull.Add(new Point(_vertices[i].X + rand?.Next(-2, 3) ?? 0,
  230.                                    _vertices[i].Y + rand?.Next(-2, 3) ?? 0));
  231.             }
  232.  
  233.             if (Count > 2)
  234.             {
  235.  
  236.                 if (DragAndDropManager.Dropping)
  237.                     e.DrawPolygon(new Pen(LineColor, LineWidth), (new ConvexPolygon(_vertices))._vertices.ConvertAll(i => new Point(i.X, i.Y)).ToArray());
  238.                 else
  239.                     e.DrawPolygon(new Pen(LineColor, LineWidth), _vertices.ConvertAll(i => new Point(i.X, i.Y)).ToArray());
  240.             }
  241.  
  242.             foreach (var i in _vertices)
  243.                 i.Draw(e, Count > 2, VertexColor, LineColor, LineWidth, VertexRadius, rand?.Next(-2, 3) ?? 0, rand?.Next(-2, 3) ?? 0);
  244.         }
  245.  
  246.         public List<Vertex> CheckVertices(in Point PointerLocation)
  247.         {
  248.             List<Vertex> Clicked = new List<Vertex>();
  249.             foreach (var i in _vertices)
  250.                 if (i.Check(PointerLocation, VertexRadius))
  251.                     Clicked.Add(i);
  252.             return Clicked;
  253.         }
  254.  
  255.         public override bool Equals(object obj)
  256.         {
  257.             return Equals(obj as ConvexPolygon);
  258.         }
  259.  
  260.         public bool Equals(ConvexPolygon other)
  261.         {
  262.             return other != null &&
  263.                    EqualityComparer<Color>.Default.Equals(VertexColor, other.VertexColor) &&
  264.                    EqualityComparer<Color>.Default.Equals(LineColor, other.LineColor) &&
  265.                    LineWidth == other.LineWidth &&
  266.                    VertexRadius == other.VertexRadius &&
  267.                    EqualityComparer<List<Vertex>>.Default.Equals(_vertices, other._vertices) &&
  268.                    Count == other.Count &&
  269.                    EqualityComparer<ReadOnlyCollection<Vertex>>.Default.Equals(Vertices, other.Vertices);
  270.         }
  271.  
  272.         public Vertex this[in int index] => _vertices[index];
  273.  
  274.         public static bool operator ==(ConvexPolygon left, ConvexPolygon right)
  275.         {
  276.             return EqualityComparer<ConvexPolygon>.Default.Equals(left, right);
  277.         }
  278.  
  279.         public static bool operator !=(ConvexPolygon left, ConvexPolygon right)
  280.         {
  281.             return !(left == right);
  282.         }
  283.     }
  284.  
  285.     [Serializable]
  286.     public class PolygonMemento : IMemento
  287.     {
  288.         private readonly Color _vertexColor;
  289.         private readonly Color _lineColor;
  290.         private readonly int _lineWidth;
  291.         private readonly int _vertexRadius;
  292.         private readonly ReadOnlyCollection<Vertex> _vertices;
  293.  
  294.         public PolygonMemento(in Color vertexColor, in Color lineColor, in int lineWidth, in int vertexRadius, in List<Vertex> vertices)
  295.         {
  296.             _vertexColor = vertexColor;
  297.             _lineColor = lineColor;
  298.             _lineWidth = lineWidth;
  299.             _vertexRadius = vertexRadius;
  300.             _vertices = vertices.AsReadOnly();
  301.         }
  302.  
  303.         public ExpandoObject GetState()
  304.         {
  305.             dynamic state = new ExpandoObject();
  306.  
  307.             state.VertexColor = _vertexColor;
  308.             state.LineColor = _lineColor;
  309.             state.LineWidth = _lineWidth;
  310.             state.VertexRadius = _vertexRadius;
  311.             state.Vertices = new List<Vertex>(_vertices);
  312.  
  313.             return state;
  314.         }
  315.     }
  316.  
  317. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement