context: // Copyright 2014 - 2014 Esk0r
  // Geometry.cs is part of Evade.
  // 
  // Evade is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  // 
  // Evade is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU General Public License for more details.
  // 
  // You should have received a copy of the GNU General Public License
  // along with Evade. If not, see <http://www.gnu.org/licenses/>.
  
  using EloBuddy; 
   using LeagueSharp.SDK; 
   namespace Tc_SDKexAIO.Common
  {
      using System;
      using System.Collections.Generic;
      using ClipperLib;
      using LeagueSharp;
      using LeagueSharp.SDK;
      using SharpDX;
      using Color = System.Drawing.Color;
      using System.Linq;
  
      public static class Geometry
      {
          public static float Distance(Obj_AI_Base anotherUnit, bool squared = false)
          {
              return GameObjects.Player.Distance(anotherUnit, squared);
          }
  
          public static float Distance(this Obj_AI_Base unit, Obj_AI_Base anotherUnit, bool squared = false)
          {
              return unit.ServerPosition.ToVector2().Distance(anotherUnit.ServerPosition.ToVector2(), squared);
          }
  
          public static float Distance(this Obj_AI_Base unit, AttackableUnit anotherUnit, bool squared = false)
          {
              return unit.ServerPosition.ToVector2().Distance(anotherUnit.Position.ToVector2(), squared);
          }
  
          public static float Distance(this Obj_AI_Base unit, Vector3 point, bool squared = false)
          {
              return unit.ServerPosition.ToVector2().Distance(point.ToVector2(), squared);
          }
  
          public static float Distance(this Obj_AI_Base unit, Vector2 point, bool squared = false)
          {
              return unit.ServerPosition.ToVector2().Distance(point, squared);
          }
  
          public static float Distance3D(this Obj_AI_Base unit, Obj_AI_Base anotherUnit, bool squared = false)
          {
              return squared ? Vector3.DistanceSquared(unit.Position, anotherUnit.Position) : Vector3.Distance(unit.Position, anotherUnit.Position);
          }
  
          public static Vector2 To2D(this Vector3 v)
          {
              return new Vector2(v.X, v.Y);
          }
  
          public static float Distance(this Vector3 v, Vector3 other, bool squared = false)
          {
              return v.ToVector2().Distance(other, squared);
          }
  
          public static bool IsValids(this Vector2 v)
          {
              return v != Vector2.Zero;
          }
  
          public static bool IsValids(this Vector3 v)
          {
              return v != Vector3.Zero;
          }
  
          public static Vector3 To3D(this Vector2 v)
          {
              return new Vector3(v.X, v.Y, GameObjects.Player.ServerPosition.Z);
          }
  
          public static Vector3 To3D2(this Vector2 v)
          {
              return new Vector3(v.X, v.Y, NavMesh.GetHeightForPosition(v.X, v.Y));
          }
  
          public static Vector3 SetZs(this Vector3 v, float? value = null)
          {
              if (value == null)
              {
                  v.Z = Game.CursorPos.Z;
              }
              else
              {
                  v.Z = (float)value;
              }
              return v;
          }
  
          public static float Distance(this Vector2 v, Vector2 to, bool squared = false)
          {
              return squared ? Vector2.DistanceSquared(v, to) : Vector2.Distance(v, to);
          }
  
          public static float Distance(this Vector2 v, Vector3 to, bool squared = false)
          {
              return v.Distance(to.ToVector2(), squared);
          }
  
          public static float Distance(this Vector2 v, Obj_AI_Base to, bool squared = false)
          {
              return v.Distance(to.ServerPosition.ToVector2(), squared);
          }
  
          public static float Distance(this Vector2 point, Vector2 segmentStart, Vector2 segmentEnd, bool onlyIfOnSegment = false, bool squared = false)
          {
              var objects = point.ProjectOns(segmentStart, segmentEnd);
  
              if (objects.IsOnSegment || onlyIfOnSegment == false)
              {
                  return squared ? Vector2.DistanceSquared(objects.SegmentPoint, point) : Vector2.Distance(objects.SegmentPoint, point);
              }
  
              return float.MaxValue;
          }
  
          public static Vector2 CommmonNormalized(this Vector2 v)
          {
              v.Normalize();
              return v;
          }
  
          public static Vector3 CommmonNormalized(this Vector3 v)
          {
              v.Normalize();
              return v;
          }
  
          public static Vector2 CommonExtend(this Vector2 v, Vector2 to, float distance)
          {
              return v + distance * (to - v).CommmonNormalized();
          }
  
          public static Vector3 CommonExtend(this Vector3 v, Vector3 to, float distance)
          {
              return v + distance * (to - v).CommmonNormalized();
          }
  
          public static Vector2 CommonShorten(this Vector2 v, Vector2 to, float distance)
          {
              return v - distance * (to - v).CommmonNormalized();
          }
  
          public static Vector3 CommonShorten(this Vector3 v, Vector3 to, float distance)
          {
              return v - distance * (to - v).CommmonNormalized();
          }
  
          public static Vector3 CommonSwitchYZ(this Vector3 v)
          {
              return new Vector3(v.X, v.Z, v.Y);
          }
  
          public static Vector2 CommonPerpendicular(this Vector2 v)
          {
              return new Vector2(-v.Y, v.X);
          }
  
          public static Vector2 CommonPerpendicular2(this Vector2 v)
          {
              return new Vector2(v.Y, -v.X);
          }
  
          public static Vector2 CommonRotated(this Vector2 v, float angle)
          {
              var c = Math.Cos(angle);
              var s = Math.Sin(angle);
  
              return new Vector2((float)(v.X * c - v.Y * s), (float)(v.Y * c + v.X * s));
          }
  
          public static float CommonCrossProduct(this Vector2 self, Vector2 other)
          {
              return other.Y * self.X - other.X * self.Y;
          }
  
          public static float RadianToDegree(double angle)
          {
              return (float)(angle * (180.0 / Math.PI));
          }
  
          public static float DegreeToRadian(double angle)
          {
              return (float)(Math.PI * angle / 180.0);
          }
  
          public static float CommonPolar(this Vector2 v1)
          {
              if (Close(v1.X, 0, 0))
              {
                  if (v1.Y > 0)
                  {
                      return 90;
                  }
                  return v1.Y < 0 ? 270 : 0;
              }
  
              var theta = RadianToDegree(Math.Atan((v1.Y) / v1.X));
              if (v1.X < 0)
              {
                  theta = theta + 180;
              }
              if (theta < 0)
              {
                  theta = theta + 360;
              }
              return theta;
          }
  
          public static float CommonAngleBetween(this Vector2 p1, Vector2 p2)
          {
              var theta = p1.CommonPolar() - p2.CommonPolar();
              if (theta < 0)
              {
                  theta = theta + 360;
              }
              if (theta > 180)
              {
                  theta = 360 - theta;
              }
              return theta;
          }
  
          public static Vector2 CommonClosest(this Vector2 v, List<Vector2> vList)
          {
              var result = new Vector2();
              var dist = float.MaxValue;
  
              foreach (var vector in vList)
              {
                  var distance = Vector2.DistanceSquared(v, vector);
                  if (!(distance < dist)) continue;
                  dist = distance;
                  result = vector;
              }
  
              return result;
          }
  
          public static ProjectionInfo ProjectOns(this Vector2 point, Vector2 segmentStart, Vector2 segmentEnd)
          {
              var cx = point.X;
              var cy = point.Y;
              var ax = segmentStart.X;
              var ay = segmentStart.Y;
              var bx = segmentEnd.X;
              var by = segmentEnd.Y;
              var rL = ((cx - ax) * (bx - ax) + (cy - ay) * (by - ay)) /
                       ((float)Math.Pow(bx - ax, 2) + (float)Math.Pow(by - ay, 2));
              var pointLine = new Vector2(ax + rL * (bx - ax), ay + rL * (by - ay));
              float rS;
              if (rL < 0)
              {
                  rS = 0;
              }
              else if (rL > 1)
              {
                  rS = 1;
              }
              else
              {
                  rS = rL;
              }
  
              var isOnSegment = rS.CompareTo(rL) == 0;
              var pointSegment = isOnSegment ? pointLine : new Vector2(ax + rS * (bx - ax), ay + rS * (by - ay));
              return new ProjectionInfo(isOnSegment, pointSegment, pointLine);
          }
  
          public static IntersectionResult Intersection(this Vector2 lineSegment1Start, Vector2 lineSegment1End, Vector2 lineSegment2Start, Vector2 lineSegment2End)
          {
              double deltaACy = lineSegment1Start.Y - lineSegment2Start.Y;
              double deltaDCx = lineSegment2End.X - lineSegment2Start.X;
              double deltaACx = lineSegment1Start.X - lineSegment2Start.X;
              double deltaDCy = lineSegment2End.Y - lineSegment2Start.Y;
              double deltaBAx = lineSegment1End.X - lineSegment1Start.X;
              double deltaBAy = lineSegment1End.Y - lineSegment1Start.Y;
  
              var denominator = deltaBAx * deltaDCy - deltaBAy * deltaDCx;
              var numerator = deltaACy * deltaDCx - deltaACx * deltaDCy;
  
              if (Math.Abs(denominator) < float.Epsilon)
              {
                  if (!(Math.Abs(numerator) < float.Epsilon)) return new IntersectionResult();
                  // collinear. Potentially infinite intersection points.
                  // Check and return one of them.
                  if (lineSegment1Start.X >= lineSegment2Start.X && lineSegment1Start.X <= lineSegment2End.X)
                  {
                      return new IntersectionResult(true, lineSegment1Start);
                  }
                  if (lineSegment2Start.X >= lineSegment1Start.X && lineSegment2Start.X <= lineSegment1End.X)
                  {
                      return new IntersectionResult(true, lineSegment2Start);
                  }
                  return new IntersectionResult();
                  // parallel
              }
  
              var r = numerator / denominator;
              if (r < 0 || r > 1)
              {
                  return new IntersectionResult();
              }
  
              var s = (deltaACy * deltaBAx - deltaACx * deltaBAy) / denominator;
              if (s < 0 || s > 1)
              {
                  return new IntersectionResult();
              }
  
              return new IntersectionResult(
                  true,
                  new Vector2((float)(lineSegment1Start.X + r * deltaBAx), (float)(lineSegment1Start.Y + r * deltaBAy)));
          }
  
          public static object[] VectorMovementCollision(Vector2 startPoint1, Vector2 endPoint1, float v1, Vector2 startPoint2, float v2, float delay = 0f)
          {
              float sP1x = startPoint1.X, sP1y = startPoint1.Y, eP1x = endPoint1.X, eP1y = endPoint1.Y, sP2x = startPoint2.X, sP2y = startPoint2.Y;
              float d = eP1x - sP1x, e = eP1y - sP1y;
              float dist = (float)Math.Sqrt(d * d + e * e), t1 = float.NaN;
              float S = Math.Abs(dist) > float.Epsilon ? v1 * d / dist : 0, K = (Math.Abs(dist) > float.Epsilon) ? v1 * e / dist : 0f;
              float r = sP2x - sP1x, j = sP2y - sP1y;
              var c = r * r + j * j;
  
              if (dist > 0f)
              {
                  if (Math.Abs(v1 - float.MaxValue) < float.Epsilon)
                  {
                      var t = dist / v1;
                      t1 = v2 * t >= 0f ? t : float.NaN;
                  }
                  else if (Math.Abs(v2 - float.MaxValue) < float.Epsilon)
                  {
                      t1 = 0f;
                  }
                  else
                  {
                      float a = S * S + K * K - v2 * v2, b = -r * S - j * K;
  
                      if (Math.Abs(a) < float.Epsilon)
                      {
                          if (Math.Abs(b) < float.Epsilon)
                          {
                              t1 = (Math.Abs(c) < float.Epsilon) ? 0f : float.NaN;
                          }
                          else
                          {
                              var t = -c / (2 * b);
                              t1 = (v2 * t >= 0f) ? t : float.NaN;
                          }
                      }
                      else
                      {
                          var sqr = b * b - a * c;
                          if (!(sqr >= 0))
                              return new object[]
                                  {t1, (!float.IsNaN(t1)) ? new Vector2(sP1x + S*t1, sP1y + K*t1) : new Vector2()};
                          var nom = (float)Math.Sqrt(sqr);
                          var t = (-nom - b) / a;
                          t1 = v2 * t >= 0f ? t : float.NaN;
                          t = (nom - b) / a;
                          var t2 = (v2 * t >= 0f) ? t : float.NaN;
  
                          if (float.IsNaN(t2) || float.IsNaN(t1))
                              return new object[]
                                  {t1, (!float.IsNaN(t1)) ? new Vector2(sP1x + S*t1, sP1y + K*t1) : new Vector2()};
                          if (t1 >= delay && t2 >= delay)
                          {
                              t1 = Math.Min(t1, t2);
                          }
                          else if (t2 >= delay)
                          {
                              t1 = t2;
                          }
                      }
                  }
              }
              else if (Math.Abs(dist) < float.Epsilon)
              {
                  t1 = 0f;
              }
  
              return new object[] { t1, (!float.IsNaN(t1)) ? new Vector2(sP1x + S * t1, sP1y + K * t1) : new Vector2() };
          }
  
          public static float PathLengths(this List<Vector2> path)
          {
              var distance = 0f;
              for (var i = 0; i < path.Count - 1; i++)
              {
                  distance += path[i].Distance(path[i + 1]);
              }
              return distance;
          }
  
          public static List<Vector2> To2D(this List<Vector3> path)
          {
              return path.Select(point => point.ToVector2()).ToList();
          }
  
          public static Vector2[] CircleCircleIntersection(Vector2 center1, Vector2 center2, float radius1, float radius2)
          {
              var D = center1.Distance(center2);
  
              if (D > radius1 + radius2 || (D <= Math.Abs(radius1 - radius2)))
              {
                  return new Vector2[] { };
              }
  
              var A = (radius1 * radius1 - radius2 * radius2 + D * D) / (2 * D);
              var H = (float)Math.Sqrt(radius1 * radius1 - A * A);
              var Direction = (center2 - center1).CommmonNormalized();
              var PA = center1 + A * Direction;
              var S1 = PA + H * Direction.CommonPerpendicular();
              var S2 = PA - H * Direction.CommonPerpendicular();
              return new[] { S1, S2 };
          }
  
          public static bool Close(float a, float b, float eps)
          {
              if (Math.Abs(eps) < float.Epsilon)
              {
                  eps = (float)1e-9;
              }
              return Math.Abs(a - b) <= eps;
          }
  
          public static Vector2 RotateAroundPoint(this Vector2 rotated, Vector2 around, float angle)
          {
              var sin = Math.Sin(angle);
  
gt:             var cos = Math.Cos(angle);