/// <summary>
        /// Finds valeys and peaks.
        /// </summary>
        /// <param name="contourPts">Contour.</param>
        /// <param name="selector">Filter function where peak or valey is choosen. Angle range can be determined also. </param>
        /// <param name="scale">A good value is ~15. A specified amount will be skipped every time to avoid local minima.</param>
        /// <param name="peaks">Found peaks.</param>
        /// <param name="valeys">Found valeys.</param>
        /// <remarks>
        /// Sample usage:
        /// <code>
        ///     contourPts.FindExtremaIndices((angle, isPeak)=>
        ///     {
        ///         if ((isPeak AND angle ;gt 0 AND angle ;lt 90) || //peak filtering
        ///             (!isPeak AND angle ;gt 0 AND angle ;lt 90))  //valey filtering
        ///             return true;
        ///
        ///         return false;
        ///     }, 
        ///     scale, out peakIndeces, out valeyIndeces);
        /// </code>
        /// </remarks>
        public static void FindExtremaIndices(this IList<Point> contourPts, Func<float, bool, bool> selector, int scale,
                                              out List<int> peaks, out List<int> valeys)
        {
            peaks = new List<int>(); valeys = new List<int>();

            for (int i = 0; i < contourPts.Count; i++)
            {
                var idxL = (i - scale) % contourPts.Count; if (idxL < 0) idxL = contourPts.Count + idxL;
                var idxC = i;
                var idxR = (i + scale) % contourPts.Count;

                Vector2D v1 = new Vector2D(contourPts[idxC], contourPts[idxL]);
                Vector2D v2 = new Vector2D(contourPts[idxC], contourPts[idxR]);

                var angle = System.Math.Acos(Vector2D.DotProduct(v1, v2)) * 180 / System.Math.PI;

                var z = Vector2D.CrossProduct(v1, v2);
                bool isPeak = z >= 0;

                if (selector((float)angle, isPeak))
                {
                    if (isPeak)
                    {
                        peaks.Add(i);
                    }
                    else
                    {
                        valeys.Add(i);
                    }
                }

            }
        }
        private static LineSegment2DF getLine(int derivativeOrientation, PointF centerPoint, float length)
        {
            Vector2D vec = new Vector2D(Angle.ToRadians(derivativeOrientation)).Multiply(length / 2);
            var p1 = vec.Add(centerPoint);
            var p2 = vec.Negate().Add(centerPoint);

            return new LineSegment2DF(p1.ToPoint(), p2.ToPoint());
        }
 /// <summary>
 /// Multiplies vector and scale.
 /// </summary>
 /// <param name="vector"><see cref="Vector2D"/>.</param>
 /// <param name="scale">Scale</param>
 /// <returns>New scaled <see cref="Vector2D"/>.</returns>
 public static Vector2D Multiply(Vector2D vector, float scale)
 {
     return new Vector2D(vector.X * scale, vector.Y * scale);
 }
 /// <summary>
 /// Normalizes the vector with its length and produces a new vector.
 /// </summary>
 /// <returns>Normalized vector.</returns>
 public Vector2D Normalize()
 {
     var norm = (float)this.Length;
     var v = new Vector2D(this.X / norm, this.Y / norm);
     return v;
 }
 /// <summary>
 /// Adds point and <see cref="Vector2D"/>.
 /// </summary>
 /// <param name="point">Point.</param>
 /// <param name="vector">Vector.</param>
 /// <returns> Translated point. </returns>
 public static PointF Add(PointF point, Vector2D vector)
 {
     return new PointF 
     {
         X = point.X + vector.X,
         Y = point.Y + vector.Y
     };
 }
 /// <summary>
 /// Gets whether two vectors have opposite directions or not.
 /// </summary>
 /// <param name="v1">First vector</param>
 /// <param name="v2">Second vector</param>
 /// <returns>True if two vectors have opposite directions, otherwise false.</returns>
 public static bool AreOpositeDirection(Vector2D v1, Vector2D v2)
 {
     return v1.X == -v2.X && v1.Y == -v2.Y;
 }
 /// <summary>
 /// Vector obtained by cross product in 2D is facing toward Z direction (other coordinates are zero)
 /// </summary>
 /// <param name="v1">First vector</param>
 /// <param name="v2">Second vector</param>
 /// <returns>Vector signed magnitude in Z direction.</returns>
 public static double CrossProduct(Vector2D v1, Vector2D v2)
 {
     return (v1.X * v2.Y) - (v1.Y * v2.X);
 }
        /// <summary>
        /// Calculates vectors dot product.
        /// </summary>
        /// <param name="v1">First vector.</param>
        /// <param name="v2">Second vector.</param>
        /// <returns>Dot product magnitude.</returns>
        public static double DotProduct(Vector2D v1, Vector2D v2)
        {
            double dotProduct = v1.X * v2.X + v1.Y * v2.Y;
            dotProduct /= v1.Length;
            dotProduct /= v2.Length;

            dotProduct = System.Math.Min(dotProduct, 1);

            return dotProduct;
        }
 /// <summary>
 /// Calculates angle between vectors (in radians).
 /// <seealso cref="Angle"/>
 /// </summary>
 /// <param name="v1">First vector.</param>
 /// <param name="v2">Second vector.</param>
 /// <returns>Angle between vectors in radians.</returns>
 public static double Angle(Vector2D v1, Vector2D v2)
 {
     double cosAngle = DotProduct(v1, v2);
     double angleRad = System.Math.Acos(cosAngle);
     return angleRad;
 }