/// <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; }