context: /*
  *     ___ _____ _   _   ___ ______   _  _   
  *    |_  |_   _| | | | / _ \|  _  \_| || |_ 
  *      | | | | | |_| |/ /_\ \ | | |_  __  _|
  *      | | | | |  _  ||  _  | | | |_| || |_ 
  *  /\__/ /_| |_| | | || | | | |/ /|_  __  _|
  *  \____/ \___/\_| |_/\_| |_/___/   |_||_| 
  *  
  *  "Very sharp, this assembly is the bomb!"
  *                                     -ISIS
  *     Greetings to our brothers in arms:
  *
  *                  Gucci
  *   (without him there would be no jihad.)
  *                Joduskame
  *   (without him there would be no sharp.)
  *
  *  h3h3, Trees, L33T, blacky, zezzy, xQx,
  *  iJava, Kurisu, Asuna, iMeh,
  *  Sebby, Beaving, xcsoft, Sida, jQuery,
  *  legacy, xQx, Kortatu, OutrageousMe
  *        and everyone using this
  *  
  */
  
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
  using LeagueSharp;
  using LeagueSharp.Common;
  using SharpDX;
  using ClipperLib;
  using Color = System.Drawing.Color;
  using Path = System.Collections.Generic.List<ClipperLib.IntPoint>;
  using Paths = System.Collections.Generic.List<System.Collections.Generic.List<ClipperLib.IntPoint>>;
  using GamePath = System.Collections.Generic.List<SharpDX.Vector2>;
  
  using EloBuddy; 
   using LeagueSharp.Common; 
   namespace HERMES_Kalista.MyUtils
  {
      /// <summary>
      /// Class that contains the geometry related methods.
      /// </summary>
      public static class Geometry
      {
          private const int CircleLineSegmentN = 22;
  
          public static Vector3 SwitchYZ(this Vector3 v)
          {
              return new Vector3(v.X, v.Z, v.Y);
          }
  
          //Clipper
          public static List<Polygon> ToPolygons(this Paths v)
          {
              var result = new List<Polygon>();
              foreach (var path in v)
              {
                  result.Add(path.ToPolygon());
              }
              return result;
          }
  
          /// <summary>
          /// Returns the position on the path after t milliseconds at speed speed.
          /// </summary>
          public static Vector2 PositionAfter(this GamePath self, int t, int speed, int delay = 0)
          {
              var distance = Math.Max(0, t - delay) * speed / 1000;
              for (var i = 0; i <= self.Count - 2; i++)
              {
                  var from = self[i];
                  var to = self[i + 1];
                  var d = (int)to.Distance(from);
                  if (d > distance)
                  {
                      return from + distance * (to - from).Normalized();
                  }
                  distance -= d;
              }
              return self[self.Count - 1];
          }
  
  
          public static class Util
          {
              public static void DrawLineInWorld(Vector3 start, Vector3 end, int width, Color color)
              {
                  var from = Drawing.WorldToScreen(start);
                  var to = Drawing.WorldToScreen(end);
                  Drawing.DrawLine(from[0], from[1], to[0], to[1], width, color);
              }
          }
  
          public static Polygon ToPolygon(this Path v)
          {
              var polygon = new Polygon();
              foreach (var point in v)
              {
                  polygon.Add(new Vector2(point.X, point.Y));
              }
              return polygon;
          }
  
          public static Paths ClipPolygons(List<Polygon> polygons)
          {
              var subj = new Paths(polygons.Count);
              var clip = new Paths(polygons.Count);
              foreach (var polygon in polygons)
              {
                  subj.Add(polygon.ToClipperPath());
                  clip.Add(polygon.ToClipperPath());
              }
              var solution = new Paths();
              var c = new Clipper();
              c.AddPaths(subj, PolyType.ptSubject, true);
              c.AddPaths(clip, PolyType.ptClip, true);
              c.Execute(ClipType.ctUnion, solution, PolyFillType.pftPositive, PolyFillType.pftEvenOdd);
              return solution;
          }
  
          public class Circle
          {
              public Vector2 Center;
              public float Radius;
  
              public Circle(Vector2 center, float radius)
              {
                  Center = center;
                  Radius = radius;
              }
  
              public Polygon ToPolygon(int offset = 0, float overrideWidth = -1)
              {
                  var result = new Polygon();
                  var outRadius = (overrideWidth > 0
                      ? overrideWidth
                      : (offset + Radius) / (float)Math.Cos(2 * Math.PI / CircleLineSegmentN));
                  for (var i = 1; i <= CircleLineSegmentN; i++)
                  {
                      var angle = i * 2 * Math.PI / CircleLineSegmentN;
                      var point = new Vector2(
                          Center.X + outRadius * (float)Math.Cos(angle), Center.Y + outRadius * (float)Math.Sin(angle));
                      result.Add(point);
                  }
                  return result;
              }
          }
  
          public class Polygon
          {
              public List<Vector2> Points = new List<Vector2>();
  
              public void Add(Vector2 point)
              {
                  Points.Add(point);
              }
  
              public Path ToClipperPath()
              {
                  var result = new Path(Points.Count);
                  foreach (var point in Points)
                  {
                      result.Add(new IntPoint(point.X, point.Y));
                  }
                  return result;
              }
  
              public bool IsOutside(Vector2 point)
              {
                  var p = new IntPoint(point.X, point.Y);
                  return Clipper.PointInPolygon(p, ToClipperPath()) != 1;
              }
  
              public void Draw(Color color, int width = 1)
              {
                  for (var i = 0; i <= Points.Count - 1; i++)
                  {
                      var nextIndex = (Points.Count - 1 == i) ? 0 : (i + 1);
                      Util.DrawLineInWorld(Points[i].To3D(), Points[nextIndex].To3D(), width, color);
                  }
              }
          }
  
          public class Rectangle
          {
              public Vector2 Direction;
              public Vector2 Perpendicular;
              public Vector2 REnd;
              public Vector2 RStart;
              public float Width;
  
              public Rectangle(Vector2 start, Vector2 end, float width)
              {
                  RStart = start;
                  REnd = end;
                  Width = width;
                  Direction = (end - start).Normalized();
                  Perpendicular = Direction.Perpendicular();
              }
  
              public Polygon ToPolygon(int offset = 0, float overrideWidth = -1)
              {
                  var result = new Polygon();
                  result.Add(
                      RStart + (overrideWidth > 0 ? overrideWidth : Width + offset) * Perpendicular - offset * Direction);
                  result.Add(
                      RStart - (overrideWidth > 0 ? overrideWidth : Width + offset) * Perpendicular - offset * Direction);
                  result.Add(
                      REnd - (overrideWidth > 0 ? overrideWidth : Width + offset) * Perpendicular + offset * Direction);
                  result.Add(
                      REnd + (overrideWidth > 0 ? overrideWidth : Width + offset) * Perpendicular + offset * Direction);
                  return result;
              }
          }
  
          public class Ring
          {
              public Vector2 Center;
              public float Radius;
              public float RingRadius; //actually radius width.
  
              public Ring(Vector2 center, float radius, float ringRadius)
              {
                  Center = center;
                  Radius = radius;
                  RingRadius = ringRadius;
              }
  
              public Polygon ToPolygon(int offset = 0)
              {
                  var result = new Polygon();
                  var outRadius = (offset + Radius + RingRadius) / (float)Math.Cos(2 * Math.PI / CircleLineSegmentN);
                  var innerRadius = Radius - RingRadius - offset;
                  for (var i = 0; i <= CircleLineSegmentN; i++)
                  {
                      var angle = i * 2 * Math.PI / CircleLineSegmentN;
                      var point = new Vector2(
                          Center.X - outRadius * (float)Math.Cos(angle), Center.Y - outRadius * (float)Math.Sin(angle));
                      result.Add(point);
                  }
                  for (var i = 0; i <= CircleLineSegmentN; i++)
                  {
                      var angle = i * 2 * Math.PI / CircleLineSegmentN;
                      var point = new Vector2(
  
gt:                         Center.X + innerRadius * (float)Math.Cos(angle),