/// <summary> /// Ricochet coordinate calculation /// </summary> /// <param name="ballCoordinates">Ball Coordinates</param> /// <returns>Ricochet Ball Coordinates</returns> public BallCoordinates Ricochet(BallCoordinates ballCoordinates) { try { Coordinates2D intersectionPoint = FindNearestIntersectionPoint(ballCoordinates); //Marks.DrawRicochetMark(Convert.ToInt32(intersectionPoint.X), Convert.ToInt32(intersectionPoint.Y), true); DateTime ricocheTime = FindRicochetTime(ballCoordinates, intersectionPoint); Vector2D vector = FindIntersectionVector(ballCoordinates.Vector, intersectionPoint); BallCoordinates coordinates = new BallCoordinates( Convert.ToInt32(intersectionPoint.X), Convert.ToInt32(intersectionPoint.Y), ricocheTime); coordinates.Vector = vector; return(coordinates); } catch (Exception e) { throw new NotSupportedException(String.Format( "[{0}] Failed to find ricochet coordinates. Reason: {1}", MethodBase.GetCurrentMethod().Name, e.Message)); } }
/// <summary> /// Find intersection time based on ball coordinates, timestamp, vector and intersection point. /// </summary> /// <param name="ballCoordinates">Ball coordinates before intersection with border</param> /// <param name="intersection">Intersection with border point</param> /// <exception cref="ArgumentOutOfRangeException">Thrown in case calculated intersection time is too big</exception> /// <exception cref="NotSupportedException">Thrown in case intersection coordinates undefined.</exception> /// <returns>Intersection timestamp</returns> public DateTime FindRicochetTime(BallCoordinates ballCoordinates, Coordinates2D intersection) { VerifyBallCoordinatesAndVectorInput(ballCoordinates); if (intersection == null || !intersection.IsDefined) { throw new NotSupportedException(String.Format("[{0}] Intersection coordinates undefined!", MethodBase.GetCurrentMethod().Name)); } double distance = ballCoordinates.Distance(intersection); double velocity = ballCoordinates.Vector.Velocity(); double deltaT = distance / velocity; return(ballCoordinates.Timestamp + TimeSpan.FromSeconds(deltaT)); }
/// <summary> /// Calculate intersection vector from intersection point /// </summary> /// <param name="vector">Last known vector before intersection</param> /// <param name="intersection">Intersection point with border</param> /// <exception cref="NotSupportedException">Thrown in case passed intersection point is not on the border</exception> /// <returns>Ball Vector after intersection</returns> public Vector2D FindIntersectionVector(Vector2D vector, Coordinates2D intersection) { if (vector == null) { throw new NotSupportedException(String.Format( "[{0}] Vector from Intersection point can not be found because last known vector is NULL", MethodBase.GetCurrentMethod().Name)); } if (!vector.IsDefined) { throw new NotSupportedException(String.Format( "[{0}] Vector from Intersection point can not be found because last known vector is undefined", MethodBase.GetCurrentMethod().Name)); } if (!intersection.IsDefined) { throw new NotSupportedException(String.Format( "[{0}] Vector from Intersection point can not be found because intersection point is undefined", MethodBase.GetCurrentMethod().Name)); } bool isDirectionChanged = false; double x = vector.X * RicochetFactor; double y = vector.Y * RicochetFactor; if (intersection.Y == MinBorderY || intersection.Y == MaxBorderY) { y *= (-1); isDirectionChanged = true; } if (intersection.X == MinBorderX || intersection.X == MaxBorderX) { x *= (-1); isDirectionChanged = true; } if (!isDirectionChanged) { throw new NotSupportedException( String.Format("[{0}] Intersection point must be on border! Current point is {1}x{2}", MethodBase.GetCurrentMethod().Name, intersection.X, intersection.Y)); } return(new Vector2D(x, y)); }
/// <summary> /// Find nearest intersection point with table borders based on /// - given ball coordinates and vector /// </summary> /// <param name="ballCoordinates">Defined coordinates with defined vector</param> /// <returns>Coordinates of intersection with border</returns> public Coordinates2D FindNearestIntersectionPoint(BallCoordinates ballCoordinates) { //verify we can proceed to calculate intersection VerifyBallCoordinatesAndVectorInput(ballCoordinates); Dictionary <Vector2D, Coordinates2D> borderIntersection = new Dictionary <Vector2D, Coordinates2D>(); List <Vector2D> vectors = new List <Vector2D>(); //get line slope double m = CalculateLineSlope(ballCoordinates.Vector); if (ballCoordinates.Vector.X != 0) { double yb = CalculateY2OnLine(m, ballCoordinates.X, ballCoordinates.Y, MinBorderX); double yc = CalculateY2OnLine(m, ballCoordinates.X, ballCoordinates.Y, MaxBorderX); Coordinates2D B = new Coordinates2D(MinBorderX, yb); Vector2D vB = new Vector2D(B.X - ballCoordinates.X, B.Y - ballCoordinates.Y); vectors.Add(vB); borderIntersection.Add(vB, B); //B Coordinates2D C = new Coordinates2D(MaxBorderX, yc); Vector2D vC = new Vector2D(C.X - ballCoordinates.X, C.Y - ballCoordinates.Y); vectors.Add(vC); borderIntersection.Add(vC, C); //C } if (ballCoordinates.Vector.Y != 0) { double xa = CalculateX2OnLine(m, ballCoordinates.X, ballCoordinates.Y, MinBorderY); double xd = CalculateX2OnLine(m, ballCoordinates.X, ballCoordinates.Y, MaxBorderY); Coordinates2D A = new Coordinates2D(xa, MinBorderY); Vector2D vA = new Vector2D(A.X - ballCoordinates.X, A.Y - ballCoordinates.Y); vectors.Add(vA); borderIntersection.Add(vA, A); //A Coordinates2D D = new Coordinates2D(xd, MaxBorderY); Vector2D vD = new Vector2D(D.X - ballCoordinates.X, D.Y - ballCoordinates.Y); vectors.Add(vD); borderIntersection.Add(vD, D); //D } //remove points from wrong direction foreach (Vector2D vector in vectors) { double direction = vector.ScalarProduct(ballCoordinates.Vector) / (vector.Velocity() * ballCoordinates.Vector.Velocity()); if (Math.Round(direction, 0) != 1) { borderIntersection.Remove(vector); } } //if no points found => Error, consider adding error rate threshold if (borderIntersection.Count < 1) { Log.Print("No vectors found!", eCategory.Error, LogTag.VECTOR); } //get nearest point Coordinates2D intersectionPoint = null; double minDistance = MaxBorderX * MaxBorderY; foreach (Coordinates2D intersection in borderIntersection.Values) { double dist = intersection.Distance(ballCoordinates); if (dist < minDistance) { minDistance = dist; intersectionPoint = intersection; } } return(intersectionPoint); }
/// <summary> /// Coordinates scalar product /// </summary> /// <param name="coordA">Coordinate to calculate Scalar Product</param> /// <param name="coordB">Coordinate to calculate Scalar Product With</param> /// <returns>Scalar Product</returns> public static double ScalarProduct(Coordinates2D coordA, Coordinates2D coordB) { return(coordA.X * coordB.X + coordA.Y * coordB.Y); }